Terminate alarm task when the app is terminated via Task Manager - android

I create an alarm to retrieve location every 30 seconds, as follows:
public class AlarmReceiver extends BroadcastReceiver {
public static final String LOG_TAG = "AlarmReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(LOG_TAG, "requesting location tracking.");
// start the service
Intent tracking = new Intent(context, LocationUpdateManager.class);
context.startService(tracking);
}
}
Here is the call from MainActivity to start the location update
private void startTracking(Context context) {
Log.i(LOG_TAG, "startTracking()");
// get a Calendar object with current time
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, START_DELAY);
Intent intent = new Intent(context, AlarmReceiver.class);
trackingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), UPDATE_INTERVAL, trackingIntent);
}
And here is the call to stop the location update:
public void stopTracking() {
Log.i(LOG_TAG, "stopTracking()");
Intent intent = new Intent(getBaseContext(), AlarmReceiver.class);
trackingIntent = PendingIntent.getBroadcast(getBaseContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarms.cancel(trackingIntent);
}
In this application, whenever the app is terminated (by any means) I would like to stop the alarm also (i.e. stop updating location). To this end, I call stopTracking() in onDestroy():
protected void onDestroy() {
Log.i(LOG_TAG, "onDestroy()");
stopTracking();
super.onDestroy();
}
I have tested many times on Samsung Galaxy S4 - 4.4.2: I open the app, put it in background (by pressing home button), then open task manager and clear the app from memory. Several times the alarm stops, but several times the alarm is still alive. Could someone explain for me?

You can use application class for that.Application's class instance will be available until when app isn't closed or killed(not minimised).When app get killed onTerminate of this class will be called.See below code.
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onTerminate() {
super.onTerminate();
//do your code here.
}
}
don't forget to add this instance to AndroidManifest.xml file.
<application
android:name=".MyApp"
android:allowBackup="true"
android:label="#string/app_name" >
</application>
But as suggested by #waqaslam, you should not rely on this because there is no gaurantee that it will be called in Real device Reference here.
One more and better thing that before user kills app from "recent apps" screen or from task manager , onPause() of running activities will be always called. So you need to save all data or do finalize work in onPause() method.That would be better.Hope it will help.Thanks.

Related

Keep service alive after app has been destroyed

I'm developing an app that need to do some check in the server every certain amount of time. The check consist in verify if there are some notification to display. To reach that goal I implemented Service, Alarm Manager and Broadcast Reciever. This is the code that I'm using so far:
public class MainActivity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
setRecurringAlarm(this);
}
/**
*
* #param context
*/
private void setRecurringAlarm(Context context) {
Calendar updateTime = Calendar.getInstance();
Intent downloader = new Intent(context, MyStartServiceReceiver.class);
downloader.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, downloader, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), 60000, pendingIntent);
}
...
}
Receiver class
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent dailyUpdater = new Intent(context, MyService.class);
context.startService(dailyUpdater);
Log.e("AlarmReceiver", "Called context.startService from AlarmReceiver.onReceive");
}
}
Service class
public class MyService extends IntentService {
public MyService() {
super("MyServiceName");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.e("MyService", "Service running!");
// TODO Do the hard work here
this.sendNotification(this);
}
private void sendNotification(Context context) {
// TODO Manage notifications here
}
}
Manifest.xml
<!--SERVICE AND BROADCAST RECEIVER-->
<service
android:name=".MyService"
android:exported="false"/>
<receiver
android:name=".MyStartServiceReceiver"
android:process=":remote"/>
The code works fine, the task in the service will be excecuted periodically. The problem is that the service is destroyed when the app is forced to close. I need to keep alive the service, capable to execute the task, even if the user has closed the app, so the user can be updated via notifications. Thank you for your time!
You can't. If the app is forced closed, that means either its crashed (in which case the service has to be stopped as it may no longer work correctly) or the user force closed it in which case the user wants the app to stop- which means the user doesn't want the service to run. Allowing a service to be automatically restarted even if the user stops it would be basically writing malware into the OS.
In fact, Android went the exact opposite (and correct) way- if the user force stops an app, NOTHING of the app can run until the user runs it again by hand.
You may go through this. I hope this will solve your problem. If you want to keep awake your service it is practically not possible to restart the app which is forced close. So if you disable force stop your problem may be solved.

How to stop my service after passing fixed amount of time?

