片段返回栈

3

你好,我有一个活动和三个片段。当我替换第一个片段时,我会将它添加到后退栈中。

FragmentTransaction fragmentTransaction = getFragmentManager()
            .beginTransaction();
fragmentTransaction.replace(R.id.authentication_parent0_linear,
                new LoginFragment(), LOGINTAG);
fragmentTransaction.addToBackStack(null);
    fragmentTransaction.commit();

但是当我在其他两个片段之间移动时,我没有将它们添加到后退堆栈中。因此,每当我从其他两个片段返回时,我需要返回到第一个片段。当我删除第一个片段并添加第二个片段或删除第一个片段并添加第三个片段时,它可以正常工作,即当我按下返回键时,我会回到第一个片段。但是,当我在这两个片段之间导航,即删除第二个并添加第三个或删除第三个并添加第二个等。在那个时刻,当我按下返回键时,我正在退出应用程序,并且后退堆栈计数显示为零,但第一次删除第一个片段时,我将其存储在后退堆栈中。

getFragmentManager()
            .beginTransaction()
            .replace(R.id.authentication_parent0_linear,
                    new SignupFragment(), SIGNUPTAG).commit();

所以我的问题是:在提交之间,片段返回栈是否会重置。如果是这样的话,我该如何在第一次获取存储的片段返回栈?

让我理解一下你想要实现什么。你有碎片 A、B、C。你从碎片 A 开始。从这里开始,你希望在用户经过任何导航路径后,按返回键都会将用户带回碎片 A?例如:A->B->C -> “返回” -> A。另一个例子:A->B->返回->A,等等。 - Kirill K
这正是我想要的。我以为我已经做到了,因为我只将片段A存储在后退栈中。我尝试了很多事情,但最终放弃了,只剩下通过片段A导航到片段B和C,而没有直接在B和C之间导航。如果我这样做,一切都能正常工作。 - krishna
4个回答

0

实现您想要的最好方法不是使用片段的返回堆栈。

  1. 请勿在任何地方使用 addToBackStack()
  2. 将您的第一个片段 LoginFragment 引用存储在实例字段 mLoginFragment 中。添加第一个片段将如下所示(可能在活动的 onCreate() 中):

      FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
      mLoginFragment = new LoginFragment();
      fragmentTransaction.replace(R.id.authentication_parent0_linear, mLoginFragment, LOGINTAG);
      fragmentTransaction.commit();
    
  3. 在您的活动中覆盖 onBackPressed() 方法,如下所示:

    @Override
    public void onBackPressed() {
        Fragment fr = getFragmentManager().findFragmentById(R.id.authentication_parent0_linear);
    
        // 检查 mLoginFragment!=null,基本上这不应该发生!
    
        if (fr == mLoginFragment) {
            super.onBackPressed();
        } else {
            FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
          fragmentTransaction.replace(R.id.authentication_parent0_linear, mLoginFragment, LOGINTAG);
          fragmentTransaction.commit();
        }
    }
    

通过使用backstack的方式可以实现所需的效果,但这种方法相对繁琐。以下是具体步骤:

1. 创建A片段时,不要调用addToBackStack() 2. 从片段A导航到B、C或其他片段时,调用addToBackStack() 3. 当从B导航到C等更深层次时,在事务之前调用popBackStack()。其解释可在SO上找到。像这样:
getFragmentManager().popBackStack();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.authentication_parent0_linear, new FragmentC(), "whatever");
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();

谢谢Kirill,我会尝试你的解决方案。 - krishna

0

片段管理器允许您在给定状态上放置名称(或标签)。如果您将相同的名称传递给popBackStack,则它将弹出状态,直到达到该状态。例如

// Add initial fragment
getFragmentManager()
    .beginTransaction();
    .replace(R.id.authentication_parent0_linear, new LoginFragment());
    .addToBackStack(TAG_FIRST_FRAGMENT_STATE) // The key is not passing null here
    .commit();

// Add other fragments like such
getFragmentManager()
    .beginTransaction();
    .replace(R.id.authentication_parent0_linear, new SignupFragment());
    .addToBackStack(null)
    .commit();


