android片段 - 如何在片段上推送另一个片段时保存片段中的视图状态

pan*_*wal 132 android android-fragments

在android中,一个片段(比如说FragA)被添加到backstack而另一个片段(比如说FragB)会出现在顶部.现在回击FragA到顶部并被onCreateView()称为.现在我FragA处于一个特定的状态,然后FragB被推到它之上.

我的问题是如何恢复FragA到以前的状态?有没有办法保存状态(比如说在Bundle中),如果有,那么我应该覆盖哪种方法?

ani*_*nia 99

片段指南 FragmentList示例中,您可以找到:

@Override
public void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt("curChoice", mCurCheckPosition);
}
Run Code Online (Sandbox Code Playgroud)

您可以在以后使用,如下所示:

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        // Restore last state for checked position.
        mCurCheckPosition = savedInstanceState.getInt("curChoice", 0);
    }
}
Run Code Online (Sandbox Code Playgroud)

我是Fragments的初学者,但它似乎是你的问题的解决方案;)在从后栈返回片段后调用OnActivityCreated.

  • 它不会调用onSaveInstanceState - 为什么会这样?所以,这种方法不起作用. (53认同)
  • 为了记录这种方法是错误的,并且应该没有接近它的票数.只有当相应的活动也在关闭时,才会调用`onSaveInstanceState`. (22认同)
  • 我无法使用此工作savedInstanceState始终为null.我正在通过xml布局添加片段.不得不将mCurCheckPosition更改为静态然后它可以工作,但感觉很烦. (18认同)
  • 当配置发生更改并且活动被破坏时,onSaveInstanceState()被称为onle,这个答案是错误的 (15认同)
  • 如果我们想要从同一个Activity中的另一个片段返回时保留片段状态,这种方法是否真的有效?onSaveInstanceState()仅在Activity onPause/onStop事件上被调用.根据文档:"也像一个活动,你可以使用Bundle保留片段的状态,以防活动的进程被杀死,你需要在重新创建活动时恢复片段状态.你可以保存状态片段的onSaveInstanceState()回调并在onCreate(),onCreateView()或onActivityCreated()期间恢复它." (10认同)

Fyo*_*yok 80

片段的onSaveInstanceState(Bundle outState)永远不会被调用,除非片段的活动调用它本身和连接片段.因此,在某些东西(通常是旋转)强制活动SaveInstanceState并稍后恢复它之前,不会调用此方法.但是如果你里面只有一个活动和大量的碎片(使用密集replace)并且应用程序仅在一个方向上运行onSaveInstanceState(Bundle outState),那么很长一段时间内可能不会调用它.

我知道三种可能的解决方法.

首先:

使用片段的参数来保存重要数据:

public class FragmentA extends Fragment {
    private static final String PERSISTENT_VARIABLE_BUNDLE_KEY = "persistentVariable";

    private EditText persistentVariableEdit;

    public FragmentA() {
        setArguments(new Bundle());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_a, null);

        persistentVariableEdit = (EditText) view.findViewById(R.id.editText);

        TextView proofTextView = (TextView) view.findViewById(R.id.textView);

        Bundle mySavedInstanceState = getArguments();
        String persistentVariable = mySavedInstanceState.getString(PERSISTENT_VARIABLE_BUNDLE_KEY);

        proofTextView.setText(persistentVariable);


        view.findViewById(R.id.btnPushFragmentB).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getFragmentManager()
                        .beginTransaction()
                        .replace(R.id.frameLayout, new FragmentB())
                        .addToBackStack(null)
                        .commit();
            }
        });

        return view;
    }

    @Override
    public void onPause() {
        super.onPause();
        String persistentVariable = persistentVariableEdit.getText().toString();

        getArguments().putString(PERSISTENT_VARIABLE_BUNDLE_KEY, persistentVariable);
    }
}
Run Code Online (Sandbox Code Playgroud)

第二种但不那么迂腐的方式 - 在单身人士中持有变量

第三个 - 不是replace()碎片而是add()/ show()/ hide()它们.

  • 永远不会调用`Fragment.onSaveInstanceState()`时的最佳解决方案.只需将您自己的数据保存到参数中,包括列表视图中的项目或只是它们的ID(如果您有其他集中数据管理器).无需保存列表视图的位置 - 已保存并自动恢复. (3认同)

e_v*_*v_e 21

请注意,如果您使用ViewPager处理Fragments,则非常简单.你只需要调用这个方法:setOffscreenPageLimit().

符合文档:

在空闲状态下设置应保留到视图层次结构中当前页面任一侧的页数.超出此限制的页面将在需要时从适配器重新创建.

Simmilar问题在这里

  • 这是不同的.setOffScreenPageLimit的作用类似于缓存(表示ViewPager在给定时刻必须处理的页数),但不用于保存片段的状态. (4认同)

Lym*_*Zoy 14

只需夸大你的视图一次.

例子如下:

public class AFragment extends Fragment {

private View mRootView;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if(mRootView==null){
        mRootView = inflater.inflate(R.id.fragment_a, container, false);
        //......
    }
    return mRootView;
}
Run Code Online (Sandbox Code Playgroud)

}


rmi*_*lle 8

我处理的问题非常类似于此.因为我知道我经常会回到之前的片段,所以我检查片段是否.isAdded()为真,如果是的话,而不是做一个transaction.replace()我只做一个transaction.show().如果片段已经在堆栈中,这将使片段不被重新创建 - 无需保存状态.

Fragment target = <my fragment>;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
if(target.isAdded()) {
    transaction.show(target);
} else {
    transaction.addToBackStack(button_id + "stack_item");
    transaction.replace(R.id.page_fragment, target);
}
transaction.commit();
Run Code Online (Sandbox Code Playgroud)

要记住的另一件事是,虽然这保留了片段本身的自然顺序,但您可能仍需要处理活动本身被销毁并在方向(配置)更改时重新创建.要在AndroidManifest.xml中为您的节点解决此问题:

android:configChanges="orientation|screenSize"
Run Code Online (Sandbox Code Playgroud)

在Android 3.0及更高版本中,screenSize显然是必需的.

祝好运


小智 5

如果您正在像这样处理 android 清单中指定的片段活动中的配置更改

<activity
    android:name=".courses.posts.EditPostActivity"
    android:configChanges="keyboardHidden|orientation"
    android:screenOrientation="unspecified" />
Run Code Online (Sandbox Code Playgroud)

那么onSaveInstanceState片段的 将不会被调用并且savedInstanceState对象将始终为空。


小智 5

我找到的最佳解决方案如下:

onSavedInstanceState():当活动要关闭时(从一个移动到另一个或配置更改),始终调用内部片段.因此,如果我们在同一个活动上调用多个片段,那么我们必须使用以下方法:

使用片段的OnDestroyView()并将整个对象保存在该方法中.然后OnActivityCreated():检查对象是否为null(因为此方法每次都调用).现在恢复对象的状态.

它的作品永远!

  • 嗨!! @ amanGoel你可以帮我一些示例代码. (2认同)