SyncAdapter process killed when swiped from recents - android

I am trying to create SyncAdapter running background operation (without foreground notification).
It is working, except the case when activity (task) which triggered ContentResolver.requestSync(...) is swiped away from recent applications. In that case process is killed and onPerformSync(...) is not finished.
I know, this is expected Android behavior, but in regular Service I would set
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_REDELIVER_INTENT;
}
or maybe use
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
restartSynchronization();
}
to retry synchronization, but this is not working in the SyncAdapterService.
How can I ensure synchronization continues/retry after activity is swiped away from recent applications?
Thank you in advance.

After some reseach I found out, that onTaskRemoved(...) is called only when startService(...) is called and not when someone only binds to it.
So I did work around by starting service in onBind(...) and stopping it and its process in onUnbind(...) methods.
This is final code:
public class SyncAdapterService extends Service {
private static final Object sSyncAdapterLock = new Object();
private static MySyncAdapter sSyncAdapter = null;
#Override
public void onCreate() {
super.onCreate();
synchronized (sSyncAdapterLock) {
if (sSyncAdapter == null) {
sSyncAdapter = new MySyncAdapter(getApplicationContext());
}
}
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
/*
* Rescheduling sync due to running one is killed on removing from recent applications.
*/
SyncHelper.requestSyncNow(this);
}
#Override
public IBinder onBind(Intent intent) {
/*
* Start service to watch {#link #onTaskRemoved(Intent)}
*/
startService(new Intent(this, SyncAdapterService.class));
return sSyncAdapter.getSyncAdapterBinder();
}
#Override
public boolean onUnbind(Intent intent) {
/*
* No more need watch task removes.
*/
stopSelf();
/*
* Stops current process, it's not necessarily required. Assumes sync process is different
* application one. (<service android:process=":sync" /> for example).
*/
Process.killProcess(Process.myPid());
return super.onUnbind(intent);
}
}

Related

If app crashes or closed from task manager then that time i want to hit api

I have created a service and called this service class from BaseActivity.
Intent serviceIntent = new Intent(this, UserAvailabilityService.class);
startService(serviceIntent);
public class UserAvailabilityService extends Service {
private static final String TAG = UserAvailabilityService.class.getSimpleName();
boolean isChecked = false;
boolean isUserAvailable = false;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate()");
isChecked = getAvailableStatusFromFref();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "onStartCommand()");
return START_NOT_STICKY;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.i(TAG, "onTaskRemoved()");
if(isChecked) {
//Hit a api
}
else
{
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestroy()");
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.i(TAG, "onLowMemory()");
}
}
If app crashes or closed from task manager then that time i want to hit api.
Right Now, When i am swipping the app from background this onTaskRemoved method is calling. and i am hitting the api.
But when i am closing the same app from task manager (Setting->Apps->App name->Force Stop) then this onTaskRemoved method is not calling.
Any idea,please let me know.
Not possible. You cannot tell from within an app whether the app will be terminated. You could watch for termination from a second app, but at any time the first can be closed without notice. Not to mention the variety of ways that both apps could be shut down (for example, they could just pull the battery). You should never write code that requires you to do something on shutdown, because it will never be reliable.
The best you can do is calling isFinishing() which checks if it is being destroyed from you onPause() method
#Override
protected void onPause(){
super.onPause();
if(isFinishing){
callApi();
}
}

startservice not working for service with process attribute

I have a very simple service, trying to run it in a separate process, but the startService() method has no effect at all unless I made it run in the same process [removed the process attribute from manifest]!
Service:
public class RemoteService extends Service {
/** Called when the service is being created. */
#Override
public void onCreate() {
Log.v("RemoteService", "Service:onCreate===> called");
}
/** The service is starting, due to a call to startService() */
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("RemoteService", "Service:onStartCommand===> called");
return START_STICKY;
}
/** A client is binding to the service with bindService() */
#Override
public IBinder onBind(Intent intent) {
Log.v("RemoteService", "Service:onBind===> called");
return null;
}
/** Called when a client is binding to the service with bindService()*/
#Override
public void onRebind(Intent intent) {
Log.v("RemoteService", "Service:onRebind===> called");
}
/** Called when The service is no longer used and is being destroyed */
#Override
public void onDestroy() {
Log.v("RemoteService", "Service:onDestroy===> called");
}
}
Manifest:
<service
android:name=".RemoteService"
android:enabled="true"
android:exported="false"
android:process=":worker"></service>
Activity:
startService(new Intent(this, RemoteService.class));
So, how to start service that has the process attribute?
Make sure to filter the logs in the logcat for the correct process. Since the service runs in a different process you do not always see them by default.

Android: Run code when application is permanently closed

