简体   繁体   English

片段Backstack

[英]Fragment Backstack

Hi I have an activity and three fragments. 嗨,我有一个活动和三个片段。 When I replace my first fragment I am adding it to backstack. 当我替换我的第一个片段时,我将它添加到backstack中。

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

But when I move between the other two fragments I am not adding them to backstack.So whenever I press back from the other two fragments I need to go back to first fragment.It works fine when I remove first fragment and add second fragment or remove first and add third ie when I press back I am coming back to first fragment. 但是当我在另外两个片段之间移动时,我没有将它们添加到backstack中。所以每当我从其他两个片段按回来时,我需要回到第一个片段。当我删除第一个片段并添加第二个片段或删除时它工作正常首先添加第三个,即当我按下时,我将回到第一个片段。 But when I navigate between those two fragments that is remove second and add third or remove third and add second etc . 但是当我在这两个片段之间导航时,会删除第二个并添加第三个或删除第三个并添加第二个等。 At that instance when I press back I am exiting the app and backstackcount is shown as zero but for the first time when I removed the first fragment I stored it in the backstack. 在那个例子,当我按下我退出应用程序并且backstackcount显示为零但是我第一次删除第一个片段时将其存储在backstack中。

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

So my question is will the fragment backstack resets between commits. 所以我的问题是片段backstack会在提交之间重置。 If so how can I get the stored fragment in the backstack for the first time 如果是这样,我怎样才能第一次在后台堆叠中获取存储的片段

Best way to achieve what you want is not to use fragment's backstack. 实现你想要的最好方法是不使用fragment的backstack。

  1. Do not use addToBackStack() anywhere 不要在任何地方使用addToBackStack()
  2. Keep your first fragment LoginFragment reference in the instance field mLoginFragment. 在实例字段mLoginFragment中保留第一个片段LoginFragment引用。 Addition of your first fragment will look like this (probably in activity's onCreate() : 添加第一个片段将如下所示(可能在activity的onCreate()

      FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); mLoginFragment = new LoginFragment(); fragmentTransaction.replace(R.id.authentication_parent0_linear, mLoginFragment, LOGINTAG); fragmentTransaction.commit(); 
  3. in your activity override onBackPressed() method as following: 在您的活动中重写onBackPressed()方法如下:

     @Override public void onBackPressed() { Fragment fr = getFragmentManager().findFragmentById(R.id.authentication_parent0_linear); // chek that mLoginFragment!=null, basically this should never happen! if (fr == mLoginFragment) { super.onBackPressed(); } else { FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.authentication_parent0_linear, mLoginFragment, LOGINTAG); fragmentTransaction.commit(); } } 

There is a cumbersome way to achieve the desired effect with the use of backstack. 使用背板可以通过一种麻烦的方式来达到预期的效果。 Here is how: 方法如下:

  1. do not call addToBAckStack() when creating fragment A 创建片段A时不要调用addToBAckStack()
  2. When navigating from fragment A to B or to C, or to other fragments call addToBackStack() 从片段A导航到B或C或其他片段时, 调用 addToBackStack()
  3. When navigating deeper from B to C, etc. call popBackStack() before the transaction. 当从B更深地导航到C等时,在事务之前调用popBackStack() Explanation of it can be found on SO. 可以在SO上找到它的说明。 Like this: 像这样:

     getFragmentManager().popBackStack(); FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.authentication_parent0_linear, new FragmentC(), "whatever"); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); 

The Fragment manager allows you to put a Name (or TAG) on a given state. 片段管理器允许您将名称(或TAG)放在给定状态。 If you pass that same name to popBackStack it will pop states until it reaches that state. 如果将相同的名称传递给popBackStack,它将弹出状态直到达到该状态。 For example 例如

// 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();
    }
}

I fnally figured it out. 我最终想通了。 based on Kirill K answer 基于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();
    }
}

} }

I have done it like this 我这样做了

1. Globally declare fragmentManager variable : 1.全局声明fragmentManager变量:

FragmentManager fm = getFragmentManager();

2.onCreate method load your 1st fragment without using backstack 2.onCreate方法在不使用backstack的情况下加载第一个片段

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

3. now when you will add new fragment then create a method which will check if the fragment is already in backstack or not and also it will handle clicking the same fragment events(if you are using frag in navigation drawer ) 3.现在当你要添加新的片段然后创建一个方法,它将检查片段是否已经在backstack中,并且它还将处理单击相同的片段事件(如果你在导航抽屉中使用frag)

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. now just pass your fragment class to 4.现在只需将你的片段类传递给

replaceFragment(new yourfragment());

5. now handle backpress 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();
        }


    }

hope this will help you 希望这个能对您有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM