FragmentManager.findFragmentByTag返回null

Mis*_*ith 1 android progressdialog android-fragments actionbarsherlock android-support-library

我正在使用Android支持库(v4)和ActionBarSherlock.我正在尝试以编程方式关闭进度对话框.我编写了一个小实用程序类来帮助对话管理.

该对话框显示为AsyncTask.onPreExecute.它会正确显示.然后我通过旋转设备来触发配置更改,这会破坏活动(onDestroy调用AsyncTask.cancel(true)).AsyncTask.onCancelled被调用,并且在我尝试关闭对话框的方法中.但没有任何反应.以下是显示和关闭对话框的辅助函数:

    public abstract class DialogHelperActivity extends SherlockFragmentActivity {

        protected void showProgressDialog(final String msg, final String tag){      
            FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
            DialogFragment dialogFragment = ProgressDialogFragment.newInstance(msg);

            ft.add(dialogFragment, tag);
            ft.disallowAddToBackStack();
            ft.commitAllowingStateLoss(); //If I try with regular commit(), exceptions are thrown.
        }

        protected void closeDialog(final String tag){
            FragmentManager fm = this.getSupportFragmentManager();
            Fragment dialogFragment = fm.findFragmentByTag(tag);        

            if(dialogFragment != null){
                FragmentTransaction ft = fm.beginTransaction();
                ft.remove(dialogFragment);
                ft.commitAllowingStateLoss();
            } else {
                System.err.println("dialog not found!"); //This line is hit always
            }               
        }


        public static class ProgressDialogFragment extends SherlockDialogFragment {     

            static ProgressDialogFragment newInstance(final String msg) {
                ProgressDialogFragment adf = new ProgressDialogFragment();
                Bundle bundle = new Bundle();

                bundle.putString("alert-message", msg);

                adf.setArguments(bundle);
                return adf;
            }

            @Override
            public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                this.setCancelable(false);
                int style = DialogFragment.STYLE_NORMAL, theme = 0;
                setStyle(style,theme);
            }

            @Override
            public Dialog onCreateDialog(Bundle savedInstanceState) {
                Bundle bundle = this.getArguments();

                String message = bundle.getString("alert-message");


                ProgressDialog dialog = new ProgressDialog(getActivity());
                if(message != null){
                    dialog.setMessage(message);
                }

                dialog.setCancelable(false);
                dialog.setIndeterminate(true);

                return dialog;
            }       
        }

    }
Run Code Online (Sandbox Code Playgroud)

旋转设备后,AsyncTask被取消.我closeDielog来自onPostExecute和来自onCancelled.对话框永远不会关闭,因为找不到标记ID(findFragmentByTag返回null).我对此感到困惑.标签是我的实现活动中的静态字符串,因此在调用showProgressDialog和之间不会丢失或更改它closeDialog.

任何想法/提示/建议将不胜感激.

谢谢.

Mis*_*ith 7

问题是我正在取消AsyncTask活动中的onDestroy.这可以摆脱bg线程,但AsyncTask.onCancelled不能关闭片段,因为它在活动被销毁后运行.在此之前,会创建一个新活动,片段管理器会恢复一个新对话框(即使它是使用创建的setRetainInstance(false),我猜这是默认设置).

通话的时间表是这样的:

  1. 屏幕旋转会触发配置更改
  2. 旧活动进入onDestroy,取消asynctask.
  3. 旧对话框进入onDetach.
  4. 新活动已创建.
  5. 创建新对话框,附加到新活动并显示.
  6. 旧任务onCancel执行,调用closeDialog,但找不到标记.

我的错误是假设字符串标记在应用程序上下文中全局标识了一个片段,但事实证明片段管理器分配的实际片段ID是片段标记/ id及其活动ID的组合.当活动被销毁时,它们的片段被分离,在此之后,即使具有相同标记/ id的新片段在前景中,因为它附加到不同的活动,片段管理器在旧活动时返回null调用findFragmentByTag.

但是,此标记/ id足以使新片段传递旧片段的参数包.这种二元性令人困惑,但它也能实现黑客攻击:我们可以在其onStop回调中使用"已取消"标志填充片段的参数包,在回调中对其进行查询onResume,如果找到该标志,则调用它自动解除.这样我就可以拥有一个概念上属于AsyncTask的进度对话框,并随之消失.