配置更改后,无法在保留的实例片段中解除DialogFragment



我在保留的实例片段中有一个进度对话框(使用DialogFragment实现)。

如果没有配置更改,则可以在没有任何问题的情况下解除DialogFragment

但是,如果配置发生更改,调用dismiss将不会有任何效果。

主活动.java

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        if (savedInstanceState == null) {
            BackupTaskFragment backupTaskFragment = BackupTaskFragment.newInstance();
            FragmentManager fm = getFragmentManager();
            Fragment oldFragment = fm.findFragmentByTag("BACKUP_TASK_FRAGMENT");
            if (oldFragment != null) {
                fm.beginTransaction().remove(oldFragment).commit();
            }
            fm.beginTransaction().add(backupTaskFragment, "BACKUP_TASK_FRAGMENT").commit();
        }
    }
}

BackupTaskFragment.java

public class BackupTaskFragment extends Fragment {
    public static final class BackupTaskDialogFragment extends DialogFragment {
        public static BackupTaskDialogFragment newInstance() {
            return new BackupTaskDialogFragment();
        }
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            ProgressDialog progressDialog = new ProgressDialog(this.getActivity());
            progressDialog.setMessage("Backup...");
            progressDialog.setCanceledOnTouchOutside(false);
            return progressDialog;
        }
    }
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Retain this instance so it isn't destroyed when MainActivity and
        // MainFragment change configuration.
        setRetainInstance(true);
        backupTask = new BackupTask(this);
        backupTask.execute();
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (isResumed() && backupTask != null) {
                    backupTaskDialogFragment = BackupTaskDialogFragment.newInstance();
                    FragmentManager fm = BackupTaskFragment.this.getFragmentManager();
                    fm.beginTransaction().add(backupTaskDialogFragment, BACKUP_TASK_DIALOG_FRAGMENT).commitAllowingStateLoss();
                }
            }
        }, 1500);
    }
    @SuppressLint("NewApi")
    public void onPause() {
        super.onPause();
        android.util.Log.i("CHEOK", "onPause");
        Activity activity = this.getActivity();
        boolean kill = false;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            if (activity != null && false == activity.isChangingConfigurations()) {
                // Stop the thread when home is pressed.
                kill = true;
            }
        } else {
            // I have no idea how to perform configuration checking in older API
            // Just do nothing, by letting the thread continue to run.
            //
            // http://stackoverflow.com/questions/15458540/calling-activity-ischangingconfigurations-in-fragment-for-api-level-lesser-than
        }
        if (kill) {
            if (backupTask != null) {
                backupTask.cancel(true);
                backupTask = null;
            }
            BackupTaskDialogFragment backupTaskDialogFragment = this.backupTaskDialogFragment;
            if (backupTaskDialogFragment != null) {
                android.util.Log.i("CHEOK", "onPause dismiss backupTaskDialogFragment");
                backupTaskDialogFragment.dismiss();
            }
        }
    }
    // This is also called by the AsyncTask.
    public void onPostExecute(File file) {
        if (isResumed()) {
            android.util.Log.i("CHEOK", "onPostExecute isResumed true");
        } else {
            android.util.Log.i("CHEOK", "onPostExecute isResumed false");
        }
        backupTask = null;
        BackupTaskDialogFragment backupTaskDialogFragment = this.backupTaskDialogFragment;
        if (backupTaskDialogFragment != null) {
            android.util.Log.i("CHEOK", "onPostExecute dismiss backupTaskDialogFragment");
            backupTaskDialogFragment.dismiss();
        }
    }
    public static BackupTaskFragment newInstance() {
        return new BackupTaskFragment();
    }
    private BackupTask backupTask;
    private BackupTaskDialogFragment backupTaskDialogFragment = null;
    private static final String BACKUP_TASK_DIALOG_FRAGMENT = "BACKUP_TASK_DIALOG_FRAGMENT";
}

备份任务.java

public class BackupTask extends AsyncTask<Void, Void, File> {
    public BackupTask(BackupTaskFragment backupTaskFragment) {
        this.backupTaskFragment = backupTaskFragment;
    }
    @Override
    protected File doInBackground(Void... params) {
        android.util.Log.i("CHEOK", "BackupTask sleep for 20 seconds...");
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        android.util.Log.i("CHEOK", "BackupTask sleep for 20 seconds done!");
        return null;
    }
    @Override
    protected void onPostExecute(File file) {
        this.backupTaskFragment.onPostExecute(file);
    }
    private final BackupTaskFragment backupTaskFragment;
}

正如您所看到的,当BackupTask完成执行时,它将触发BackupTaskFragment的onPostExecute,以解除BackupTaskDialogFragment

然而,在BackupTaskFragment的onPostExecute之前是否有配置更改,解除BackupTaskDialogFragment不起作用。

知道为什么它不起作用吗?我们该如何解决这个问题?

完整的最小可行代码可以从https://www.dropbox.com/s/dcy856zmp18dhgk/MyApplication.zip?dl=0

当配置发生更改时,BackupTaskFragment中的this.backupTaskDialogFragment不再引用当前运行的对话框片段。

代替

BackupTaskDialogFragment backupTaskDialogFragment = this.backupTaskDialogFragment;
if (backupTaskDialogFragment != null) {

使用

public BackupTaskDialogFragment getBackupTaskDialogFragment() {
    Activity activity = getActivity();
    if (activity != null) {
        FragmentManager fm = activity.getFragmentManager();
        return (BackupTaskDialogFragment)fm.findFragmentByTag(BACKUP_TASK_DIALOG_FRAGMENT);
    }
    return null;
}
...
BackupTaskDialogFragment backupTaskDialogFragment = getBackupTaskDialogFragment();
if (backupTaskDialogFragment != null) {

最新更新