为什么需要Fragment?Fragment与Activity又是什么关系?Fragment的生命周期是怎样的?Fragment如何使用呢?其实Fragment是一种可以嵌入在活动中的UI片段,能够让程序更加合理和充分地利用大屏幕的空间,出现的初衷是为了适应大屏幕的平板电脑,可以将其看成一个小型Activity,又称作Activity碎片。下面来看看Fragment到底有哪些神奇之处吧 ~
Fragment基本概述
使用Fragment可以把屏幕划分成几块,然后进行分组,进行一个模块化管理。Fragment不能够单独使用,需要嵌套在Activity中使用,其生命周期也受到宿主Activity的生命周期的影响。
1、一个Activity可以运行多个Fragment
2、Fragment不能脱离Activity而存在
3、Activity是屏幕的主体,而Fragment是Activity的一个组成元素
4、一个Fragment可以被多个Activity重用
5、Fragment有自己的生命周期,并能接收输入事件
6、可以在Activity运行时动态地添加或删除Fragment
Fragment的优势:
1、模块化:我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中。
2、可重用:多个Activity可以重用一个Fragment。
3、可适配:根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好。
静态加载与动态加载
使用Fragment有两种方式,分别是静态加载和动态加载。
1、静态加载
关于静态加载的流程如下:
- 定义Fragment的xml布局文件
- 自定义Fragment类,继承Fragment类或其子类,同时实现onCreate()方法,在方法中,通过inflater.inflate加载布局文件,接着返回其View
- 在需要加载Fragment的Activity对应布局文件中的name属性设为全限定类名,即包名.fragment
- 最后在Activity调用setContentView()加载布局文件即可
静态加载一旦添加就不能在运行时删除
比如我现在要先进入到一个专门用于静态加载的Activity
1 | // 静态加载 |
StaticLoadActivity的布局文件如下:
1 | <LinearLayout |
其中fragment的name属性都指向了com.example.learnfragment.ListFragment:
1 | // 列表 Fragment |
fragment_list.xml 布局文件如下所示:
1 | <LinearLayout |
现在只需要点击Main Activity中的TextView即可看到静态加载Fragment的效果:
由此可见,其实Fragment是可复用的,因为StaticLoadActivity的布局文件中写了两个Fragment标签。
2、动态加载
动态加载Fragment的流程如下:
- 提前准备好Container,即Fragment的容器
- 获得FragmentManager对象,通过getSupportFragmentManager()
- 获得FragmentTransaction对象,通过fm.beginTransaction()
- 调用add()方法或者repalce()方法加载Fragment
- 最后调用commit()方法提交事务
下面演示一下动态加载Fragment,先在activity_main.xml布局文件中准备好两个Container和按钮:
1 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
一个Container是list_container、一个是detail_container,四个按钮的点击事件分别为dynamicLoad:
1 | public class MainActivity extends AppCompatActivity { |
动态加载Fragment中,FragmentTransaction类提供了方法完成增删等操作,完成后调用FragmentTransaction.commit()方法提交修改。
transaction.add():往Activity里面添加一个片段
transaction.remove():从Activity中移除一个Fragment,如果被移除的Fragment没有添加到回退栈,这个Fragment实例将会被销毁
transaction.replace():使用另一个Fragment替换当前的,实际上是remove()然后add()的合体
transaction.hide():隐藏当前Fragment,仅不可见,不会销毁
transaction.show():显示之前隐藏的Fragment
detach():会将view从UI中移除,和remove()不同,此时fragment的状态依然由FragmentManager维护
attach():重建view视图,附加到UI上并显示。
FragmentTransaction的commit方法一定要在Activity.onSaveInstance()之前调用,commit()操作是异步的,内部通过mManager.enqueueAction()加入处理队列。对应的同步方法为commitNow(),commit()内部会有checkStateLoss()操作,如果开发人员使用不当(比如commit()操作在onSaveInstanceState()之后),可能会抛出异常,而commitAllowingStateLoss()方法则是不会抛出异常版本的commit()方法,但是尽量使用commit(),而不要使用commitAllowingStateLoss()。
FragmentManager拥有回退栈(BackStack),类似于Activity的任务栈,如果添加了该语句,就把该事务加入回退栈,当用户点击返回按钮,会回退该事务(回退指的是如果事务是add(frag1),那么回退操作就是remove(frag1));如果没添加该语句,用户点击返回按钮会直接销毁Activity。
3、使用注意点
1、Fragment的onCreateView()方法返回Fragment的UI布局,需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛IllegalStateException异常。
2、如果在创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据。
3、可以在Fragment的onAttach()中通过getArguments()获得传进来的参数。如果要获取Activity对象,不建议调用getActivity(),而是在onAttach()中将Context对象强转为Activity对象。
Activity向Fragment传值
在ListFragment写一个获取ListFragment的方法:
1 | public class ListFragment extends Fragment { |
这样在创建ListFragment对象的时候,直接ListFragment.getInstance()传参即可:
1 | switch (id){ |
Fragment向Activity传值
还是根据上面的例子,首先在ListFragment中定义
1 | public class ListFragment extends Fragment { |
MainActivity中:
1 | public class MainActivity extends AppCompatActivity implements ListFragment.OnTittleListener { |
如果在Fragment中需要Context,可以通过getActivity()
,如果该Context需要在Activity被销毁后还存在,则使用getActivity.getApplicationContext()
; 考虑Fragment的重复使用问题,降低与Activity的耦合,Fragment操作应该由它的管理者Activity决定。
Fragment生命周期
Fragment中常用的生命周期方法
当Fragment从创建到运行时回调的生命周期方法有
1、onAttach():当Fragment依附到Activity时调用的方法
2、onCreate():当Fragment创建时调用的方法
3、onCreateView():给Fragment加载布局时调用的方法
4、onActivityCreated():当该Fragment依附的Activity创建时调用的方法
5、onStart():当Fragment启动时调用的方法
6、onResume():当Fragment正在运行时调用的方法
当Fragment不再使用时调用的生命周期方法
7、onPause():当Fragment不在交互时调用该方法
8、onStop():当Fragment不再可见时调用该方法
9、onDestroyView():销毁Fragment布局时调用的方法
10、onDestroy():当Frament销毁时调用的方法
11、onDetach():当Fragment完全脱离Activity时调用的方法
下面通过代码演示一下Fragment的生命周期:
MainActivity的布局中有两个按钮,一个是用于加载Fragment的,另外一个是切换到另外一个Activity的,MainActivity的界面代码如下所示:
1 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
MyFragment的界面:
1 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
AnotherActivity的界面:
1 | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
MainActivity的逻辑,其实主要就是两个点击事件:
1 | public class MainActivity extends AppCompatActivity { |
MyFragment代码如下:
1 | public class MyFragment extends Fragment { |
通过演示可以看到如下效果:
1 | 10-18 17:18:08.735 5107-5107/cn.changlin.fragmentlifecycle I/MyFragment: onCreate: Fragment创建 |
- 本文作者: Tim
- 本文链接: https://zouchanglin.cn/20683.html
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明出处!