Android data storage performance

android, mobile

Solution

There is no need to keep your activity in the foreground waiting for a background logic to complete.

What you should do instead is to execute this background logic in a way which is 'detached' from your activity.

There are two ways of solving this problem: risky and safe.

The Risky Way

class MyActivity extends Activity {

     void calledWhenActivityNeedsToBeClosed() {

          // start a thread to do background work
          new Thread() {
                public void run() {
                     perform long running logic here
                }
          }.start();

          // and clos the activity without waiting for the thread to complete
          this.finish();
     }
}

You can use an AsyncTask or any of the java.concurrent constructs instead of the thread. They will all do the work.

I have used this way for years. It mostly works fine. But.. it is inherently flawed. Why? Because once activity is finish()-ed, Android can at any time reclaim it together with all its resources and including halting of all worker threads. If your long running work does not exceed several seconds, and I assume your repo update is such, the risk here is minimal. But why take it?

The Safe Way

Declare a Service and before activity going down activate it to perform the long running action:

class MyActivity extends Activity {

     void calledWhenActivityNeedsToBeClosed() {

          // delegate long running work to service
          startService(this, new Intent(this, MyWorkerService.class));

          // and close the activity without waiting for the thread to complete
          this.finish();
     }

}

This is much safer. Android can, and often does, also kill running services, but is does so much more reluctantly than killing background activities.

Note that if you can see a scenario in which your UI is visible while the worker service is still running, you would probably want to use an IntentService instead.

Finally - if you want to be absolutely assured that background logic will not be cleared by Android, you should use a foreground service. Below is how to do it, but please be warned - in cases like you have described, a foreground service is probably over engineering:

static final int NOTIF_ID = 100;

// Create the FG service intent 
Intent intent = new Intent(getApplicationContext(), MyActivity.class); // set notification activity
showTaskIntent.setAction(Intent.ACTION_MAIN);
showTaskIntent.addCategory(Intent.CATEGORY_LAUNCHER);
showTaskIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

PendingIntent pIntent = PendingIntent.getActivity(
                getApplicationContext(),
                0,
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT);

Notification notif = new Notification.Builder(getApplicationContext())
                .setContentTitle(getString(R.string.app_name))
                .setContentText(contentText)
                .setSmallIcon(R.drawable.ic_notification)
                .setContentIntent(pIntent)
                .build();

startForeground(NOTIF_ID, notif);

Problem

I m actually developping an Android application with data storage, and I proceed like this : Activity -> Business services -> Repo (with Spring REST fw). Using this, I m forced to let the activity finish his storing job before closing it (thread treatment, progress dialog ...). Is this a bad way of coding to use an android service to store data ? With this, users can continue to navigate, and have the impression to work with a very fluid application. Is this a good solution ? Thanks

Original source