完成AsyncTask后,如何处理关闭DialogFragment(兼容性lib)


问题内容

关于如何处理AsyncTask期间的配置更改的文章很多,但是我发现没有一个关于AsyncTask完成并尝试关闭DialogFragment(兼容性库)时处于后台的应用程序(onPause())的明确解决方案。

这是问题所在,如果我运行的AsyncTask应该在onPostExecute()中关闭DialogFragment,则当应用程序试图关闭DialogFragment时,它在后台时会收到IllegalStateException。

private static class SomeTask extends AsyncTask<Void, Void, Boolean> {

    public SomeTask(SomeActivity tActivity)
    {
        mActivity = tActivity;
    }

    private SomeActivity mActivity;

    /** Set the view during/after config change */
    public void setView(Activity tActivity) {
        mActivity tActivity;
    }

    @Override
    protected Boolean doInBackground(Void... tParams) {
        try {
          //simulate some time consuming process
          TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException ignore) {}
        return true;
    }

    @Override
    protected void onPostExecute(Boolean tRouteFound) {
        mActivity.dismissSomeDialog();  
    }

}

该活动如下所示:

import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;

public class SomeActivity extends FragmentActivity {

    public void someMethod() {
        ...
        displaySomeDialog();
        new SomeTask(this).execute();
        ...
    }

    public void displaySomeDialog() {
        DialogFragment someDialog = new SomeDialogFragment();
        someDialog.show(getFragmentManager(), "dialog");
    }

    public void dismissSomeDialog() {
        SomeDialogFragment someDialog = (SomeDialogFragment) getFragmentManager().findFragmentByTag("dialog");
        someDialog.dismiss();
    }

    ....

}

正常运行,除非SomeTask仍在运行时应用程序切换到后台。在那种情况下,当SomeTask尝试关闭disSomeDialog()时,我得到一个IllegalStateException。

05-25 16:36:02.237: E/AndroidRuntime(965): java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

我所见过的所有帖子似乎都通过精心设计的变通办法指向了一些混乱的方向。是否没有某种Android处理方式?如果它是一个Dialog而不是DialogFragment,那么Activity的dismissDialog()将正确处理它。如果它是真实的DialogFragment而不是ACP中的一个,则dismissAllowingStateLoss()将对其进行处理。DialogFragment的ACP版本没有这样的东西吗?


问题答案:

要解决非法状态异常问题并实质上实现dismissAllowingStateLoss(),可以使用以下方法来完成。

getFragmentManager().beginTransaction().remove(someDialog).commitAllowingStateLoss();

这应该在没有hacky代码的情况下解决该问题。如果您具有使用dialog.show();通过处理程序与UI线程进行通信的线程,则也可以将其应用于show。这也可能导致非法状态异常

getFragmentManager().beginTransaction().add(someDialog).commitAllowingStateLoss();

鉴于发帖人的问题,@ joneswah是正确的。如果使用支持库,请更换

getFragmentManager()

getSupportFragmentManager()

对于未来的Google员工:@Alex
Lockwood对该解决方案提出了良好而有效的关注。该解决方案确实可以解决该错误,并且在大多数情况下都可以使用,但是从UX的角度暗示了原始问题中的方法存在问题。

该活动应假定异步任务可能未完成并且不会执行onPostExecute()。无论启动任何UI操作(即微调器,理想情况下不是对话框)来通知用户异步操作,都应具有在超时或通过跟踪状态并检入onRestore
/ onResume类型生命周期事件来自动停止的规定,以确保用户界面已正确更新。服务可能也值得调查。