开发者

How can I detect if an Activity is in a usable state from a Runnable?

I have a Service which is performing a data update. I have an activity which attaches a listener to the service (via a local binding). The listener receives progress updates. Upon receiving a progress update, it schedules a runnable to be run on the UI thread. Here's the code (updated to show the full listing):

public class MyActivity extends Activity {

  static final int UPDATE_DIALOG = 0;
  ProgressDialog updateDialog;

  private TaskService taskService;

  private ServiceConnection taskServiceConnection = new ServiceConnection() {

    private final TaskServiceObserver taskServiceObserver = new TaskServiceObserver() {

      public void updateProgress(final int progress, final int total) {
        runOnUiThread(new Runnable() {
          public void run() {          
            if (updateDialog == null || !updateDialog.isShowing()) {
              showDialog(UPDATE_DIALOG);
            }
            updateDialog.setProgress(progress);
          }
        });
      }

      public void updateCompleted() {
        runOnUiThread(ne开发者_如何学JAVAw Runnable() {
          public void run() {  
            dismissDialog(UPDATE_DIALOG);
            startNextActivity();
          }
        });
      }
    };

    public void onServiceConnected(ComponentName name, IBinder binder) {
      taskService = ((LocalBinder) binder).getService();

      taskService.addObserver(taskServiceObserver);
    }

    public void onServiceDisconnected(ComponentName name) {
      taskService.removeObserver(taskServiceObserver);
      taskService = null;
    }

  };

  protected void onStart() {
    super.onStart();

    Intent intent = new Intent(this, TaskService.class);
    startService(intent);
    bindService(intent, taskServiceConnection, Context.BIND_AUTO_CREATE);
  }

  protected void onStop() {
    super.onStop();

    if (taskService != null) {
      unbindService(taskServiceConnection);
    }
  }

  protected Dialog onCreateDialog(int id) {
    switch (id) {
    case UPDATE_DIALOG:
      updateDialog = new ProgressDialog(this);
      updateDialog.setTitle("My App");
      updateDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      updateDialog.setMessage("Preparing to run for the first time...");
      return updateDialog;
    default:
      return null;
    }
  }

}

If I tap the home button while the dialog is showing, then return to the app, I get a crash on the showDialog line. With the debugger I was able to determine that the activity is in the finished state.

What would be an appropriate check to put in my runnable which would determine whether it is safe to call showDialog?


I would personnally dismiss the progress dialog when the activity goes to pause (override onPause) and recreate it if necessary when the activity is resumed (override onResume). You could be leaking memory by keeping references to your activity in other separate objects (your dialog)


You should detach the listener in the onPause method so that since your activity is going into the background, the listener won't fire and try to update the UI.


The solution I ended up going with was to create a flag taskServiceBound which was set to true after binding to the service in onStart and set to false before unbinding from the service in onStop. Because the flag is updated on the UI thread, I can use it to gate the Runnables in updateProgress and updateCompleted. For example:

  public void updateCompleted() {
    runOnUiThread(new Runnable() {
      public void run() {  
        if (taskServiceBound) {
          dismissDialog(UPDATE_DIALOG);
          startNextActivity();
        }
      }
    });
  }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