At point A in my application I start my service and expect the service get closed from point B. However, there might be few scenarios that point B doesn't ask service to get closed. In this case I want the service close itself after fixed amount of time.
I have written following code into my Service class and expect the service gets closed after 10 seconds from launch time (It will be 45min in the future but I don't want to stay that long for test).
public class ChatService extends Service implements ITCPConnection
{
private static final int SERVICE_LIFE_TIME = 10 * 1000; // In millis
private AlarmReceiver mAlarmReceiver;
private AlarmManager alarmMgr;
private PendingIntent alarmIntent;
#Override
public void onCreate()
{
super.onCreate();
//
mAlarmReceiver = new AlarmReceiver();
registerReceiver(mAlarmReceiver, new IntentFilter());
//
Intent intent = new Intent(this, AlarmReceiver.class);
alarmIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
alarmMgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + SERVICE_LIFE_TIME, alarmIntent);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.e(TAG, "onDestroy()");
// Unregister receiver
if (mAlarmReceiver != null)
{
unregisterReceiver(mAlarmReceiver);
}
disconnect();
}
public void disconnect()
{
// If the alarm has been set, cancel it.
if (alarmMgr!= null)
{
alarmMgr.cancel(alarmIntent);
}
...
Log.e(TAG, "disconnect()");
}
/*****************
* Alarm Receiver
*****************/
private static class AlarmReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.e(TAG, "Stop service from AlarmReceiver");
context.stopService(intent);
}
}
}
My problem is AlarmReceiver.onReceive() never gets called and therefore my service will be alive indefinitely.
What you are trying to do is to targeting a broadcast receiver explicitly.
According to this, it cannot be done over a dinamically created (i.e. not declared into the manifest) broadcast receiver, because the os would not know how to resolve it.
To check if this is the root of the problem, you can go with the implicit way and set an action inside the intent and by filtering it in the IntentFilter.
Anyway, using the post delayed can be seen as a valid alternative, since you expect the service to be shut down naturally or still be around to intercept the delayed event.
Another (unrelated) thing is that you are calling
context.stopService(intent);
by using the broadcast intent and not the intent that started the service. You could simply call stopSelf().

KitKat: Service is null after exiting main activity

I have a service and I need to check if it's still running after some time from a static context.
[I noticed this happens only on Android KitKat]
What I did:
My service:
public class Servizio extends Service {
public static Service servizio;
[...Other things...]
#Override
public void onCreate() {
super.onCreate();
servizio = this;
scheduleMyAlarmToDoSomethingAfterSomeTime();
}
[...Other things...]
}
Then I launch the service from the main Activity in onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
[...]
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ServizioUtility.toggleService(this, true);
[...]
}
Then I check if it's null after a minute (with an alarm receiver whose alarm was launched by the service. Note that the receiver works fine and the following code is called):
if (Servizio.servizio!=null) {// FIXME
[...]
//THIS IS NOT CALLED IN THE 2ND SCENARIO
}
There are 2 scenario:
I run the activity, wait for the alarm to be launched and Servizio.servizio is not null.
I run the activity, "kill" it using the , wait for the alarm receiver to be called, Servizio.servizio is now null. Note that the service, on the other hand, is still running (checked from Settings->App->Running menu).
What's happening in the 2nd scenario?
I found out this is an issue with Android KitKat, if you want to check it out:
https://code.google.com/p/android/issues/detail?id=63793
https://code.google.com/p/android/issues/detail?id=63618
My simple workaround:
It sets the alarm with a 1 sec delay and stops the service by calling stopForeground().
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
if (Build.VERSION.SDK_INT >= 19) {
Intent serviceIntent = new Intent(this, MessageHandlerService.class);
serviceIntent.setAction(ACTION_REFRESH);
serviceIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);
manager.set(AlarmManager.RTC, System.currentTimeMillis()+1000, PendingIntent.getService(this, 1, serviceIntent, 0)); //1 sec delay
stopForeground(true);
}
}

The process of the service is killed after the application is removed from the application tray

