I am stuck in a problem in which I need to compute some concurrent calculation in the background and notify the user when each execution is completed.
I read a lot of articles. In which I found Service Class, Intent Service, and other ones. But I found crash above 24 android os versions.
Nowadays which method is best to execute the background service in android and why?
For the above problem you can use Work Manager. For better understanding please review the following link
https://developer.android.com/topic/libraries/architecture/workmanager
Best Method to execute the Background service is to use the system AlarmManager class and invoke alarm after every XXX seconds but it will drain the bettery but solution definately work for you.
step to follow ,
create alarm
public static void setUpalarm(Context context) {
Intent intent = new Intent(context, RestartServiceFromTimer.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(context , 0,
intent,0);
// Setup periodic alarm every every half hour from this point onwards
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
long delay = 5 * 1000 * 60; // time sets to 5 minute change accordingly
long time = System.currentTimeMillis() + delay;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
alarm.set(AlarmManager.RTC_WAKEUP, time, pIntent);
else if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
alarm.setExact(AlarmManager.RTC_WAKEUP, time, pIntent);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, time, pIntent);
}
2 create Broadcast receiver and restart service again also schedule alarm again
public class RestartServiceFromTimer extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("Task Trigger","Task is triggered");
if(!isMyServiceRunning(DetectIncomonCallService.class,context.getApplicationContext()))
{ Intent myserviceIntent = new Intent(context.getApplicationContext(),Service.class);
//start your background service here
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O)
{
ContextCompat.startForegroundService(context.getApplicationContext(),myserviceIntent);//this is for forground service
}
else
{
context.startService(myserviceIntent);
}
}
MainActivity.setUpalarm(context.getApplicationContext());
}
private boolean isMyServiceRunning(Class<?> serviceClass,Context context) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
3 call method from main activity like this
setUpalarm(MainActivity.this)
You can use Foreground Service for android OREO and higher
versions and for below OREO Android version, you can use background STICKY, NON_STICKEY services. From the service, you can broadcast your action with value when your calculation is completed.
Related
I want to run my app in background if I kill the app instance also. But after I kill my app the service also stops working. Here is my code please any one help me to solve my issue.
I followed this link for running in the background but it is not working if I remove the instance. Please can any one show me how to run a background service if the instance is removed also?
This is my MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ctx = this;
setContentView(R.layout.activity_main);
Intent alarmIntent = new Intent(MainActivity.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(MainActivity.this, ALARM_REQUEST_CODE, alarmIntent, 0);
mSensorService = new SensorService(getCtx());
mServiceIntent = new Intent(getCtx(), mSensorService.getClass());
if (!isMyServiceRunning(mSensorService.getClass())) {
startService(mServiceIntent);
}
}
Ths is my service class
public class SensorService extends Service{
public int counter=0;
public SensorService(Context applicationContext) {
super();
Log.i("HERE", "here I am!");
}
public SensorService() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startTimer();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i("EXIT", "ondestroy!");
Intent broadcastIntent = new Intent("uk.ac.shef.oak.ActivityRecognition.RestartSensor");
sendBroadcast(broadcastIntent);
}
private Timer timer;
private TimerTask timerTask;
long oldTime=0;
public void startTimer() {
//set a new Timer
timer = new Timer();
//initialize the TimerTask's job
initializeTimerTask();
//schedule the timer, to wake up every 1 second
timer.schedule(timerTask, 1000, 1000); //
}
/**
* it sets the timer to print the counter every x seconds
*/
public void initializeTimerTask() {
timerTask = new TimerTask() {
public void run() {
Log.i("in timer", "in timer ++++ "+ (counter++));
}
};
}
/**
* not needed
*/
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Its a long story. I have gone through it. Still implemented it. Now my service runs on every boot_complete event and keeps running all the time ( with a notification ).
Official Documentation:
Big NO. Google android developer documentation is poor, with no proper sample example too. It is theoretical and just theoretical. Keep reading if interested
https://developer.android.com/about/versions/oreo/background
Synopsis 1:
You can only receive BOOT_COMPLETE and only few broadcasts in traditional receiver. Rest all broadcast receivers you need to implement runtime in a service by registering them through a code from service which always runs.
Synopsis 2:
Again, you can not have always running processes in or above 8.0 (Oreo)...
To achieve always running process... Create a Intentservice with proper notification of type ongoing and make OnStartCommand START_STICKY and register receiver with code in OnCreate
How to implement it :
I have implemented it take reference from here :
Oreo: Broadcast receiver Not working
Now Your Question : I want to run my app in background if it kills the
app instance also.
With the help of above implementation link of my own you can achieve it
*Terms and conditions
You device must have proper android operating system released and burnt as it is.
Yes, I am using android :
No... You are Using Funtouch OS : VIVO ( By modifying Android)
There are many devices in market COLOR OS : OPPO ( By modifying Android)
....
....
Already google has made it complicated... version by version....
With no proper documentation and sample codes....
And Now Independent mobile device manufacturers making a lot of
changes to allow only selective applications run in background
like WhatsApp, Facebook, Google Twitter Instagram
Now you will ask a developer question If these app runs in background then I can make my app run in background too....
No... They are OS based modifications to check if a service is from allowed vendors then only it can be alive there in background. If they will not allow these vendors then no one take phones which does not run these famous social apps.
Hushhhhhhhh.......
You need to create ForegroundService in order continue processing when your app is killed, as follows:
public class SensorService extends Service{
private PowerManager.WakeLock wakeLock;
#Override
public void onCreate() {
super.onCreate();
//wake lock is need to keep timer alive when device goes to sleep mode
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK_TAG");
createNotificationChannel(this);
Notification notification = new NotificationCompat.Builder(this, "NOTIFICATION_CHANNEL").setSmallIcon
(<icon>).setContentTitle("Title")
.setContentText("Content").build();
startForeground(1001, notification);
}
#Override
public void onDestroy() {
super.onDestroy();
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
public void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "Channel name";
String description = "Description";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("NOTIFICATION_CHANNEL", name, importance);
channel.setDescription(description);
NotificationManager notificationManager = getApplicationContext().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
To start the service:
Intent i = new Intent(context, SensorService.class);
ContextCompat.startForegroundService(context, i)
Note:
You cannot run service endlessly with this approach. During doze mode if OS recognizes it as CPU intensive then your Service will be terminated.
You need to call stopSelf() when your Timer task has been executed successfully.
Oreo Introduced
new Concept PIP (Picture in Picture Mode )
and it have categories services control by making channels and priority to them.you have to change the code just for oreo to create notifications and services
read about google developers documentation carefully here
https://developer.android.com/guide/topics/ui/notifiers/notifications
both java and kotlin code is available here to create notification in oreo
https://developer.android.com/training/notify-user/build-notification
it was my effort to find the solution after searching and sharing with you.
here is some sample code :
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Much longer text that cannot fit one line...")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText("Much longer text that cannot fit one line..."))
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
for creating channels write this code:
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.channel_name);
String description = getString(R.string.channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
you can see full detials for push notifications and sending messages by clicking on the above links.
Hi i need to call a method every 4 seconds, even when the device is sleeping, i use alarm manager with service Start_stick, the service name is TransactionService. the code works well when the device is active and the method is called every exact 4 second, but when the screen is locked and device sleep the calling becomes inaccurate. so the method is now called every 2 seconds, sometimes every 1 sec,5 ....
this is how i run the thread to call method every 4 seconds
AlarmManager mgr = (AlarmManager) getApplicationContext().getSystemService(
Context.ALARM_SERVICE);
Intent notificationIntent = new Intent(getApplicationContext(),
TransactionService.class);
PendingIntent pendingIntent = PendingIntent.getService(
getApplicationContext(), 0, notificationIntent, 0);
mgr.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis(), 4000, pendingIntent);
this is the log of calling the method when device is active and screen is on
12-30 13:23:00.565 17397-17479/com.ids.simcardrefill D/url: calling
12-30 13:23:04.565 17397-17537/com.ids.simcardrefill D/url:calling
12-30 13:23:08.565 17397-17411/com.ids.simcardrefill D/url:calling
12-30 13:23:12.565 17397-17655/com.ids.simcardrefill D/url:calling
and this is how the method is calling when device is sleeping
12-30 13:09:12.565 17397-17655/com.ids.simcardrefill D/url:calling
12-30 13:09:17.785 17397-17598/com.ids.simcardrefill D/url:calling
12-30 13:09:20.565 17397-17479/com.ids.simcardrefill D/url:calling
12-30 13:09:25.775 17397-17537/com.ids.simcardrefill D/url:calling
12-30 13:09:28.565 17397-17411/com.ids.simcardrefill D/url:calling
here the difference between calling is inaccurate: 2 seconds, 5 seconds, 3 seconds
this is how the service look like :
public int onStartCommand(Intent intent, int flags, int startId) {
mshared = PreferenceManager
.getDefaultSharedPreferences(getApplicationContext());
edit = mshared.edit();
hostname = mshared.getString(
getApplicationContext().getString(R.string.hostname), "0");
contin = true;
cost
= mshared.getString(getString(R.string.test), "0.09");
if (contin) {
getTransactions get = new getTransactions(getApplicationContext());
get.execute(hostname);
}
return START_STICKY;
}
`
any solution ??
You should crate a service for working in background: https://developer.android.com/guide/components/services.html
You should use Handler in order to implement every 4 second functionality.
Handler handler = new Handler();
Runnable test = new Runnable() {
#Override
public void run() {
//do work
handler.post(test, 4000); //wait 4 sec and run again
}
};
public void stopTest() {
handler.removeCallbacks(test);
}
public void startTest() {
handler.post(test,0); //wait 0 ms and run
}
EDIT: i have tried the code below and it works for me
MyService.java
public class MyService extends Service {
Handler handler;
Runnable test;
public MyService() {
handler = new Handler();
test = new Runnable() {
#Override
public void run() {
Log.d("foo", "bar");
handler.postDelayed(test, 100); //100 ms you should do it 4000
}
};
handler.postDelayed(test, 0);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
AndroidManifest.xml
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
//some code
startService(new Intent(this, MyService.class));
}
And remember if you want start-stop functionality take loot at my first example.
The correct way to do this is using a Handler (as already mentioned in the other answer), but I will take the liberty to add a few points to it.
The problem
I had a similar situation, where the AlarmManager was firing erratically. Digging deeper into the issue led to me to understand that since the AlarmManager operation wakes up the CPU by holding a CPU wake-lock and is intensive on the battery (given that the device is inactive), the OS tries to batch different alarms from different apps and fires all pending alarms when the device wakes up. This leads to the erratic behaviour of the AlarmManager. The documentation also specifies that we shouldn't be using this to trigger events at exact timestamps. There are Android APIs which are supposed to work for exact intervals, eg AlarmManager.setExact(), but the OS optimises itself to ignore the exactness if the interval duration is less than a minute. [not documented, but speaking from my personal experiences]
The fix
I fixed the issue using a Handler only, as shared in the other answer. But there is a small caveat. In the edge case that the Handler is killed (due to any reason), it won't trigger itself and your polling would stop.
The caveat
The fallback is to keep a AlarmManager as well, running every minute to trigger the Handler back again in case it was stopped prematurely by the OS. So, you have a Handler running every n seconds. Store the timestamp of the last time the Handler was called in SharedPreferences. Have a backup AlarmManager running every x minutes (ideally x = 5*n, so that you don't miss more than 5 polling calls). The AlarmManager checks when the Handler last ran. If it's within the margin, the AlarmManager does nothing and reschedules itself after x minutes. If it's been more than x minutes, the Handler must have been killed by the OS and the AlarmManager starts the Handler back again.
Adding some code to give you context as well.
public class PollingAlarmReceiver extends WakefulBroadcastReceiver {
final long POLLING_FREQUENCY_MARGIN = 5 * 1000; //margin kept in case the System delays any threads
Context mContext = ServicesApp.getContext();
/*
Splash/BootReceiver starts the Alarm and the Handler for polling.
The Handler starts the polling service and schedules the next run after an delay of the polling interval.
Before starting the service, the Handler also checks when the service was last run and whether it is time for the next call or not (with a margin of 5 seconds [POLLING_FREQUENCY_MARGIN]).
The Handler should cover all the cases and run smoothly. In case it fails, the Alarm acts as a failsafe.
The Alarm runs at an interval of 1 minute checking when the Handler was last called.
If it is past the time of the next scheduled call (with a margin of 5 seconds [POLLING_FREQUENCY_MARGIN]), the Alarm starts the runnable and makes the Handler queue the next run.
*/
#Override
public void onReceive(Context context, Intent intent) {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext == null)
mContext = context.getApplicationContext();
if (mContext != null) {
if (getLastPolledTimestamp(mContext) > 0 && (System.currentTimeMillis() > (POLLING_FREQUENCY_MARGIN + getPollingInterval(mContext) + getLastPolledTimestamp(mContext)))) {
startPollingHandler();
}
}
}
Runnable mPoller = new Runnable() {
#Override
public void run() {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext != null) {
try {
if ((System.currentTimeMillis() >= (getPollingInterval(mContext)) - POLLING_FREQUENCY_MARGIN + getLastPolledTimestamp(mContext))) {
if (!isServiceRunning(PollingService.class, mContext)) {
mContext.getSharedPreferences(CommonLib.APP_SETTINGS, 0).edit().putLong(LAST_POLLED_TIMESTAMP, System.currentTimeMillis()).commit();
Intent service = new Intent(mContext, PollingService.class);
startWakefulService(mContext, service);
}
}
} finally {
ServicesApp.getHandler().postDelayed(mPoller, getPollingInterval(mContext));
}
}
}
};
public void startAlarmToCheckForHandler() {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext != null) {
AlarmManager alarmMgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(mContext, PollingAlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
alarmMgr.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime(), 60 * 1000, alarmIntent);
}
}
public void startPollingHandler() {
mPoller.run();
}
public void cancelAlarm() {
if (mContext == null)
mContext = ServicesApp.getContext();
if (mContext != null) {
AlarmManager alarmMgr = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(mContext, PollingAlarmReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
alarmMgr.cancel(alarmIntent);
}
}
}
P.S. : I have this code running on production for thousand of devices whose main functionality rely on the exactness of the polling and it seems to be working great for me.
I'm developing an app that should perform a certain task every 60 seconds. Since there's some accuracy problems with alarms in Android 4.4+, where all alarms are inexact, I've opted for the chained model: A BroadcastReceiver fires the first alarm, and each alarm in turn sets the next alarm.
The problem is that, even though I'm setting the alarms at intervals of 60 seconds (60000 ms), the alarms trigger at 5 second intervals, and sometimes even less. I've tested the code on my Nexus 5 (Android 5.1.1) and on an Android 5.0.1 emulator, both giving the same result.
I should point out that both receivers are registered on the AndroidManifest and my application has the RECEIVE_BOOT_COMPLETED permission.
EDIT: setExact() causes exactly the same problem
StartupReceiver.java (BroadcastReceiver for BOOT_COMPLETED):
public class StartupReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Got the BOOT_COMPLETED signal");
// Get the first alarm to be invoked immediately
AlarmReceiver.setNextScanAlarm(context, 0);
}
}
AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Start the service
Intent startServiceIntent = new Intent(context, BackgroundService.class);
startServiceIntent.putExtra("interval", 60000);
startServiceIntent.putExtra("action", "scan");
context.startService(startServiceIntent);
// Schedule the next alarm
setNextScanAlarm(context, 60000);
}
public static void setNextScanAlarm(Context context, int interval) {
Intent scanIntent = new Intent(context, AlarmReceiver.class);
scanIntent.putExtra("interval", interval);
scanIntent.putExtra("action", "scan");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
0,
scanIntent,
PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
interval,
pendingIntent);
}
}
What could be the problem?
I believe because this is an alarm clock when calling
alarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
interval,
pendingIntent);
The variable you are calling interval is the amount of time you want to elapse UNTIL the next alarm , but when you think about this when does it know to start? More so, when does time actually equal zero? When you create it? No. When you call .set()? No. It is actually zero upon BOOT. So you are asking it to launch 60 seconds after boot, and your asking for this everytime, this time will have already elapsed.
This is where the confusion is, and where you should probably just use a call like new
Handler.postDelayed(Runnnable r, 60000) instead of an alarm Manager. It will be much more accurate and will not be subject to some problems with understanding the Android Operating System and its alarms/clocks/etc/etc.
But for your specific case I believe you could solve it by accessing System function calls/variables. So inside of your function setNextScanAlarm() I believe it would look like this:
public static void setNextScanAlarm(Context context, int interval) {
//create the intent the same way as before
Intent scanIntent = new Intent(context, AlarmReceiver.class);
scanIntent.putExtra("interval", interval);
scanIntent.putExtra("action", "scan");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
0,
scanIntent,
PendingIntent.FLAG_ONE_SHOT);
//create new variables to calculate the correct time for this to go off
long timeRightNow = System.elapsedRealTime() //use something else if you change AlarmManager type
long timeWhenIShouldGoOff = timeRightNow + interval;
//use the new timeWhenIShouldGoOff variable instead of interval
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(
AlarmManager.ELAPSED_REALTIME_WAKEUP,
timeWhenIShouldGoOff,
pendingIntent);
}
See my answer to a similar question.
I use postDelayed() instead of AlarmManager for the short time intervals (less than 1 minute), and AlarmManager for long.
I have an Android background service that report positions from time to time. When I test locally over wifi it works pretty well, however when testing in 3G connection for example (sometimes on Edge) I have perceived that the application apparently enters in a bottleneck and do not execute the onLocationChanged method. That's okay because maybe lost signal or so on. However after a while (maybe when connection is re-established) it start updating all requests at once, in a matter of a few seconds many many times the method onLocationChanged is executed.
Does anyone have ideas how to solve that? Is it possible to add timeout into the method locationManager.requestLocationUpdates?
My Listener
public class MyListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
//report location to server
HttlCallToUpdatePostion(loc.Latitude, loc.Longitude, loc.Accuracy);
}
}
My Service
Handler handler = null;
LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
MyListener listener = new MyListener();
protected void doWork() {
Looper.prepare();
handler = new Handler();
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 5000, listener);
Looper.loop();
}
I wrote an app, exactly what you need.
When it was a service only I met the same problem. While the UI went to background and screen off the service went to background and it scheduled the system calls, once when triggered the buffer was flushed and I had like 10-50 updates.
The solution it is: an Alarm must be set and scheduled with 5000 value and a BroadcastRreceiver will receive and it will handle properly. Than you will meet other problems, which is not asked here.
For me this was a SOLUTION and the app is in use!
Edit:
Alarm setup code part:
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
// In reality, you would want to have a static variable for the request
// code instead of 192837
PendingIntent sender = PendingIntent.getBroadcast(this, 192837, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Get the AlarmManager service
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
// am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
am.setRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis(), timerInterval, sender);
AndroidManifest.xml :
<receiver android:process=":remote" android:name=".broadcastreceiver.AlarmReceiver"/>
class implementation part:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Context appContext = context.getApplicationContext();
...
check for power saving mode in adorid system setting: it must be disable to permit location manager to generete update location when the screen is off
I have activity which needs to be active all the time. I have thread which sleep 10 sec, and monitors values taken from database, compare them and start method. I'm wondering if user go back to other applications and activities, does my activity and thread still work, or they are handled by activity manager and go to pause-stop-destroy?? How to stay them a live??
Thank you.
here is code for that thread:
new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
while(true){
try {
Thread.sleep(10000);
myHendler.post(new Runnable() {
public void run() {
// TODO Auto-generated method stub
final Calendar cal = Calendar.getInstance();
int godina2 = cal.get(Calendar.YEAR);
int mesec2 = cal.get(Calendar.MONTH);
int dan2 = cal.get(Calendar.DAY_OF_MONTH);
int sati2 = cal.get(Calendar.HOUR_OF_DAY);
int minuti2 = cal.get(Calendar.MINUTE);
trenutniDatum = new StringBuilder().append(dan2).append("-").append(mesec2 +1).append("-").append(godina2);
trenutnoVreme = prepraviVreme(sati2) + ":" + prepraviVreme(minuti2);
for(int i = 0; i < primljenoIzBazeDatum.length; i++){
String bazaBroj = "";
String bazaText = "";
if(primljenoIzBazeDatum[i].toString().equals(trenutniDatum.toString()) && primljenoIzBazeVreme[i].toString().equals(trenutnoVreme)){
int bazaId = Integer.parseInt(primljenoIzBazeId[i]);
bazaBroj = primljenoIzBazeBroj[i].toString();
bazaText = primljenoIzBazeText[i].toString();
String datumPromena = "*" + primljenoIzBazeDatum[i].toString() + "* SENT *";
datumVreme.open();
datumVreme.updateData(bazaId, datumPromena);
datumVreme.close();
sendPoruka(bazaBroj, bazaText);
}
} // end for
} // end run
});
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
Based on my understanding of what you want to do, here is what I would do :
First, create a BroadcastReceiver
public class Poller extends BroadcastReceiver {
private final String TAG = "Poller";
#Override
public void onReceive( Context context, Intent intent ) {
Log.i(TAG, "Poller broadcastintent received");
Intent myIntent = new Intent( context, PollerService.class );
context.startService( myIntent );
}
then , create the service that is called and then shuts itself down
public class PollerService extends Service {
final String TAG = "PollerService";
#Override
public void onStart(Intent intent, int startId) {
Log.i(TAG, "Service onStart()");
pollingTask.execute();
}
AsyncTask<Void, Void, Void> pollingTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... param) {
// Do what you want in the background
}
#Override
protected void onPostExecute(Void result) {
stopSelf();
}
};
}
then, set an AlarmManager to wake the service every minute
AlarmManager am = ( AlarmManager ) getSystemService( Context.ALARM_SERVICE );
Intent alarmIntent = new Intent( "CHECK_DATABASE" );
PendingIntent pi = PendingIntent.getBroadcast(context, 0 , alarmIntent, 0 );
int type = AlarmManager.ELAPSED_REALTIME_WAKEUP;
long interval = POLLING_INTERVAL_IN_MILLISECONDS;
long triggerTime = SystemClock.elapsedRealtime() + interval;
// For short intervals setInexact repeating is same as exactRepeating, use at least fifteen minutes to make it more efficient
am.setInexactRepeating( type, triggerTime, interval, pi );
Log.i(TAG, "Set inexact alarm through AlarmManager");
}
setup the receiver in Android manifest
<receiver android:name="Poller">
<intent-filter>
<action android:name="CHECK_DATABASE"/>
</intent-filter>
</receiver>
finally, unset the AlarmManager to stop polling once your required SMS is received
AlarmManager am = ( AlarmManager ) getSystemService( Context.ALARM_SERVICE );
Intent intent = new Intent( "CHECK_DATABASE" );
PendingIntent pi = PendingIntent.getBroadcast( context, 0 , intent, 0 );
am.cancel(pi);
I do think that Peter is right though and this will kill you battery unless you'll only be checking until you get the required info and then don't poll and that's a short time.
Also, if you can get the exact time when you want to send the SMS with a single call from the database you can just set up the AlarmManger to wake up the service at that time, perform the action and be done with it. That would be the best approach (I can't quite make out if that is the case from you code but it does seems to be from you comments).
No, no application code on Android is not guaranteed to run all the time. Android OS can kill off aplications and services any time it feels it needs to.
Your best bet to periodically execute code would be to use AlarmManager, which makes your code execute periodically. Also a proper flag must be set to execute your code when device is asleep.
Note, since your period is very short (10s), it would keep CPU running all the time, draining the batterry very quickly.
If it has to be active all the time you have to use a Service: http://developer.android.com/guide/topics/fundamentals/services.html
I'm wondering if user go back to other applications and activities,
does my activity and thread still work, or they are handled by
activity manager and go to pause-stop-destroy?? How to stay them a
live??
They won't be kept "alive". If the system needs the resources your activity is destroyed. If you want to keep things running in the background even after your app is finished you have to use a Service.
In Java language you can scheduling your programs by traditional way:
java.util.Timer
java.util.TimerTask
for more information you can see:
http://enos.itcollege.ee/~jpoial/docs/tutorial/essential/threads/timer.html
http://www.ibm.com/developerworks/java/library/j-schedule/index.html
but better practice is using a scheduling framework such as Quartz, you can see http://www.quartz-scheduler.org/.
Spring framework also integration with Quartz framework.