// On back press
@Override
public void onBackPressed() {
    FragmentManager fragmentManager = getFragmentManager();
    if (fragmentManager.getBackStackEntryCount() > 1) {
        fragmentManager.popBackStack(TAG_FIRST_FRAGMENT_STATE, 0);
    } else {
        super.onBackPress();
    }
}

谢谢cyroxis,我也会尝试这个。 - krishna

0

我终于搞明白了,基于Kirill K的回答

    public class MainActivity extends Activity implements OnClickAuthentication,
    LoginInterface, SignupInterface {

FragmentManager fragmentManager;
FragmentTransaction fragmentTransaction;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    fragmentManager = getFragmentManager();
    Fragment fragment = fragmentManager.findFragmentByTag("one");
    if (fragment == null) {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction
                .replace(R.id.relative, new OneFragment(), "one");
        fragmentTransaction.commit();
    }
}

@Override
public void onClickAuthButton(int flag) {
    if (flag == 2) {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction
                .replace(R.id.relative, new TwoFragment(), "two");
        fragmentTransaction.commit();
    } else {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.replace(R.id.relative, new ThreeFragment(),
                "three");
        fragmentTransaction.commit();

    }

}

@Override
public void switchToSignup() {
    fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction
            .replace(R.id.relative, new ThreeFragment(), "three");
    fragmentTransaction.commit();

}

@Override
public void switchToLogin() {
    fragmentTransaction = fragmentManager.beginTransaction();
    fragmentTransaction.replace(R.id.relative, new TwoFragment(), "two");
    fragmentTransaction.commit();

}

@Override
public void onBackPressed() {
    Fragment twoFragment = fragmentManager.findFragmentByTag("two");
    Fragment threeFragment = fragmentManager.findFragmentByTag("three");
    if ((twoFragment != null && twoFragment.isVisible())
            || (threeFragment != null && threeFragment.isVisible())) {
        fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction
                .replace(R.id.relative, new OneFragment(), "one");
        fragmentTransaction.commit();
    } else {
        super.onBackPressed();
    }
}

}


0

我是这样做的

1. 全局声明fragmentManager变量:

FragmentManager fm = getFragmentManager();

2. 在onCreate方法中加载第一个fragment,不使用backstack

fm.beginTransaction().replace(R.id.content_frame , new main_fragment()).commit();

3. 现在当你添加新的fragment时,创建一个方法来检查该fragment是否已经在backstack中,同时它还将处理点击相同fragment的事件(如果你正在使用导航抽屉中的fragment)

void replaceFragment (Fragment fragment) {
    Fragment current = fm.findFragmentById(R.id.content_frame);
    //Check if that frag is already opened
    if (!current.getClass().equals(fragment.getClass())) {


        String backStateName = fragment.getClass().getName();

        boolean fragmentPopped = fm.popBackStackImmediate(backStateName, 0);

        if (!fragmentPopped) {

            //fragment is not in back stack,so add it.
            FragmentTransaction ft = fm.beginTransaction();
            ft.replace(R.id.content_frame, fragment);
            ft.addToBackStack(backStateName);
            ft.commit();

        }
    }
    else {
        //if fragmentPopped is true then it will auto pop up the fragment
        //so we dnt have to do anything here     
    }
}

4. 现在只需将您的碎片类传递给

replaceFragment(new yourfragment());

5. 现在处理后退键

public void onBackPressed() {

    int backStackEntryCount = fm.getBackStackEntryCount();


       if (backStackEntryCount == 0) {
            new AlertDialog.Builder(this)
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .setTitle("Closing Activity")
                    .setMessage("Are you sure you want to close this Application?")
                    .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            finish();
                            System.exit(0);
                        }

                    })
                    .setNegativeButton("No", null)
                    .setOnCancelListener(new DialogInterface.OnCancelListener() {
                        @Override
                        public void onCancel(DialogInterface dialogInterface) {
                               //backpress over alert dialog
                                finish();
                                System.exit(0);
                        }
                    })
                    .show();

        } else {


            super.onBackPressed();
        }


    }

希望这能对你有所帮助


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接