How to execute background task when Android app is closed / set to background?

You can use services for what you want to achieve. A service will keep on running in the background even when the activity component has been destroyed, provided you have not invoked stopService(..) or stopSelf() methods.

In the service you can make an Async network call, preferably using retrofit, and then you can update you local storage like Sqlite DB with the latest data fetched from your web service.

Here is the official link, you can just use an unbounded service for what you want to achieve.


The accepted answer is not correct.

Unfortunately, the author believes that posting a new Runnable task to the Handler() creates a separate thread - "I created a separate thread to perform your background operations" :

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    handler = new Handler();
    handler.post(new Runnable() {
        @Override
        public void run() { 
           // write your code to post content on server
        }
    });
    return android.app.Service.START_STICKY;
}

onStartCommand() callback is always called on the main thread, and the new Handler() is attached to the current thread (which is "main"). So the Runnable task is posted at the end of main thread queue.

To fix the issue and execute the Runnable in a really separate thread you can use AsyncTask as the simplest solution:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            // ...
        }
    });
    return android.app.Service.START_STICKY;
}

Think yourself before you copy-paste anything ...


The following code will help you to post your contents when your app is closed or in the background:

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.widget.Toast;

public class SendDataService extends Service {
    private final LocalBinder mBinder = new LocalBinder();
    protected Handler handler;
    protected Toast mToast;
 
    public class LocalBinder extends Binder {
        public SendDataService getService() {
            return SendDataService .this;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        handler = new Handler();
        handler.post(new Runnable() {
            @Override
            public void run() { 

// write your code to post content on server
            }
        });
        return android.app.Service.START_STICKY;
    }

}

More explanation of my code is:

Service runs in the background even if your application is in the background, but remember, it always runs on the main thread, because of which I created a separate thread to perform your background operations.

Service is started as a sticky one, as even if because of any reason your service got destroyed in the background it will automatically get restarted.

More details can be found here: https://developer.android.com/guide/components/services.html

And to check if your app is in the foreground/background, the following code will help:

  private boolean isAppOnForeground(Context context) {
    ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
    if (appProcesses == null) {
      return false;
    }
    final String packageName = context.getPackageName();
    for (RunningAppProcessInfo appProcess : appProcesses) {
      if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
        return true;
      }
    }
    return false;
  }
}

// Use like this:
boolean foregroud = new ForegroundCheckTask().execute(context).get();

Happy Coding!!!!