问题

DialogFragment 在 Activity 中创建后通过 show(fm, tag),弹出 Dialog,如下面的代码所示:

1
2
3
MyDialogFragment dialog = new MyDialogFragment(); // 一个自定义的 DialogFragment
dialog.setButtonListener(aListener); // 一个自定义方法,设置一个监听(如某个按钮的回调)
dialog.show(getFragmentManager(), "tag"); // 弹出对话框

点击按钮可以回调 Activity 的 aListener,但是,如果在对话框存在的情况下旋转屏幕,再怎么点按钮aLisenter也不回调了?!

原因

只要理解了Fragment 和 Activity 生命周期就会知道原因其实很简单:

  1. 旋转屏幕时,Activity将会被重新创建。
  2. Activity“临终”前会在onSaveInstanceState()中保存 DialogFragment的状态(FragmentManagerState);
  3. “复活”后的Activity,在onCreate()中会根据savedInstanceState所给予的FragmentManagerState自动重新实例化DialogFragment,并且 show()出 dialog

流程为:

旋转屏幕-->-Activity.onSaveInstanceState()-->-Activity.onCreate()-->- DialogFragment.show()--|

这个时候的DialogFragment所持有的aListener引用当然也不复存在,再点按钮自然也不会收到回调(虽然这个 dialog 看起来跟旋转屏幕之前的没什么两样,但它们是两个实例)

解决办法

  1. 把 Listener变成 Parcelable 对象塞到 Fragment 的 Arguments 中(不推荐)
  2. 在 Activity 的 onCreate() 中 通过 FragmentManager 找到重新实例化的 DialogFragment,重新设置一次 Listener

至于第一种办法,主要是将 Listener 实现 Parcelbale 即可,略~~(就是懒

第二种办法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    // call super first !
    super.onCreate(savedInstanceState);

    // find MyDialogFragment
    if(savedInstanceState != null){
        MyDialogFragment dialog = (MyDialogFragment) getFragmentManager()
                .findFragmentByTag("dialog");
        if(dialog != null)
            dialog.setButtonListener(aListener);
    }
    // ...
    setContentView(...);
}

具体实例代码见:https://github.com/yrom/sample-dialogfragment-listener