Android 如何避免FragmentManager重新创建片段?

Android 如何避免FragmentManager重新创建片段?,android,android-fragments,android-lifecycle,Android,Android Fragments,Android Lifecycle,我正在进行一项活动,其中包含TabLayout和两个表示选项卡内容的片段。 我在活动的OnCreate方法中手动管理打开选项卡的当前状态: import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fr

我正在进行一项活动,其中包含TabLayout和两个表示选项卡内容的片段。 我在活动的OnCreate方法中手动管理打开选项卡的当前状态:

import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;

import com.google.android.material.tabs.TabLayout;

public class LoginActivity extends AppCompatActivity {

    private TabLayout tabLayout;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        tabLayout = findViewById(R.id.tabLayout);

        //initialize or restore opened tab, after activity first started or recreated
        int tabIndex = savedInstanceState == null ? 0 : savedInstanceState.getInt("tabIndex");
        Fragment f;
        switch (tabIndex) {
            case 0:
                f = new SignInFragment();
                break;
            case 1:
                f = new SignUpFragment();
                break;
            default:
                throw new UnsupportedOperationException();
        }
        //sync tab indicator
        tabLayout.selectTab(tabLayout.getTabAt(tabIndex));
        //set opened fragment
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.tabContent, f)
                .commit();

        //add listener to handle tab switching
        tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                Fragment tabFragment;
                switch (tab.getPosition()) {
                    case 0:
                        tabFragment = new SignInFragment();
                        break;
                    case 1:
                        tabFragment = new SignUpFragment();
                        break;
                    default:
                        throw new UnsupportedOperationException();
                }
                getSupportFragmentManager().beginTransaction()
                        .setCustomAnimations(com.google.android.material.R.anim.abc_grow_fade_in_from_bottom, com.google.android.material.R.anim.abc_shrink_fade_out_from_bottom)
                        .replace(R.id.tabContent, tabFragment)
                        .commit();
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("tabIndex", tabLayout.getTabAt(tabLayout.getSelectedTabPosition()).getPosition());
    }
}
这只是一个简单的例子。我真正的代码是用C#编写的,并且有一些其他逻辑来存储和管理活动重启之间的状态

配置更改时出现的问题(例如开关方向):

  • 打开的碎片被摧毁
  • 活动被破坏
  • 活动重新启动
  • 在onCreate方法中,当调用super.onCreate(savedInstanceState)片段管理器时,使用默认(无参数)构造函数重新创建片段(在步骤1中销毁)
  • 我的代码在onCreate方法中还原被破坏的片段。所以,碎片管理器重新创建的碎片被销毁并替换为我在这一步中创建的碎片
  • 如何避免这种行为?片段管理器还原的片段中不需要我。另外,我不需要片段的默认构造函数(我有一些自定义ViewModel,通过托管活动的构造函数注入到片段中)

    是否将null设置为super.onCreate()?我认为这不是一个好的解决方案


    另外,我知道ViewPager和ViewPager2用于管理表格布局的选项卡。不推荐使用ViewPager。对于ViewPager2,我有一个奇怪的错误:第一个选项卡(索引为0)工作正常,但在第二个选项卡中,我无法将注意力集中在任何输入上(单击输入并将焦点自动丢失,不知道原因)。

    对片段使用全局变量首先创建片段,然后随时替换它们,例如:

    private Fragment signInFragment = new SignInFragment();
    private Fragment signUpFragment = new SignUpFragment();
    int tabIndex = savedInstanceState == null ? 0 : 
    savedInstanceState.getInt("tabIndex");
        Fragment f;
        switch (tabIndex) {
            case 0:
                f = signInFragment
                break;
            case 1:
                f = signUpFragment
                break;
            default:
                throw new UnsupportedOperationException();
        }
    

    为什么?我想你不明白这个问题。我知道如何在选项卡切换之间存储片段实例。这不是问题。问题在于当配置更改(例如方向更改)时,托管活动的片段管理器存储打开片段的类型(而不是实例)。当重新创建活动时,调用super.onCreate()时,fm将尝试自动重新创建存储的片段(使用默认片段构造函数)。我想避免这种情况,因为我手动重新创建框架并使用非默认构造函数。我建议在其中使用viewModel和savedInstanceState。因此,您可以在viewModel中存储所有设置或任何您想要的内容。你也可以使用导航组件,它更容易解决你的问题。是的,我可以。即使我重写代码,在片段中只使用默认构造函数,也不能解决问题。片段被重新创建两次。第一个片段在调用base/parent super.onCreate of activity时由FragmentManager自动重新创建,第二个片段在初始化选项卡切换逻辑时由我的代码重新创建。我发现只有一种方法可以避免这种行为——将null设置为super.onCreate调用。这不是一个表格布局的问题。这是连接到活动的任何片段的问题-片段管理器在活动重新启动时自动保存/恢复片段。另一个好的、方便的方法是在重新启动活动后或在片段重新创建时清除片段堆栈。这不起作用。您始终需要使用FragmentManager来开始添加、替换或删除片段。