1.Fragment 是什么?
Fragment 是 Android 自 3.0 版本开始引入的一种可以嵌入在 Activity 当中的UI片段,主要是为了能在不同分辩率屏幕上进行更为动态和灵活的UI设计,让程序更加合理和充分利用大屏幕空间。
2.Fragment 为什么被称为第五大组件
- 使用频率高;
- 有自己的生命周期;
- 可以灵活加载到Activity中;
- 虽然有自己的生命周期,并不像 Activity 那样独立的,需要依附 Activity。
3.Fragment 加载到 Activity 的两种方式
- 静态加载:作为XML标签添加到 Activity 的布局文件当中。
步骤1:新建fragment.xml文件
步骤2:在Fragment中,重写onCreateView方法,为Fragment设置xml布局文件,转换成view对象返回。
//传递三个参数:
//LayoutInflater inflater表示布局填充器或者加载器,将xml文件转换成view对象。
//ViewGroup container表示fragment插入activity的布局视图对象。
//Bundle saveInstanceState表示存储上一个fragment的信息。
View view = inflater.inflate(R.layout.fragment,container,false);
return view;
步骤3:在activity布局中,通过fragment标签引入fragment,记住是name属性
<fragment
android:name="com.songsong.FragmentTest.fragment"
...
/>
- 动态加载:动态在 Activity 中添加 Fragment 。 (常用)
//前提1:先创建 Fragment类并继承 Fragment,在onCreateview设置XML布局文件。
//前提2:在Activity的XML布局文件中准备好布局容器R.id.lin_id
//步骤1:创建Fragment的管理器对象FragmentManager
FragmentManager manager = getFragmentManager();
//步骤2:获取Fragment的事务对象并且开启事务
FragmentTransaction transaction = manager.beginTransaction();
//步骤3:调用事务中相应的动态操作Fragment的方法执行,add、remove和replace
transaction.add(R.id.lin_id, new Fragment1());
//模拟返回栈
transaction.addToBackStack(null);
//步骤4:提交事务
transaction.commit();
4.Fragment 和 Activity 之间的通信
通常,Fragment 与 Activity 通信存在三种情形:
- Activity 操作内嵌的 Fragment,
- Fragment 操作宿主 Activity,
- Fragment 操作同属 Activity中的其他 Fragment。
- 在 Activity 中调用 Fragment 中的 findFragmentById 方法;
//通过FragmentManage的findFragmentById得到实例,然后就可以调用fragment里的方法
RightFragment rf = getFragmentManager().findFragmentById(R.id.right_fragment);
- 在 Fragment 中调用 Activity 中的 getActivity 方法;
//fragment中调用Activity的方法,getActivity本身就是一个Context对象。
MainActivity act = getActivity();
-
Fragment 与 Fragment 之间的通信:
先在一个碎片中可以得到与它相关联的活动,然后再通过这个活动去获取另外一个碎片的实例,这样实现了不同碎片之间的通信了 。
5.Fragment 的生命周期
简单的Fragment流程图—— onAttach->onCreate -> onCreateView -> onActivityCreated -> onStart -> onResume ->创建成功-> onPause->onStop->onDestroyView -> onDestroy->onDetach。其中和Activity有不少名称相同作用相似的方法,而不同的方法有:
- onAttach():当Fragment和Activity建立关联时调用
- onCreateView():当Fragment创建视图时调用
- onActivityCreated():当与Fragment相关联的Activity完成onCreate()之后调用
- onDestroyView():在Fragment中的布局被移除时调用
- onDetach():当Fragment和Activity解除关联时调用
Fragment操作生命流程图:
- 打开 Fragment:onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume
- 替换 Fragment:onPause->onStop->onDestroyView
- 返回旧 Fragment:onCreateView->onActivityCreated->onStart->onResume
- 退出 Fragment:onPause->onStop->onDestroyView->onDestroy->onDetach
6.FragmentPagerAdapter 与 FragmentStatePagerAdaper 区别:
FragmentPagerAdapter :FragmentPagerAdapter 在切换 ViewPager 的时候,只是把 Fragment的UI 与 Activity的UI 脱离开来,并不回收内存。所以它适用页面较少的情况。(在其源码 DestroyItem 方法中的最后一行,mCurTransaction.detach 可知)
FragmentStatePagerAdaper :由于 FragmentStatePagerAdaper 在每次切换 ViewPager 的时候,它是回收内存的。又因为在页面较多的情况下会更耗内存,所以它适合页面较多的情况。(在源码 DestroyItem 方法中的最后一行,mCurTransaction.remove 可知 )
7.Fragment 的 replace、add、remove 方法
- replace 是 FragmentManager 的方法,是将 Activity 最上层的 Fragment 替换掉。
- add 将 Fragment 的实例添加到 Activity 的最上层;
- remove 将 Fragment 的实例从 Activity 的队列中删除;
8.Fragment 特点
- Fragment 可以作为 Activity 界面的一部分组成出现;
- 可以在一个 Activity 中同时出现多个 Fragment,并且一个 Fragment 也可以在多个 Activity 中使用;
- 在 Activity 运行过程中,可以添加、移除或者替换 Fragment;
- Fragment 可以响应自己的输入事件,并且有自己的生命周期,它们的生命周期会受宿主 Activity 的生命周期影响。
- Fragment 可以轻松得创建动态灵活的 UI 设计,可以适应于不同的屏幕尺寸。从手机到平板电脑。
- Fragment 解决 Activity 间的切换不流畅,轻量切换。
- Fragment 替代 TabActivity 做导航,性能更好。
- Fragment 做局部内容更新更方便,原来为了达到这一点要把多个布局放到一个 activity 里面,现在可以用多 Fragment 来代替,只有在需要的时候才加载 Fragment,提高性能。
9.Activity和Fragment的异同?
- Activity和Fragment的相似点在于,它们都可包含布局、可有自己的生命周期,Fragment可看似迷你活动。
- 不同点是,由于Fragment是依附在Activity上的,多了些和宿主Activity相关的生命周期方法:如onAttach()、onActivityCreated()、onDetach();另外,Fragment的生命周期方法是由宿主Activity而不是操作系统调用的,Activity中生命周期方法都是protected,而Fragment都是public,也能印证了这一点,因为Activity需要调用Fragment那些方法并管理它。
10.怎么理解Activity和Fragment的关系?
- 正如Fragment的名字“碎片”,它的出现是为了解决Android碎片化 ,它可作为Activity界面的组成部分,可在Activity运行中实现动态地加入、移除和交换。
- 一个Activity中可同时出现多个Fragment,一个Fragment也可在多个Activity中使用。
- 另外,Activity的FragmentManager负责调用队列中Fragment的生命周期方法,只要Fragment的状态与Activity的状态保持了同步,宿主Activity的FragmentManager便会继续调用其他生命周期方法以继续保持Fragment与Activity的状态一致。
11.何时会考虑使用Fragment?
- 用两个Fragment封装两个界面模块,这样只使一套代码就能适配两种设备,达到两种界面效果;(新闻列表、新闻内容)
- 单一场景切换时使用Fragment更轻量化,如ViewPager和Fragment搭配使用。
12.Activity向引入的Fragment传值
- 步骤1:Activity中创建Fragment对象,调用setArguments(Bundle)方法存储值。
- 步骤2:Fragment中调用getArguments()获取传递Bundle对象解析获取具体值。
13.Fragment向Activity传值
步骤1:Fragment 中定义传值的回调接口,在生命周期 onAttach() 方法中获取接口的实现。
private MyListener listener;
@Override
public void onAttach(...){
...
listener = (MyListener)getActivity();
}
public interface MyListener{
public abstract void sendMessage(String str);
}
步骤2:Fragment 需要传值的位置调用接口回调方法传值。
listener.sendMessage(info);
步骤3:Activity 实现回调接口重写回调方法获取传递的值。
@Override
public void sendMessage(String str){
if(null !=str && !"".equals(str)){
//显示处理
}
}
14.Fragment与Fragment之间的传值
13.遇到过哪些关于Fragment的问题,如何处理的?
getActivity()空指针:这种情况一般发生在在异步任务里调用getActivity(),而Fragment已经onDetach(),此时就会有空指针,解决方案是在Fragment里使用 一个全局变量mActivity,在onAttach()方法里赋值,这样可能会引起内存泄漏,但是异步任务没有停止的情况下本身就已经可能内存泄漏,相比直接crash,这种方式显得更妥当一些。
Fragment视图重叠:在类onCreate()的方法加载Fragment,并且没有判断saveInstanceState==null或if(findFragmentByTag(mFragmentTag) == null),导致重复加载了同一个Fragment导致重叠。(PS:replace情况下,如果没有加入回退栈,则不判断也不会造成重叠,但建议还是统一判断下)
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// 在页面重启时,Fragment会被保存恢复,而此时再加载Fragment会重复加载,导致重叠 ;
if(saveInstanceState == null){
// 或者 if(findFragmentByTag(mFragmentTag) == null)
// 正常情况下去 加载根Fragment
}
}
Fragment状态保存 startActivityForResult 是哪个类的方法,在什么情况下使用?
本文参考资料:
- 《Android开发艺术探索》
- https://www.jianshu.com/p/718aa3c1a70b