如何在暂停时处理AsyncTask onPostExecute以避免IllegalStateException

我很欣赏在轮换更改上有关AsyncTask的大量发帖。 使用兼容性库时,遇到以下问题并试图closuresDialogFragment中的onPostExecute

我有一个AsyncTask显示进度DialogFragment ,然后在onPostExecuteclosures对话框,然后可能会抛出另一个DialogFragment

如果进度对话框正在显示,我把应用程序放入后台,我得到了以下的片段:

1) onPause

2) onSaveInstanceState

3) onPostExecute在其中我试图消除和调用一个对话框。

我得到一个IllegalStateException因为我试图有效地提交一个事务,当活动保存了它的状态,我明白这一点。

在我认为(也许不正确),我不会得到一个onPostExecute直到重新创build活动的onPostExecute 。 然而,当把应用程序放到后台时,我认为(当然肯定是错误的) onPostExectute在片段/活动暂停时不会被调用。

我的问题是,我的解决scheme是简单地在onPostExecute中检测到片段/活动已暂停,只需执行我需要在onResume做什么呢? 对我来说似乎有些丑陋。

在此先感谢彼得。

编辑1

需要支持2.1及以上版本

编辑2

我曾考虑使用FragmentTransaction:add显示对话框FragmentTransaction:addFragmentTransaction:commitAllowingStateLoss但是这不是没有问题。

如果您需要将任务与活动生命周期同步,我相信装载机正是您所需要的。 更具体地说,你应该使用AsyncTaskLoader来完成这项工作。 所以,现在不是运行一个AsyncTask,而是启动加载器,然后等待侦听器的响应。 如果活动暂停,您将不会得到callback,这部分将被pipe理。

还有另一种方式来处理这个任务:使用保留其实例的片段。 一般的想法是,你创build一个没有UI的片段,并调用setRetainInstance(true) 。 它有一个任务正在被通知的活动是否可用。 如果不是,任务的线程将暂停,直到一个活动变为可用。

实现你需要的另一种方法是实现我在本文中logging的PauseHandler类。

然后在你的onPostExecute方法中调用sendMessage()将消息发布到处理程序中。

当您的应用程序恢复时,将处理该操作。

而不是使用BroadcastReceiver,我更喜欢使用像番石榴,otto或eventbus这样的总线库。 它们的性能比广播接收机的实现要好得多。

我想出了一个解决这个问题没有任何主要的解决方法:在这个blogentry (当然我使用AsyncTaskComplex版本)中描述了如何维护一个progressdialog和一个asynctask的基本思想。 所有的荣誉都归于这位水浒传的作者,我只是添加了一个小小的东西:

显然,我不再使用showDialog()。 相反,我坚持使用DialogFragments。

第二个调整是importent,也解决了IllegalStateException的问题:

而不是只告诉onRetainCustomNonConfigurationInstance()的asynctask,没有更多的活动,我也做onPause()。 而不是只告诉onCreate()asynctask有一个新的活动,我也做onResume()。

而且你去了,你的AsyncTask不会试图通知你的活动,当活动不可见时,他的完成导致IllegalStateException。

如果您希望看到更多的代码而不是文字,请发表评论。

/编辑:源代码来显示我的解决scheme,我认为是一个相当不错的一个:)

 public class MyActivity extends Activity { private MyTask mTask; @Override protected void onCreate(Bundle pSavedInstanceState) { super.onCreate(pSavedInstanceState); setContentView(R.layout.editaccount); Object retained = getLastCustomNonConfigurationInstance(); if ( retained instanceof NewContactFolderIdTask ) { mTask = (MyTask) retained; mTask.setActivity(this); } } @Override protected void onPause() { if(mTask != null) { mTask.setActivity(null); } super.onPause(); } @Override public Object onRetainCustomNonConfigurationInstance() { if(mTask != null) { mTask.setActivity(null); return mTask; } return null; } @Override protected void onResume() { if(mTask != null) { mTask.setActivity(this); } loadValues(); // or refreshListView or whatever you need to do super.onResume(); } public void onTaskCompleted() { loadValues(); // or refreshListView or whatever you need to do DialogFragment dialogFragment = (DialogFragment) getSupportFragmentManager().findFragmentByTag(PROGRESS_DIALOG_FRAGMENT); if(dialogFragment != null) { dialogFragment.dismiss(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); menuInflater.inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: // app icon in Action Bar clicked; go home Intent intent = new Intent(this, OXClient.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); return true; case R.id.menu_refresh: mTask = new MyTask(this); mTask.execute(); break; } return super.onOptionsItemSelected(item); } private class NewContactFolderIdTask extends AsyncTask<Boolean, Integer, Bundle> { private MyActivity mActivity; private boolean mCompleted; private NewContactFolderIdTask(MyActivity pActivity) { this.mActivity = pActivity; } public void setActivity(MyActivity pActivity) { this.mActivity = pActivity; if(mCompleted) { notifiyActivityTaskCompleted(); } } private void notifiyActivityTaskCompleted() { if(mActivity != null) { mActivity.onTaskCompleted(); } } @Override protected Bundle doInBackground(Boolean... pBoolean) { // Do your stuff, return result } @Override protected void onPreExecute() { DialogFragment newFragment = ProgressDialogFragment.newInstance(); newFragment.show(getSupportFragmentManager(), PROGRESS_DIALOG_FRAGMENT); } @Override protected void onPostExecute(Bundle pResult) { mCompleted = true; notifiyActivityTaskCompleted(); } } 

}

在活动/片段暂停时如何处理Handler消息我提供了使用BroadcastReceiver的另一种方法。

我认为它更清洁更优雅,它提供的优点是你可以从你的应用程序中的任何地方调用基本片段上的代码,并且通过使用粘性广播,你的调用可以被“记住”并在片段恢复后执行。