Question

For instance, we are in SomeActivity and the activity has a button that invokes moving files from one dir to another (let's call it job).

On BlackBerry I would:

  1. push a non-cancellable popup (Dialog screen) saying "Please wait..."
  2. start a thread that fulfills the job
  3. on thread completion close the popup

This approach 99.99% can guarantee that we stay on the same screen after the task is over, user just sees the popup and waits for job completion. Device rotation or whatever does not break the desired workflow.

On Android things change. I know there's the AsyncTask that is probably provided to solve my case. There's even a good example of how it should be used. But since there's no guarantee of how long an Activity instance will live the AsyncTask should be cancelled on onSaveInstanceState (and restarted on onRestoreInstanceState). This means using AsyncTask there's no guarantee we are able to fully fulfill the job once started. In some cases as sending an http post request for creating a user I would not want to get in "user already exists for this login" trouble on reruning the AsyncTask. This is possible since the AsyncTask can be interrupted while the request is already sent (and the server actually is doing its job - creating a new user), but the AsyncTask is canceled before we got the response.

Is there any solution on Android to get the BB-like behaviour stated above?

Was it helpful?

Solution 3

In May 2010 Google issued a new IO session called Developing Android REST client applications which explains how to achieve exactly what I asked for.

It turned out the question is rather complicated, so there is no easy and quick solution. The solution requires deep knowledge of Android platform/API. This is the price caused by the flexibility of the app process/Activity lifecycles.

I feel some oddity on why this info was not presented from the very first version of Android. Looks like Google knew how to write 100% bugless apps and for some marketing reason did not share the approach. Just imagine how many buggy apps was written by May 2010.

Anyway I'm glad now I have smth we call best practice approach.

OTHER TIPS

But since there's no guarantee of how long an Activity instance will live the AsyncTask should be cancelled on onSaveInstanceState (and restarted on onRestoreInstanceState).

Or have it be managed by a Service.

If your Activity wants to stay on the screen, you can simply start a Thread like this:

final File fromFile = ...;
final File toFile = ...;

new Thread() {
    @Override
    public void run() {
      // do something with fromFile, toFile
    }
}.start();

That way the GUI-Thread is ready to do other thinks like displaying a

  android.app.ProgressDialog

Also, consider making the Dialog uncancellable with

  ProgressDialog.setCancelable(false);

That way the user can only leave via the HOME-Key, which you get notified of when

  Activity.onPause()

is called. Futhermore you might want to look into Wakelocks, to stop the Screen from turning black and your application pushed in the background where it might be killed. You'd do this in the Thread:

  PowerManager pm = (PowerManager) ivContext.getSystemService(Context.POWER_SERVICE);
  Wakelock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp");
  wakeLock.acquire();

  // ... copy stuff ...

  wakeLock.release();

Of course you'd have to release the wakeLock, too, when the user leaves via the HOME-Key.

Finally if you want to call GUI-Elements from your background-thread, this will only work if the Thread is part of the GUI-Event-Loop, like the normal Thread is you are running in, when getting called with on...-Methods. To achieve this your background-thread will have to callback to the GUI-Thread via a Handler. Like this:

  private Handler mHandler = new Handler() { 
      @Override
      public void handleMessage(Message msg) {
          Log.v(TAG, "Got Message "+msg.what); // prints: Got Message 77
      // ... do GUI actions ...
      }    
  };

  // ... in Thread ...

  int lvInfo = 77;
  mHandler.sendEmptyMessage(lvInfo);

You can even put objects in the message like so:

  Message txtMsg = Message.obtain();
  textMsg.obj = "Hello World";
  mHandler.sendMessage(lvTextMsg);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top