I am starting a service (or re-starting the running service) when an activity is launched, using :
Intent intent = new Intent(this, MyService.class);
startService(intent);
Later on based on certain actions, the same activity binds to the service using
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
And when the activity is destroyed, I call
unbindService(mConnection);
Earlier, the service used to restart when I killed the same activity/application from the application tray and showed the "message 1 process 1 service running" under running apps.
Now, the service does not restart on killing the same activity/application.
And I get the message "0 process 1 service running", which means the service is actually not running.
The service does not restart on application being closed. My application consists of one activity. Also the service is successfully started when launched after a system boot.
Why does the process of the service gets killed when I start it using startService() ??
edit
The service used to re-start earlier after i closed the app from the application tray. But now suddenly with the SAME code, it doesn't. It happens with other apps too when i close them. eg.
Here is a workaround I came across and works well for re-starting a service if its process is killed on closing the application. In your service, add the following code.
I came across this workaround in this thread.
#Override
public void onTaskRemoved(Intent rootIntent){
Intent restartServiceIntent = new Intent(getApplicationContext(), this.getClass());
restartServiceIntent.setPackage(getPackageName());
PendingIntent restartServicePendingIntent = PendingIntent.getService(getApplicationContext(), 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager alarmService = (AlarmManager) getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarmService.set(
AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 1000,
restartServicePendingIntent);
super.onTaskRemoved(rootIntent);
}
Seems to be a bug that the process of the application is killed. There is no point for a service to run if its process is killed.
Please be aware of that: onDestroy is not always called. You should not put code that way.
When activity forced closed or closed by system abnormally, onDestroy is not getting called.
Unfortunately, this is a complicated problem due to the way Android works. There are a number of strategies that each work around different parts of the problem. For best results, combine multiple strategies together.
Note that some of these strategies may no longer be necessary in more recent Android versions.
1. Start an activity
What to do
Taken from Foreground service killed when receiving broadcast after acitivty swiped away in task list:
In the foreground service:
#Override
public void onTaskRemoved( Intent rootIntent ) {
Intent intent = new Intent( this, DummyActivity.class );
intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
startActivity( intent );
}
In the manifest:
<activity
android:name=".DummyActivity"
android:theme="#android:style/Theme.NoDisplay"
android:enabled="true"
android:allowTaskReparenting="true"
android:noHistory="true"
android:excludeFromRecents="true"
android:alwaysRetainTaskState="false"
android:stateNotNeeded="true"
android:clearTaskOnLaunch="true"
android:finishOnTaskLaunch="true"
/>
(If your service is in a different process then set this activity's process to the same one.)
In DummyActivity.java:
public class DummyActivity extends Activity {
#Override
public void onCreate( Bundle icicle ) {
super.onCreate( icicle );
finish();
}
}
Side effects
Causes the recents activity to close. Normally, swiping away an app doesn't close the recents activity.
Disadvantages
This only takes effect when the dummy activity starts, which may take half a second or more, so this still leaves the service open to being killed for a bit.
Explanation
When you remove/swipe your app away, a flag called waitingToKill is set. While this flag is set, Android may kill the process at any point in the future, such as when you receive a broadcast. Starting an activity clears this flag.
2. Spam a BroadcastReceiver with foreground broadcasts
What to do
Merge this into your service code:
if (Build.VERSION.SDK_INT >= 16) {
Intent intent = new Intent(this, DummyReceiver.class);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
//This seems to be timing-related; the more times we do this,
//the less likely the process gets killed
for (int i = 0; i < 50; ++i)
sendBroadcast(intent);
}
Create a dummy broadcast receiver:
public class DummyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {}
}
Add the receiver to your manifest:
<receiver android:name=".DummyReceiver" />
Side effects
May cause a slight (~250ms) delay/hang when the task is removed from the recents screen.
Disadvantages
This only keeps the process alive while it is receiving the broadcasts. the waitingToKill flag is still set, so the process may still be killed afterwards, such as when a broadcast is received.
Explanation
If your process isn't running in foreground priority, Android will try to kill it immediately. Receiving foreground broadcasts temporarily prevents this, resulting in the waitingToKill flag being set instead.
3. Don't bind to services
Binding to a service seems to increase the likelihood of the service's process being killed immediately when a task is removed.
I know this question is old but I recently encountered this problem and suddenly my service get stopped on closing app. Earlier it was working fine. This problem wasted my lot of time. To others who have similar problem make sure that YOUR BACKGROUND DATA RESTRICTION IS OFF.
This was the problem I had and it actually makes sense as when background data is Restricted background process won't run.
onDestroy is not always called. The Main problem in your case is ur unable to start the service when app closed,that time android OS(In Some OS) will kill the service, If you are not able to restart the service then call a alarm manger to start the reciver like this,
Manifest is,
<service
android:name=".BackgroundService"
android:description="#string/app_name"
android:enabled="true"
android:label="Notification" />
<receiver android:name="AlarmReceiver">
<intent-filter>
<action android:name="REFRESH_THIS" />
</intent-filter>
</receiver>
IN Main Activty start alarm manger in this way,
String alarm = Context.ALARM_SERVICE;
AlarmManager am = (AlarmManager) getSystemService(alarm);
Intent intent = new Intent("REFRESH_THIS");
PendingIntent pi = PendingIntent.getBroadcast(this, 123456789, intent, 0);
int type = AlarmManager.RTC_WAKEUP;
long interval = 1000 * 50;
am.setInexactRepeating(type, System.currentTimeMillis(), interval, pi);
this will call reciver and reciver is,
public class AlarmReceiver extends BroadcastReceiver {
Context context;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
System.out.println("Alarma Reciver Called");
if (isMyServiceRunning(this.context, BackgroundService.class)) {
System.out.println("alredy running no need to start again");
} else {
Intent background = new Intent(context, BackgroundService.class);
context.startService(background);
}
}
public static boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningServiceInfo> services = activityManager.getRunningServices(Integer.MAX_VALUE);
if (services != null) {
for (int i = 0; i < services.size(); i++) {
if ((serviceClass.getName()).equals(services.get(i).service.getClassName()) && services.get(i).pid != 0) {
return true;
}
}
}
return false;
}
}
And this Alaram reciver calls once when android app is opened and when app is closed.SO the service is like this,
public class BackgroundService extends Service {
private String LOG_TAG = null;
#Override
public void onCreate() {
super.onCreate();
LOG_TAG = "app_name";
Log.i(LOG_TAG, "service created");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(LOG_TAG, "In onStartCommand");
//ur actual code
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// Wont be called as service is not bound
Log.i(LOG_TAG, "In onBind");
return null;
}
#TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.i(LOG_TAG, "In onTaskRemoved");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(LOG_TAG, "In onDestroyed");
}
}
when there is no binding to a service or well established foreground then android system recognize the service as unused overloading service that should be shut down. Here is the best way to maintain your service even if the app is closed: AlarmManager or Service

