为什么FragmentManager.findFragmentByTag(TAG_TASK_FRAGMENT)不返回null

时间:2015-11-11 06:16:52

标签: android fragment

我读了这个http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html。我在链接中播放了示例代码。令我惊讶的是,如果我在TaskFragment.onCreate()中删除setRetainInstance(true),当我旋转手机时,fm.findFragmentByTag(TAG_TASK_FRAGMENT)不会返回null。我在这里复制代码一行换行(删除setRetainInstance(true))。

请解释为什么fm.findFragmentByTag(TAG_TASK_FRAGMENT)在这种情况下不会返回null。

public class MainActivity extends Activity implements TaskFragment.TaskCallbacks {

  private static final String TAG_TASK_FRAGMENT = "task_fragment";

  private TaskFragment mTaskFragment;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    FragmentManager fm = getFragmentManager();
    mTaskFragment = (TaskFragment) fm.findFragmentByTag(TAG_TASK_FRAGMENT);

    if (mTaskFragment == null) {
      mTaskFragment = new TaskFragment();
      fm.beginTransaction().add(mTaskFragment, TAG_TASK_FRAGMENT).commit();
    }
  }

  @Override
  public void onPreExecute() { }

  @Override
  public void onProgressUpdate(int percent) { }

  @Override
  public void onCancelled() {  }

  @Override
  public void onPostExecute() { }
}


public class TaskFragment extends Fragment {
  interface TaskCallbacks {
    void onPreExecute();
    void onProgressUpdate(int percent);
    void onCancelled();
    void onPostExecute();
  }

  private TaskCallbacks mCallbacks;
  private DummyTask mTask;

  @Override
  public void onAttach(Activity activity) {
    super.onAttach(activity);
    mCallbacks = (TaskCallbacks) activity;
  }

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

// I remove this call to produce the problem
 //   setRetainInstance(true);

    mTask = new DummyTask();
    mTask.execute();
  }

  @Override
  public void onDetach() {
    super.onDetach();
    mCallbacks = null;
  }

  private class DummyTask extends AsyncTask<Void, Integer, Void> {   
    @Override
    protected void onPreExecute() {
      if (mCallbacks != null) {
        mCallbacks.onPreExecute();
      }
    }

    @Override
    protected Void doInBackground(Void... ignore) {
      for (int i = 0; !isCancelled() && i < 100; i++) {
        SystemClock.sleep(100);
        publishProgress(i);
      }
      return null;
    }

    @Override
    protected void onProgressUpdate(Integer... percent) {
      if (mCallbacks != null) {
        mCallbacks.onProgressUpdate(percent[0]);
      }
    }

    @Override
    protected void onCancelled() {
      if (mCallbacks != null) {
        mCallbacks.onCancelled();
      }
    }

    @Override
    protected void onPostExecute(Void ignore) {
      if (mCallbacks != null) {
        mCallbacks.onPostExecute();
      }
    }
  }
}

1 个答案:

答案 0 :(得分:1)

SetRetainInstance控制整个片段(及其内容)是保留在内存中还是从Bundle重新创建为新片段。

它返回null的唯一时间是应用程序第一次运行。之后它已添加到FragmentManager并始终可用。 (无论您是否使用FragmentManager,旋转设备都不会清除SetRetainInstance

您似乎认为SetRetainInstance控制片段是否保留在FragmentManager中。它没有。

在您的示例中,AsyncTask在第一次创建Fragment时开始运行。 SetRetainInstance用于停止正在调用的Fragment的OnDestroy方法。方向更改后,片段及其运行任务仍在FragmentManager中,任务仍在运行。如果没有SetRetainInstance,当Orientation发生更改时,从FragmentManager中检索片段时,片段将被销毁并从其bundle中重新创建。这使得AsyncTask处于一个微妙的状态,因为任务仍然可以运行,即使它的托管片段已被破坏可能导致崩溃。

请参阅此问题以获得更深入的解释。

Understanding Fragment's setRetainInstance(boolean)