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