Fragment相关
Android中展示界面一般是通过
Activity
去实现的,当要实现类似商城类的首页时,就会拿出Fragment
去实现对应的每个标签页,由Activity
进行管理。
Fragment介绍
Fragment
存在必须依附于FragmentActivity
使用,并且与FragmentActivity
一样,拥有自己独立生命周期,同时可以处理用户的交互动作。并且可以在一个Activity
中动态的添加、替换,移除不同的Fragment
,同样Fragment
也可以拥有多个子Fragment
并对他们进行控制,对于信息的显示有很大的便利性。
Fragment使用方式
Fragment初始化
默认提供两种初始化方式:
new XXFragment()
1
DemoFragment fragment = new DemoFragment()
xml 引入
1
2
3
4<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
class="com.demo.fragment.DemoFragment"/>
主流使用的是第一种方法,但是并不是推荐的标准用法,如果需要有参数传入的情况下。
在Fragment
中添加newInstance()
,然后方法里面传入参数,以后获取Fragment就调用该方法,不要使用new
方法。
1 |
|
1 |
|
Fragment会被重新销毁(可能因为内存不足、手机发生了配置变化),重新创建时会默认调用无参构造函数。
通过
setArguments()
传递的Bundle也会被保留下来。
操作Fragment
1 |
|
涉及到了以下类:
FragmentManager
在Activity通过getSupportManager
获取该对象,在Fragment
中通过getChildFragmentManager()
获取
FragmentTransaction
:Fragment操作事务
通过beginTransaction()
开启事务,事务开启后就可以对Fragment
进行操作
以下为几种常用的操作方法:
add()
:添加Fragment到Activity或Fragment中
hide()/show()
:隐藏和显示Fragment
remove()
:移除指定Fragment
replace()
:内部实质是调用remove()
和add()
完成Fragment修改过程
addToBackStack()
:添加当前Fragment到回退栈中,当按下返回键时可以根据回退栈进行操作
commit()
:提交事务,对Fragment进行操作后都需要commit()
完成提交后可以生效
commitAllowingStateLoss()
:也是提交事务的一种,但是不会在其中抛出异常,只是跳过了检测mStateSaved
是否进行了保存
确保
commit()
在Activity.onPostResume()
或者FragmentActivity.onResumeFragments()
内调用,而且不要随意使用commitAllowingStateLoss()
进行代替,不能滥用该方法。因为忽略状态丢失,Activity意外崩溃时就无法还原之前保存的数据。
添加Fragment有两种方法:
通过replace()
1 |
|
通过add()
配合show()、hide()
1 |
|
replace()
不会保留Fragment的状态,会销毁视图并重新加载,调用时保存的数据都会消失。
hide()/show()
只是对Fragment进行隐藏/显示,不会影响存储的数据
Fragment生命周期
{% fullimage /images/Fragment生命周期.png,Fragment生命周期,Fragment生命周期%}onAttach()
:Fragment和Activity绑定时调用。Fragment附加到Activity之后,无法再次调用setArguments()
onCreate()
:此时可以获取到setArguments()
传递过来的参数,通过Bundle获取
onCreateView()
:在Fragment加载布局时调用
1 |
|
onActivityCreated()
:当Activity的onCreate()
执行完成后调用
onDestoryView()
:Fragment中布局被移除时调用
onDetach()
:Fragmen和Activity解绑时调用
其中还有一个setRetainInstance()
当调用到该方法时,在Actiivity重新创建时可以完全不销毁Fragment
,以便Fragment中恢复数据。调用了
setRetainInstance(true)
后,Fragment恢复时就会跳过onCreate()
、onDestroy()
生命周期回调,因此在使用该方法时,onCreate()
中不要做初始化逻辑。
当因为设备配置发生变化时,
FragmentManager
首先销毁队列中的fragment的视图,接着FragmentManager
会检查Fragment
中的retainInstance
属性,如果为false,直接销毁Fragment实例;若设置为true,fragment的视图会被销毁,但fragment本身不会被销毁,处于短暂的保留状态。当Activity需要时会对其进行恢复。
Fragment通信
Fragment与Activity通信
如果Activity中包含自己管理的Fragment的引用,可以通过该引用直接访问所有public方法
Activity中未保存任何Fragment的引用,通过给每个Fragment设置
Tag或ID
,后面通过调用FragmentManager.findFragmentByTag()或FragmentManager.findFragmentById()
获取对应Fragment实例在Fragment通过
getActivity()
获取Activity实例,然后执行操作。通过
getActivity()
获取Activity实例,可能会返回null
导致异常。该方法返回结果只会在onAttach()
及onDetach()
会非空,其他时候都有可能为空,所以可以先使用getContext()
去进行替代,这样比较安全。还有一种就是定义一个全局变量,当触发
onAttach()
进行赋值,后续调用直接使用该全局变量DemoFragment.java 1
2
3
4
5
6Context context ;
@Override
public void onAttach(Context context){
super.onAttach(context);
this.context = context;
}
使用接口方式(推荐做法)
DemoFragment.java 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//Fragment中定义接口
public interface ShowMsgListener{
void showMsg(String str);
}
private ShowMsgListener msgListener;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
if(activity!=null){
//获取Activity中实现的接口
msgListener=(DemoActivity)activity;
}
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement showMsgListener");
}
}
//调用接口
msgListener.showMsg("From fragment");DemoActivity.java 1
2
3
4
5
6public DemoActivity extends FragmentActivity implements ShowMsgListener{
@Override
public void showMsg(String str){
//拿来做事
}
}Fragment从Activity获取数据
Fragment与Fragment通信
Fragment之间的通信需要通过Activity进行关联,不应该是直接的进行通信。
实现通信步骤主要有以下三步:
- 定义接口
- Activity实现接口
- 在接口方法中Activity调用对应Fragment
Fragment常见问题
Fragment重叠
当宿主Activity
因为被系统回收或者配置发生改变导致销毁重建时,会重新执行onCreate()
,就有可能重新执行一次Fragment
创建过程,然后又会新建一个Fragment
。
1 |
|
Fragment懒加载
懒加载:只在要使用时才去加载数据,而不是在初始化时就加载完毕。
在加载数据前需要先判断三种状态:
- 数据是否已经加载过
- Fragment是否已经调用到
onCreate()
- 界面对于用户是否可见
Fragment.startActivityForResult()
Fragment启动,Activity获取结果
1 |
|
1 |
|
Fragment启动,Fragment获取结果
1 |
|
1 |
|
要求父Activity必须覆写了
onActivityResult()
且调用了super.onActivityResult()
。
Fragment配合ViewPager使用
一般类似资讯类、新闻类App首页都会分成多个标签,在不同的标签会有不同的内容,这个时候就需要配合ViewPager来实现内容展示,关键在于对应的fragment是否需要进行销毁。
可用的Adapter分为两种:
FragmentPagerAdapter
:对于不再需要的fragment,选择调用detach()
,仅销毁视图并不会销毁fragment实例。FragmentStatePagerAdapter
:再切换不同fragment的时候,会把前面的fragment进行销毁,但是在系统销毁前,会存储其Fragment的Bundle,倒是需要重新创建Fragment时,可以从onSaveInstanceState()
获取保存的数据。
使用FragmentStatePagerAdapter
比较省内存,但是销毁重建的过程也是需要时间的,如果页面较少可以使用FragmentPageAdapter
,很多的话还是推荐FragmentStatePagerAdapter
。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!