Demo记录Fragment 返回栈

Posted 彼岸花you

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Demo记录Fragment 返回栈相关的知识,希望对你有一定的参考价值。

效果


toast打印的是返回之前显示的fragment的标记
点击返回键时,不会直接退出activity,而是返回到之前显示的Fragment(当前显示的是首页时,直接退出Activity)


Fragment 知识点

1、Fragment和Activity关联的主要方式在于:添加、替换

通过Activity中Fragment的管理器,将Fragment添加到Activity指定的布局中,每一次添加Fragment都会在原界面的基础上添加Fragment,可以理解为在原Fragment的基础上又覆盖了一层,如果Fragment之间背景透明,可以看到各个添加的Fragment内容重叠,所以,一般在第一个将Fragment显示到界面上时使用addFragment方式,要改变Fragment的内容,则通过replaceFragment来进行。替换的方式,不会出现内容重叠的情况。

2、Fragment 返回栈

Fragment 依附于Activity来做内容的显示,当在Activity中点击返回按钮时,这个Activity将会销毁。想点击返回实现Fragment的返回,而不是直接退出Activity,则需要使用到返回栈。

返回栈的相关操作:入栈、出栈、获取返回栈里的个数

入栈:addToBackStack(@Nullable String name);
示例代码:

FragmentManager mSupportFragmentManager = getSupportFragmentManager();
mSupportFragmentManager.beginTransaction()
        .replace(R.id.frameLayout_content, fragments[0], "first")
        .addToBackStack("first")
        .commit();

出栈

popBackStack();//将返回栈里面的栈顶元素pop出栈
popBackStack(String name,int flags);//将标记为name之上的元素全部移除,flags表示标记为name的这个元素是否需要出栈,0表示不需要,POP_BACK_STACK_INCLUSIVE表示该元素需要出栈。
popBackStack(int id,int flags);//将栈里面位置在id上面的元素都移除,根据flags来判断是否移除该位置的元素。
popBackStackImmediate();//和上面相比,只是多了个Immediate 表示立即执行,其余的参数 则和上面一致。
popBackStackImmediate(String name,int flags);
popBackStackImmediate(int id,int flags);

获取返回栈中元素的个数
getBackStackEntryCount();

期间遇到的问题:在onCreate中执行获取的个数一直为0,解决方案:
在获取个数之前 使用executePendingTransitions();

最后还有一种获取元素个数有问题的操作,在onPressBack中进行的操作,详情 直接跳到文章末尾。

解决方案参考自:
http://stackoverflow.com/questions/13964409/why-fragmentmanagers-getbackstackentrycount-return-zero


Demo

界面设计:

Activity Layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.tjstudy.radiogrouptab.MainActivity">

    <FrameLayout
        android:id="@+id/frameLayout_content"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <RadioGroup
        android:id="@+id/radioGroup_tabs"
        android:layout_width="match_parent"
        android:layout_height="?android:actionBarSize"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/tab1"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@drawable/selector_tabs"
            android:button="@null"
            android:gravity="center"
            android:text="第一个界面" />

        <RadioButton
            android:id="@+id/tab2"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:button="@null"
            android:gravity="center"
            android:background="@drawable/selector_tabs"
            android:text="第二个界面" />

        <RadioButton
            android:id="@+id/tab3"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@drawable/selector_tabs"
            android:layout_weight="1"
            android:button="@null"
            android:gravity="center"
            android:text="第三个界面" />
    </RadioGroup>
</LinearLayout>

其中涉及到 selector_tabs 是选择器
背景颜色选择器

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true">
        <color android:color="#cc0000" />
    </item>
    <item>
        <color android:color="#00cc00" />
    </item>
</selector>

选择器相关:
http://blog.csdn.net/u012391876/article/details/52243797

三个Fragment准备,没有进行其他操作,界面指显示了一个TextView 显示是第几页 第一个Fragment 参考代码

/**
 * 第一个界面 tab1
 */
public class FirstFragment extends Fragment 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) 
        return inflater.inflate(R.layout.fragment_first, container, false);
    
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tjstudy.radiogrouptab.fragment.FirstFragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="第一个界面" />

</FrameLayout>

其他两个Fragment的代码和这个类似-略

重点:Activity的操作
1、 界面默认显示第一页,addFragment1
2、 点击tab的时候,replaceFragment
3、 点击返回键的处理,回退到首页-默认的第一页,当前页已经是首页的情况下,直接结束这个activity。

package com.tjstudy.radiogrouptab;

