【问题标题】:onCreateView() for Fragment being called before Activity onRestoreInstanceState()在 Activity onRestoreInstanceState() 之前调用 Fragment 的 onCreateView()
【发布时间】:2016-12-18 21:32:18
【问题描述】:

所以我有一个附加到活动的片段,我试图确保在屏幕旋转时事情顺利进行(或任何会中断活动的事情)。为此,我在我的活动中使用了 onSaveInstanceState 和 onRestoreInstanceState 方法来保存我的活动存储的信息。

当我的片段的视图被创建时,片段向 Activity 询问信息(这是片段的 onCreateView() ):

ArrayList<String> picList = mListener.getPics();
ArrayList<String> descripList = mListener.getDescriptions();

为了让片段创建视图,它需要访问 picList 和 descripList,它们是活动的成员变量。这些成员变量在 onSaveInstanceState 和 onRestoreInstanceState 中存储和恢复。

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    if(photoFile != null)
        outState.putString("photoFile", photoFile.getAbsolutePath());
    outState.putString("currentFragTag", currentFragTag);
    outState.putStringArrayList("picList", picList);
    outState.putStringArrayList("descripList", descripList);
}

@Override
protected void onRestoreInstanceState(Bundle saved) {
    super.onRestoreInstanceState(saved);
    if(saved.getString("photoFile") != null)
        photoFile = new File(saved.getString("photoFile"));
    currentFragTag = saved.getString("currentFragTag");
    picList = saved.getStringArrayList("picList");
    descripList = saved.getStringArrayList("descripList");
    currentFrag = getFragmentManager().findFragmentByTag(currentFragTag);
    changeFrag(currentFrag, currentFragTag);
}

问题是,在活动中调用 onRestoreInstanceState() 之前调用了 onCreateView()。我尝试在片段中使用 onActivityCreated(),但这也是在 onRestoreInstanceState() 之前调用的。附加调试器后,当屏幕旋转时,始终最后调用 onRestoreInstanceState()。这意味着片段在创建视图时无法访问活动的信息。

这应该发生吗?恢复 Activity 时,如何让 Fragment 的视图使用来自 Activity 的信息?

【问题讨论】:

  • 您是否将 Fragment 设置为setRetainInstance(true)
  • 我没有。那会带来什么?我快速搜索了一下,发现不能用于 back stack 上的 Fragments,会出现问题。
  • 它需要在创建 Fragment 实例时简单地调用该方法。我不完全确定它的作用,但这是保留片段状态的一种方式。也许你可以参考这里? stackoverflow.com/questions/15313598/…

标签: android android-fragments


【解决方案1】:

我认为最简单的方法是使用 EventBus。
您可以在重新创建 Activity 时发送“msg”,您的 Fragment 的“目标方法”将获取此 msg(该 msg 是 Object,它可以是一个 bundle)。

【讨论】:

  • 顺便说一句,@Ardock 的回答很棒。
【解决方案2】:

更新回复:

阅读替代方案Passing data between a fragment and its container activity。另见this

修改了之前的回复:

请参阅 this 并尝试将您的代码放在 onResume() 中并使视图无效或 detach/attach the fragment 作为快速解决方案,但不是 the best solution 正如 Alex Lockwood 所说:

片段是可重复使用的 UI 组件。他们有自己的生命周期, 展示自己的观点,定义自己的行为。你通常 不需要让您的活动与内部混乱 片段的工作,因为片段的行为应该是 独立于任何特定活动。

如果确实需要之前的代码,重写next方法,直接在fragment中保存/恢复需要的数据:

/**
 * Called when the fragment's activity has been created and this
 * fragment's view hierarchy instantiated.  It can be used to do final
 * initialization once these pieces are in place, such as retrieving
 * views or restoring state.  It is also useful for fragments that use
 * {@link #setRetainInstance(boolean)} to retain their instance,
 * as this callback tells the fragment when it is fully associated with
 * the new activity instance.  This is called after {@link #onCreateView}
 * and before {@link #onViewStateRestored(Bundle)}.
 *
 * @param savedInstanceState If the fragment is being re-created from
 * a previous saved state, this is the state.
 */
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        restoreInstanceState(savedInstanceState);
    }
}

/**
 * Called to ask the fragment to save its current dynamic state, so it
 * can later be reconstructed in a new instance of its process is
 * restarted.  If a new instance of the fragment later needs to be
 * created, the data you place in the Bundle here will be available
 * in the Bundle given to {@link #onCreate(Bundle)},
 * {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}, and
 * {@link #onActivityCreated(Bundle)}.
 *
 * <p>This corresponds to {@link Activity#onSaveInstanceState(Bundle)
 * Activity.onSaveInstanceState(Bundle)} and most of the discussion there
 * applies here as well.  Note however: <em>this method may be called
 * at any time before {@link #onDestroy()}</em>.  There are many situations
 * where a fragment may be mostly torn down (such as when placed on the
 * back stack with no UI showing), but its state will not be saved until
 * its owning activity actually needs to save its state.
 *
 * @param outState Bundle in which to place your saved state.
 */
@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.put...;
}

并创建这个,用于从包中检索所需的数据:

public void restoreInstanceState(Bundle savedInstanceState) {
    ... = savedInstanceState.get...
}

或使用getActivity() 方法从此处直接访问某些方法或字段,如果您出于某种原因需要有关活动的代码。

/**
 * Return the {@link FragmentActivity} this fragment is currently associated with.
 * May return {@code null} if the fragment is associated with a {@link Context}
 * instead.
 */
final public FragmentActivity getActivity() {
    return mHost == null ? null : (FragmentActivity) mHost.getActivity();
}

例如:((YourActivity) getActivity()).getPics();

并将getPics() 方法添加到活动中。

更多信息here 和定义接口here 的替代解决方案。

【讨论】:

  • 你能在 onResume() 中编辑片段的视图吗?因为我使用 onResume() 进行了测试,并且虽然我能够从活动中访问信息,但我的方法包括如下几行:descrip.setText(descripList.get(i));、img.setImageBitmap(bitmap);但是视图没有改变
  • 您可以使视图无效或分离/附加片段,但我认为有更好的设计替代方案,请阅读此stackoverflow.com/questions/12705342/…
猜你喜欢
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-08
  • 1970-01-01
  • 1970-01-01
  • 2015-07-29
  • 2012-02-12
相关资源
最近更新 更多