在android开发中,在一个activity中添加几个fragment是很常见的,这里介绍两种实现方式
  1. 使用ViewPager+Fragment简单实现页面的切换
  2. 通过使用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生命周期变化
  1. ViewPager中的setOffscreenPageLimit( limit)方法影响Fragement的生命周期,n默认等于1(即预加载下一个页面)。
  2. 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()