So I have code that I want called when my application is closed. Not just when it is sent to the background or the surface is destroyed. How do I do this? Is there a method that I can override in a SurfaceView or Activity class?
New Edit - current BackgroundService class:
public class BackgroundService extends Service {
private String savedString;
public void onCreate() {
System.out.println("Service created");
super.onCreate();
}
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("start command: ");
savedString = intent.getStringExtra("myString);
return super.onStartCommand(intent, flags, startId);
}
public IBinder onBind(Intent intent) {
return null;
}
public void onTaskRemoved(Intent rootIntent) {
System.out.println("the saved string was: " + savedString);
super.onTaskRemoved(rootIntent);
}
public void onDestroy() {
System.out.println("destroyed service");
super.onDestroy();
}
}
Where I then have this in my other class:
Intent serviceIntent = new Intent(activity.getApplicationContext(), BackgroundService.class);
serviceIntent.putExtra("myString", "this is my saved string");
activity.startService(serviceIntent);
you need to add a background service
public class BackgroundServices extends Service
{
#Override
public void onCreate() {
Toast.makeText(this, "start", Toast.LENGTH_SHORT).show();
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
then in your activity. where you want to trigger this service
use
startService(new Intent(getBaseContext(), BackgroundServices.class));
in your case it will be call on onDestory function of that activity
Yes when the process is terminated
That is not possible in general. Nothing in your app is called when the process is terminated.
For example when you open the running apps screen, and swipe away the app to stop it from running
That is a task removal. It may result in your process being terminated, and there are many ways in which your process can be terminated that has nothing to do with task removal.
To detect task removal, override onTaskRemoved() in a Service.

How to catch when service died?

Hi i am using service on devises from API 15.
I need to catch when service die itself or when user kill app from task and service stop.
here is my service:
#Override
public void onCreate() {
super.onCreate();
mTimerIntent = new Intent(SERVICE_TIMER_BROADCAST);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null){
mTimerType = intent.getExtras().getInt(TIMER_TYPE_KEY);
mTimer.run();
}
return START_NOT_STICKY;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d("test", "onDestroy");
setLoginStatusFailed();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
super.onTaskRemoved(rootIntent);
Log.d("test", "onTaskRemoved");
setLoginStatusFailed();
}
private void setLoginStatusFailed(){
new USB_LogOut(getApplicationContext());
}
on KitKat device it works great, but when I tried it on 4.0 it is does't work...
Any ideas why it happen and how to fix this?
Services can't run 24 hours a day. At some point the system will very likely need to kill your process to have memory for elsewhere, and you will go away without a call to onDestroy(). Later the system will restart the process and service.
You can return start_sticky in onStartCommand for restart the service if the service killed by the system or user as well .
http://developer.android.com/reference/android/app/Service.html#ServiceLifecycle
You can refer Google forum for more details https://groups.google.com/forum/#!topic/android-developers/2DTkEk73xpk

Persistent Service on Android

I am trying to write a service that comes with a MediaPlayer. I have different Activities accessing it, so I thought it would be best to peruse a Service.
It works fine so far, I have also added a call to startForeground, as described here. The notification shows up.
But when I now press the home or back button on the device, the service is stopped and onDestroy is called, and the notification icon disappears. When I return, the service seems to reBind just fine.
I stop the music playback on onDestroy, so of course it stops. But I would like to keep the notification and service alive even when the user is on another app.
EDIT: I hope this is the relevant part:
public class MediaPlayerService extends Service {
private static class PlayerMessageHandler extends Handler {
private final MediaPlayerService owner;
public PlayerMessageHandler(MediaPlayerService owner) {
this.owner = owner;
}
#Override
public void handleMessage(Message msg) {
// Handle
}
}
private static final int NOTIFICATION_ID = 13138;
private final Messenger messenger = new Messenger(new PlayerMessageHandler(
this));
private MediaPlayer player;
private Notification notification;
#Override
public IBinder onBind(Intent intent) {
startNotification();
return messenger.getBinder();
}
#Override
public void onCreate() {
super.onCreate();
Log.v(TAG, "Media player service created.");
player = new AudiobookPlayer(this);
new Thread(seekerUpdate).start();
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "Received start id " + startId + ": " + intent);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.v(TAG, "Media player service destroyed.");
if (player.isPlaying()) {
player.pause();
}
sendMessageToUI(MSG_PLAYER_HAS_PAUSED);
isRunning = false;
}
private void sendMessageToUI(int msg) {
Log.v(TAG, "Sending " + msg);
sendMessage(Message.obtain(null, msg));
}
private void sendMessage(final Message message) {
// Send
}
private void startNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this);
builder.setSmallIcon(R.drawable.notification);
builder.setContentTitle(getString(R.string.app_name));
notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
}
}
EDIT2: Methods from the activity, taken from here
#Override
protected void onStart() {
super.onStart();
// Bind to the service
bindService(new Intent(this, MediaPlayerService.class),
playerServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
// Unbind from the service
if (bound) {
unbindService(playerServiceConnection);
bound = false;
}
}
You should make your service sticky. In fact, this is what the tutorial uses:
public class HelloService extends Service {
...
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
...
// If we get killed, after returning from here, restart
return START_STICKY;
}
...
}
EDIT: from the discussion that transpired since, turns out that my suspicion was correct, and Hugo provided a spot-on diagnosis. I guess you now need to add builder.setOngoing(true); in startNotification().
Extracted from http://developer.android.com/guide/components/services.html
Bound
A service is "bound" when an application component binds to it by
calling bindService(). A bound service offers a client-server
interface that allows components to interact with the service, send
requests, get results, and even do so across processes with
interprocess communication (IPC). A bound service runs only as long as
another application component is bound to it. Multiple components can
bind to the service at once, but when all of them unbind, the service
is destroyed.
You are binding your Activities on onStart and unbinding on onStop. When you press Home or Back, your last foreground Activity may call onStop, unbinding the last Activity from the Service and killing it.
An alternative solution would be call startService so the onStartCommand will be called, then calling the bindService to bind the Activities.

Categories

Resources