在android开发中,在一个activity中添加几个fragment是很常见的,这里介绍两种实现方式
- 使用ViewPager+Fragment简单实现页面的切换
- 通过使用FragmentTransaction动态显示或隐藏Fragment
一、ViewPager+Fragment
//自定义一个Adapter,继承FragmentPagerAdapter
public class TestPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public TestPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
if (fragments != null && fragments.size() > 0) {
return fragments.size();
}
return 0;
}
}
//在activity中初始化ViewPager 以及设置Adapter
ViewPager viewPager=findViewById(R.id.viewPager);
//设置预加载页面
viewPager.setOffscreenPageLimit(2);
//fragmentList为Fragment集合
TestPagerAdapter adapter=new TestPagerAdapter(getSupportFragmentManager(),fragmentList);
viewPager.setAdapter(adapter);
使用 FragmentPagerAdapter 时,ViewPager 中的所有 Fragment 实例常驻内存,当 Fragment 变得不可见时仅仅是视图结构的销毁,即调用了 onDestroyView 方法。由于 FragmentPagerAdapter 内存消耗较大,所以适合少量静态页面的场景。
使用 FragmentStatePagerAdapter 时,当 Fragment 变得不可见,不仅视图层次销毁,实例也被销毁,即调用了 onDestroyView 、onDestroy和 onDetach方法,仅仅保存 Fragment 状态。
相比而言, FragmentStatePagerAdapter 内存占用较小,所以适合大量动态页面,比如我们常见的新闻列表类应用
二、FragmentTransaction+Fragment
//activity布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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.yuong.demo.FragmentTestActivity">
<FrameLayout
android:id="@+id/layout_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/fragment_menu" />
</RelativeLayout>
//新建一个Fragment
public class TestFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_test, null);
}
}
//在activity中
TestFragment testFragment= new TestFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!testFragment.isAdded()) {
transaction.add(R.id.layout_container, testFragment);
transaction.commit();
//.addToBackStack(null);
}
FragmentTransaction的add()、hide()、show()、replace方法
add():向Activity加入一个片段,这个片段在activity容器中有他自己的视图。
hide():隐藏已经存在的Fragment,但是仅仅对已经添加到父容器中的Fragment有关,隐藏Fragment
的View
show():显示一个以前被隐藏的Fragment,这仅仅对已经添加到activity中的Fragment有关,显示
Fragment的View
detach():Fragment的视图被销毁,但是它的状态没有被销毁,还是被fragment manager管理
attach():Fragment中的view重新加到UI视图中并显示,Fragment的生命周期如下:
onCreateView()→onActivityCreate()→onStart()→onResume()
replace():就相当于执行remove(Fragment)→add(int, Fragment, String)这两个方法
三、在切换Fragment时,Faragment的生命周期变化
ViewPager中Fragment生命周期变化
- ViewPager中的setOffscreenPageLimit( limit)方法影响Fragement的生命周期,n默认等于1(即预加载下一个页面)。
- ViewPager中Fragment集合中,比如当前的显示Fragment(fragmentA)在其集合中的下标为m,某个特定的Fragment(fragmentB)在其集合中的下标为n
a. 当 n - m 的绝对值小于等于limit且大于 0 时
(1)如果fragmentB的view没有加载到UI视图中,fragmentB的生命周期:onAttach()→onResume()
(2)如果fragmentB的view已加载到UI视图中,则fragmentB的生命周期没有变化,可能会执行以下方法:
//setUserVisibleHint 在onAttach()前执行的
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
Log.e(TAG, "setUserVisibleHint()-----> "+isVisibleToUser);
if (isVisibleToUser) {
//当前的Fragment用户可见
} else {
//当前的Fragment用户不可见
}
}
b. 当 n - m 的小于等于 0 时即当前显示的fragmentA,一定会执行setUserVisibleHint()方法
c. 当 n - m 的绝对值大于 limi t时,如果fragmentB的view已加载到UI视图中,则fragmentB的生命周期没有变化,可能会执行以下方法:onPause()→onDestroyView()
3. 使用 FragmentStatePagerAdapter 时,当 Fragment 变得不可见,不仅视图层次销毁,实例也被销毁,即onPause()→onDetach()
使用FragmentTransaction时Fragment的生命周期变化
在activity中FragmentTransaction中对Fragment的操作大致可以分为两类:
一、显示操作:add()、 replace()、 show()、 attach()
二、隐藏操作:remove() 、hide() 、detach()
(1)add() 、replace()
当使用add() 方法在activity中添加Fragment时,Fragment的生命周期如下:
onAttach()→onResume()
//只要调用add()方法,就会调用一下方法
onAttach()
onCreate()
onCreateView()
onViewCreated()
onActivityCreated()
onStart()
onResume()
退出Activty时,每个Fragment生命周期中的onPause() - ->onDetach()也会被各调用一次。
//退出Activty时,Fragment的生命周期
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
当使用replace()来添加Fragment的时,将要添加到Activity中的Fragment会先把目前的显示的Fragment(在不使用回退栈的情况下)销毁,然后添加到加到Activity中,生命变化如下:
//目前的Fragment销毁,生命周期如下:
onResume()
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()
//将要添加的Fragment,生命周期如下:
onAttach
onCreate
onCreateView
onViewCreated
onActivityCreated
onStart
onResume
(2)show() hide()
调用show() & hide()方法时,Fragment的正常生命周期方法并不会被执行,仅仅
是Fragment的View被显示或者隐藏,并视情况调用onHiddenChanged()。尽管
Fragment的View被隐藏,但它在父布局中并未被detach,仍然是作为
containerView的childView存在着
//只有Fragment显示或者隐藏改变时,才会调用此方法
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
if (hidden) {
// 不在最前端显示 相当于调用了onPause()
}else{
// 在最前端显示 相当于调用了onResume()
}
}
(3)attach() detach()
当调用attach() 和detach()方法时 ,一旦一个Fragment被detach(),它的
onPause()-onDestroyView()周期都会被执行,Fragment的View也会被 detach
,但是不会执行onDestroy()和onDetach(),也就是说Fragment的实例还在内存
中的,在重新调用attach()后,onCreateView()-onResume()周期也会被再次执行
// 调用detach()
onPause()
onStop()
onDestroyView()
//重新调用attach()
onCreateView
onViewCreated
onActivityCreated
onStart
onResume
(4)remove()
当调用remove方法时 ,Fragment的生命周期:onPause()-onDetach()
onPause()
onStop()
onDestroyView()
onDestroy()
onDetach()