在旋转时分配正确的 android 片段

Assign the right android fragment on rotate


我最近一直在开发一个小型 Android 应用程序,但我遇到了一个很难解决的错误。

因为我使用的是 BottomNavigationView,所以我必须像这样初始化我的 Home 片段:

@Override
protected void onStart(){
    super.onStart();
    FragmentTransaction f = fm.beginTransaction();
    f.replace(R.id.content, homeFragment).commit();
}

替换发生在这个 FrameLayout 上:

<FrameLayout
    android:id="@+id/content"
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:visibility="visible"
    app:layout_constraintBottom_toTopOf="@+id/navigation"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintVertical_bias="1.0" />

但这会引发一个小错误:如果我旋转设备,片段将设置回我的 homeFragment,而不管当前的片段。
因为我不能直接打电话给我

public boolean onNavigationItemSelected(@NonNull MenuItem item) {
//
}

我尝试了一些转变:

但是这些解决方案并没有带来好运:
最后一个在你转动屏幕和 select home
后崩溃 其他的只是导致与我的标准初始化相同的情况。

您可以执行此操作的一种方法是创建一个变量来存储片段标记,在处理底部导航的开关盒中,您可以在该变量中保存适当的标记。然后实现 onSaveInstanceState 函数并将该标记写入您的外州。最后,监听 onCreate 中保存的实例状态并启动适当的片段。像这样:

String fragmentTag;
String FRAGMENT-TAG-KEY = "fragment-tag";

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

    // recovering the instance state
    if (savedInstanceState != null) {
        String fragmentTag = savedInstanceState.getString("FRAGMENT-TAG-KEY");
        switch (fragmentTag){
            case "FragmentA": {
                //launch this fragment. 
                break;
            }
            case "FragmentB": {
                //launch this fragment. 
                break;
            }
        }
    }
}

@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(FRAGMENT-TAG-KEY, fragmentTag);
    super.onSaveInstanceState(outState);
}


bottomNavigationView.setOnNavigationItemSelectedListener(
    new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.action_home: {
                    fragmentTag = "FragmentA";
                }

                case R.id.action_fragmentb: {
                    fragmentTag = "FragmentA";
                }
            }
            return true;
        }
    });

如果特定片段需要存储数据,您可以将其存储在本地并重新加载。否则,您可能必须将数据发送回 activity,然后将其传递到您的片段中。可能是这样的情况,你可以存储片段的实例并在片段中实现 outstate,然后在片段中的 onActivityCreated 中你可以恢复你的实例状态。我不确定您的其余代码是什么样子,所以我只能推测您可能会如何存储片段的数据(如果有的话)。

只有在用户第一次导航到您的 Activity 时才会导致您的代码 运行 的最简单方法是将您的代码从 onStart() 移动到 onCreate() 并将其包装在 if 语句中,该语句检查 savedInstanceState 是否为空(只有在 activity 第一次启动时才为真)。

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate();
    // the rest of your onCreate() etc...

    if (savedInstanceState == null){
        FragmentTransaction f = fm.beginTransaction();
        f.replace(R.id.content, homeFragment).commit();
    }
}

您可以仅在 activity 第一次启动时将此技术用于您想要 运行 的任何内容,而不仅仅是 FragmentTransactions。虽然片段是这个技巧的一个非常常见的用例。