public class MainActivity extends AppCompatActivity implements View.OnClickListener 
    private RadioButton tab1;
    private RadioButton tab2;
    private RadioButton tab3;
    private FragmentManager mSupportFragmentManager;
    private Fragment[] fragments;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initListener();
    

    private void initListener() 
        tab1.setOnClickListener(this);
        tab2.setOnClickListener(this);
        tab3.setOnClickListener(this);
    

    private void initView() 
        tab1 = (RadioButton) findViewById(R.id.tab1);
        tab2 = (RadioButton) findViewById(R.id.tab2);
        tab3 = (RadioButton) findViewById(R.id.tab3);

        //初始化界面
        mSupportFragmentManager = getSupportFragmentManager();
        fragments = new Fragment[]new FirstFragment(), new SecondFragment(), new ThirdFragment();
        mSupportFragmentManager.beginTransaction()
                .add(R.id.frameLayout_content, fragments[0], "first")
//        第一个不添加到栈里面 添加到栈之后 点击返回按钮时,会将fragment出栈 这里出栈之后界面就变成空白的了
//                .addToBackStack("first")
                .commit();
        tab1.setChecked(true);
    

    @Override
    public void onClick(View v) 
        int id = v.getId();
        switch (id) 
            case R.id.tab1:
                mSupportFragmentManager.beginTransaction()
                        .replace(R.id.frameLayout_content, fragments[0], "first")
                        .addToBackStack("first")//添加到返回栈
                        .commit();
                break;
            case R.id.tab2:
                mSupportFragmentManager.beginTransaction()
                        .replace(R.id.frameLayout_content, fragments[1], "second")
                        .addToBackStack("second")
                        .commit();
                break;
            case R.id.tab3:
                mSupportFragmentManager.beginTransaction()
                        .replace(R.id.frameLayout_content, fragments[2], "third")
                        .addToBackStack("third")
                        .commit();
                break;
        
    

    @Override
    public void onBackPressed() 
        //需要判断当前界面是不是 就是默认的界面
        int backStackEntryCount = mSupportFragmentManager.getBackStackEntryCount();
        Toast.makeText(this, "backStackEntryCount:" + backStackEntryCount, Toast.LENGTH_SHORT).show();
        if (backStackEntryCount > 0) 
            //1、获取返回栈 栈顶元素的标记
            String name = mSupportFragmentManager.getBackStackEntryAt(backStackEntryCount - 1).getName();
            Toast.makeText(this, name, Toast.LENGTH_SHORT).show();
            //2、判断栈顶元素是不是默认界面
            Toast.makeText(this, "getTag().name:" + fragments[0].getTag().equalsIgnoreCase(name), Toast.LENGTH_SHORT).show();
            if (fragments[0].getTag().equalsIgnoreCase(name)) 
                //2.1 是默认界面则 直接退出activity
                finish();
             else 
    //将栈里面的元素全部回退
//        while (mSupportFragmentManager.getBackStackEntryCount() > 0) 
//            mSupportFragmentManager.popBackStackImmediate();
//        
                //2.2 不是默认界面,则将返回栈中的元素全部出栈--由于第一个界面没有添加到栈 显示的则是第一个界面
                mSupportFragmentManager.popBackStackImmediate(0, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            
            tab1.setChecked(true);
         else 
            finish();
        
    

为什么在第一次操作添加Fragment到界面上时,不将其添加到返回栈中?
Fragment被添加到返回栈中,点击返回键时,会先执行将Fragment从返回栈中移除的操作,第一次添加Fragment时,将该Fragment添加到返回栈中,此时点返回键时,Fragment被移除,此时界面Fragment区域就变成一片空白了。

获取返回栈中元素个数遇到的问题
在onBackPress中,获取返回栈元素个数 不是预期的值(比预期值少1),没有达到预期效果。解决方案参考上面提供的网址。
super.onPress();影响了相关代码的执行,获取返回栈的个数和进行出栈操作在super.onPress之前执行,由于将super.onPress放到后面,activity会直接退出,这里没有使用super.onPress方法,而是改用finish直接结束activity.


Demo源码

http://download.csdn.net/detail/u012391876/9729927

以上是关于Demo记录Fragment 返回栈的主要内容,如果未能解决你的问题,请参考以下文章

Android Gems — Fragment本质之返回栈和事务管理

Fragment全解析系列:Fragment之我的解决方案:Fragmentation

android多个fragment返回键层层返回

返回 Activity / Fragment 历史记录时的 Android Back Button 行为

Android第四天

Android中Fragment装载WebView 返回键设置问题