A service in android which send SMS at regular interval

I want to make a service in android which run in background always and start as soon as I boot my phone and send message at a regular interval.I have writen my code as below
MainActivity.class
package test.sai;
public class MainActivity extends Activity {
Timer t;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
alrm();
Log.e("msg", "in main");
}
public void alrm() {
Intent myAlarm = new Intent(getApplicationContext(), AlarmReceiver.class);
Log.e("msg", "in alrm");
//myAlarm.putExtra("project_id", project_id); //Put Extra if needed
PendingIntent recurringAlarm = v PendingIntent.getBroadcast(getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Calendar updateTime = Calendar.getInstance();
Log.e("msg", "in alrm1");
//updateTime.setWhatever(0);
alarms.setInexactRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), AlarmManager.INTERVAL_FIFTEEN_MINUTES, recurringAlarm); //you can modify the interval of course
}
}
This class is calling AlarmReceiver.class
package test.sai;
public class AlarmReceiver extends BroadcastReceiver
{
GPSTracker gps;
#Override
public void onReceive(Context context, Intent intent)
{
gps = new GPSTracker(context);
if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
Intent pushIntent = new Intent(context,MainActivity.class);
pushIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(pushIntent);
Log.e("pro", "alrmmanager");
}
Intent myService = new Intent(context, FirstService.class);
myService.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(myService);
Log.e("msg", "in alrmmanager1");
}
}
and finally AlarmReceiver is calling the service class
package test.sai;
public class FirstService extends Service{
Timer t;
int time = 0;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onStart(Intent intent, int startId) {
Log.e("time", time++ +"");
Toast.makeText(this, time+1+"", 500).show();
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}
Now I want to on GPS as soon as service starts and then I want to use GPS to track location of mobile and send a message to another mobile.I also have code for GPS and sms sending but I am not getting how to call and where to call those methodss,so that my service keep on running and sending messages at some perticular interval.please help.
You can use alarmManager for this... Because if you create your own timerTask, it is very much susceptible to get destroyed by the processor.
To answer your two part question:
First you need to learn how to handle onBoot within Android Framework. Refer to this Q/A Trying to start a service on boot on Android
Lastly you need to understand the SMSManager class. Refer to the documentation http://developer.android.com/reference/android/telephony/SmsManager.html
I don't think anyone should provide complete code for your request as your main problem/question is "How can I help myself and stop looking for others to fix all my problems".
Try registering a BroadcastReceiver with AlarmManager to receive an intent at your regular interval. You'll probably want two, one that listens for a BOOT_COMPLETED action, and another that the AlarmManager will start on interval. You can have the second receiver start a service if whatever you want to do will take a while to execute.
Here's a question on how to make the receiver run on boot so you can register the other receiver with AlarmManager:
Android BroadcastReceiver on startup
Here's another that wants pretty much the same thing you want, minus the SMS:
How to Autostart an AlarmManager to start a Scheduled Activity?

Categories

Resources