我有一个使用 NavigationDrawer 模式的 AppCompatActivity,用于管理一些 fragment 。其中一个没有 setRetainInstance(true)
,我显示了一个 DialogFragment,其中包含一个 ProgressDialog 和一个带有以下代码的 AsyncTask:
SavingLoader savingLoader = SavingLoader.newInstance(savingLoaderMaxValue);
savingLoader.show(getChildFragmentManager(), SAVING_LOADER_TAG);
new MyAsyncTask().execute();
其中 SavingLoader
类是这个:
public class SavingLoader extends DialogFragment {
private static final String MAX_VALUE_TAG = "MAX_VALUE_TAG";
private static final String PROGRESS_VALUE_TAG = "PROGRESS_VALUE_TAG";
public static SavingLoader newInstance(int max_value){
SavingLoader s = new SavingLoader();
Bundle args = new Bundle();
args.putInt(MAX_VALUE_TAG, max_value);
s.setArguments(args);
return s;
}
private ProgressDialog dialog;
public SavingLoader(){}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setCancelable(false);
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState){
dialog = new ProgressDialog(getActivity(), getTheme());
dialog.setTitle(getString(R.string.dialog_title_saving));
dialog.setMessage(getString(R.string.dialog_message_saving));
dialog.setIndeterminate(false);
int max = (savedInstanceState == null ?
getArguments().getInt(MAX_VALUE_TAG) : savedInstanceState.getInt(MAX_VALUE_TAG));
if (max >= 1){
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
dialog.setProgress((savedInstanceState == null ?
0 : savedInstanceState.getInt(PROGRESS_VALUE_TAG)));
dialog.setMax(max);
} else dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
return dialog;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(MAX_VALUE_TAG, dialog.getMax());
outState.putInt(PROGRESS_VALUE_TAG, dialog.getProgress());
}
public int getProgress(){
return dialog.getProgress();
}
public int getMax(){
return dialog.getMax();
}
public void incrementProgressBy(int value){
if (dialog.getProgress() + value <= dialog.getMax())
dialog.incrementProgressBy(value);
}
}
在 onPostExecute()
方法中,我需要执行一些 UI 更新,所以这是我的问题:如果我启动对话框和 AsyncTask (如上)并且我不旋转手机,所有按预期工作。如果我在 onPostExecute()
方法之后旋转手机,也会发生同样的情况。但是,如果我在 AsyncTask 仍在运行时旋转手机,当它完成并到达 onPostExecute()
方法时,它会给出 IllegalStateException
,表示托管 AsyncTask 的 fragment 和Dialogfragment 不再附加到该 Activity 。因此,我尝试重写 fragment 的 onAttach()
和 onDetach()
方法(使用简单的 System.out.println
) ,查看 onPostExecute()
何时被调用。结果是,当我旋转手机时,我总是得到以下输出:
onDetach
onAttach
... (if I rotate more my phone)
onPostExecute
那么当 AsyncTask 完成时不应该附加 fragment 吗?感谢大家的时间和关注。
最佳答案
我终于通过停止使用 AsyncTask
并使用 LoaderManager 解决了这个问题。 + AsyncTaskLoader遵循此article 。简而言之,您的 fragment 必须实现 LoaderCallbacks接口(interface)并管理AsyncTaskLoader
。骨架 fragment 可能是这样的:
public class MyFragment extends Fragment implements LoaderManager.LoaderCallbacks {
@Override
public View onCreateView(LayoutInflater inflater, final ViewGroup container,
Bundle savedInstanceState) {
// Inflate here your view as you usually do and find your components
// For example imagine to have a button tha will fire the task
Button b = (Button) view.findViewById(R.id.my_button);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Use this to start task for the first time
getLoaderManager().initLoader(0, null, this);
// .. or this for restart the task, details in
// the provided article
// getLoaderManager().restartLoader(0, null, this);
}
});
// Get fragments load manager
LoaderManager lm = getLoaderManager();
if (lm.getLoader(0) != null) {
// Reconnect to an existing loader
lm.initLoader(0, null, this);
}
// Return your view here
return view;
}
// LoaderCallbacks methods to override
@Override
public Loader onCreateLoader(int id, Bundle args) {
// Create an instance of the loader passing the context
MyTaskLoader loader = new MyTaskLoader(getActivity());
loader.forceLoad();
return loader;
}
@Override
public void onLoadFinished(Loader loader, Object data) {
// Use this callback as you would use the AsyncTask "onPostExecute"
}
@Override
public void onLoaderReset(Loader loader) {}
// Now define the loader class
private static class MyTaskLoader extends AsyncTaskLoader {
public MyTaskLoader(Context context){
super(context);
}
@Override
public Object loadInBackground() {
// Do here your async work
}
}
}
关于android - IllegalStateException fragment 在旋转后未附加到 onPostExecute 中的 Activity ,但未调用 onDetach,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31057766/