如何使用事务回栈来弹出片段?

Posted

技术标签:

【中文标题】如何使用事务回栈来弹出片段?【英文标题】:How can I use the transaction backstack to pop fragments? 【发布时间】:2021-08-17 01:12:51 【问题描述】:

假设我有一个带有 FragmentContainerView 的 MainActivity。 这个 FragmentContainerView 的大小与 MainActivity 匹配。

然后我想在这个 FragmentContainerView 中一次显示一个片段。

Fragment1、Fragment2 和 Fragment3。

每个片段都有一个按钮。按下按钮时,将加载下一个片段。

Fragment1 (Press button)--> Fragment2 (Press button)--> Fragment3 (Press button)--> Fragment1 --> 以此类推。

到目前为止,我能够实现,但我不确定如何制作我的片段,以便当我按下后退按钮时,

Fragment1 应该退出应用程序

Fragment2 应该加载 Fragment1

Fragment3 应该加载 Fragment2

这是我的MainActivity

    public class MainActivity extends AppCompatActivity 

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FirstFragment fragment = new FirstFragment();
        Bundle bundle = new Bundle();
        bundle.putString("CLASS_NAME", " ");
        fragment.setArguments(bundle);
        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container_view, fragment, null)
                .commit();
    

这是我的Fragment1

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
        super.onViewCreated(view, savedInstanceState);

       
        binding = FragmentFirstBinding.bind(getView());


        String previous_class = getArguments().getString("CLASS_NAME");
        if(!previous_class.equals(" "))
            binding.textViewFirstFragment.setText(previous_class);
        

        //On button click, navigate to MainActivity
        binding.buttonFirstFragment.setOnClickListener(this);
    

@Override
    public void onClick(View v) 
        //Log.i("BACKSTACK", "debug: current status of fragment back stack " + getFragmentManager().getBackStackEntryCount());
        Fragment fragment = new SecondFragment();
        putBundleArgument(fragment);
        replaceFragment(fragment);
        debug();
    

    public void replaceFragment(Fragment fragment) 
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.fragment_container_view, fragment);
        transaction.addToBackStack(null);
        transaction.commit();
    

这是我的Fragment2

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);

   
    binding = FragmentSecondBinding.bind(getView());

    String previous_class = getArguments().getString("CLASS_NAME");
    binding.textViewSecondFragment.setText(previous_class);
    //On button click, navigate to MainActivity
    binding.buttonSecondFragment.setOnClickListener(this);


@Override
public void onClick(View v) 
    //Log.i("BACKSTACK", "debug: current status of fragment back stack " + getFragmentManager().getBackStackEntryCount());
    Fragment fragment = new ThirdFragment();
    putBundleArgument(fragment);
    replaceFragment(fragment);
    debug();


public void replaceFragment(Fragment fragment) 
    FragmentTransaction transaction = getFragmentManager().beginTransaction();
    transaction.replace(R.id.fragment_container_view, fragment);
    transaction.addToBackStack(null);
    transaction.commit();

最后,这是我的Fragment3

 @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) 
    super.onViewCreated(view, savedInstanceState);
    
    binding = FragmentThirdBinding.bind(getView());

    String previous_class = getArguments().getString("CLASS_NAME");
    binding.textViewThirdFragment.setText(previous_class);
    //On button click, navigate to MainActivity
    binding.buttonThirdFragment.setOnClickListener(this);


@Override
public void onClick(View v) 

    Fragment fragment = new FirstFragment();
    putBundleArgument(fragment);
    replaceFragment(fragment);
    debug();


public void replaceFragment(Fragment fragment) 
    FragmentTransaction transaction = getFragmentManager().beginTransaction();

    /*
    ThirdFragment fragment3 = new ThirdFragment();
    transaction.remove(fragment3);
    SecondFragment fragment2 = new SecondFragment();
    transaction.remove(fragment2);
    */
    getFragmentManager().popBackStack();
    getFragmentManager().popBackStack();
    getFragmentManager().popBackStack();


    transaction.replace(R.id.fragment_container_view, fragment);
    transaction.addToBackStack(null);
    transaction.commit();


【问题讨论】:

那么你的代码中的哪一步出错了?是你第一次使用 FragmentOne 的时候吗?在去 FragmentTwo 并尝试回到 One 之后?去 FragmentThree 之后又回到 FragmentThree 之后?还是回到一号之后?请具体。 【参考方案1】:
 @Override // override this in MainActivity
 public void onBackPressed()
     int count = getSupportFragmentManager().getBackStackEntryCount();
     if(count == 1)//When there is only 1 fragment left in the stack ie Fragment 1.
        finsh();
     else
        getSupportFragmentManager().popBackStack(); //Fragment 2 and 3 are popped here.
     super.onBackPressed();  
 

【讨论】:

这是 Fragments 在您使用 addToBackStack() 时已经为您做的事情。手动执行此操作绝对是 100% 错误的做法,并且无法处理嵌套片段和custom back handling。 @ianhanniballake 我 100% 同意这将导致未来的问题,但这个解决方案源于他们现有的代码库。任何时候我提供的解决方案都不能解决问题,但会导致设计本身没有它,我被否决了。从外观上看,它对提问者有用。我没有发布的原始答案完全取消了链接片段的创建,这将导致更易于维护的控制结构。 我认为这无论如何都行不通 - 在 FragmentThree 时,这将弹出返回堆栈(带你到 Two)并调用 super.onBackPressed() 这也会弹出片段返回堆栈(带你to One),这不是你想要的。

以上是关于如何使用事务回栈来弹出片段?的主要内容,如果未能解决你的问题,请参考以下文章

DialogFragment dismiss() 不弹出回栈

使用片段清除回栈

片段回栈和替换

导航组件 NavDeepLinkBuilder 回栈

Android导航组件回栈

如何控制Android回栈