Fragment笔记
Posted 「已注销」
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fragment笔记相关的知识,希望对你有一定的参考价值。
Fragment笔记
Fragment的产生与介绍
android运行在各种各样的设备中,有小屏幕的手机,超大屏的平板甚至电视。针对屏幕尺寸的差距,很多情况下,都是先针对手机开发一套App,然后拷贝一份,修改布局以适应平板等超级大屏的。难道无法做到一个App可以同时适应手机和平板么,当然了,必须有啊。Fragment的出现就是为了解决这样的问题。你可以把Fragment当成Activity的一个界面的一个组成部分,甚至 Activity的界面可以完全有不同的Fragment组成,更帅气的是Fragment拥有自己的生命周期和接收、处理用户的事件,这样就不必在Activity写一堆控件的事件处理的代码了。更为重要的是,你可以动态的添加、替换和移除某个Fragment。
为什么要使用fragment
- 单Activity+多Fragment:
一个app仅有一个Activity,界面皆是Frament,Activity作为app容器使用。优点:性能高,速度最快。参考:新版知乎 、google系app
- 多模块Activity+多Fragment
优点:速度快,相比较单Activity+多Fragment,更易维护
- 无视图的fragment 保存数据用
- activity的onSaveInstanceState(Bundle outState)能保存的数据量有限,当有大量数据要保存的时候用无视图的fragment
- Activity异常销毁时,onSaveInstanceState能保存的数据有限,数据过大容易oom。所以我们可以在onSaveInstanceState时attach一个Fragment,并将要存储的大数据保存到这个Fragment。当Activity重建时找到这个Fragment,再从中取出那些数据
FragmentPagerAdapter与FragmentStatePagerAdapter
Fragment的生命周期
- Fragment 主要用于定义Fragment
- FragmentManager 主要用于在Activity中操作Fragment
- FragmentTransaction 保证一些列Fragment操作的原子性,熟悉事务这个词,一定能明白
- 获取FragmentManager的方式
-
getFragmentManager()
-
v4中,getSupportFragmentManager
- 主要的操作都是FragmentTransaction的方法
-
FragmentTransaction transaction = fm.benginTransatcion();//开启一个事务
-
transaction.add() 往Activity中添加一个Fragment
-
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上并显示。
-
transatcion.commit()//提交一个事务
- Fragment Arguments
setArguments方法必须在fragment创建以后,添加给Activity前完成 - Fragment与Activity通信
- Fragment与ActioBar和MenuItem集成
-
静态使用fragment
注意点:- 嵌套了fragment 能
//作业: 尝试下 fragment嵌套 静态使用fragment - 静态加载一旦添加就不能在运行时删除
- 静态fragment 在哪儿初始化的?
- fragment一定要有一个没有参数的构造函数
fragment 为什么需要一个空构造? 看源码
- 嵌套了fragment 能
-
动态使用fragment 90%
获得FragmentManager对象,通过getSupportFragmentManager()
获得FragmentTransaction对象,通过fm.beginTransaction()
调用add()方法或者repalce()方法加载Fragment;
最后调用commit()方法提交事务
androidx jetpack下面的fragment
v4包下的fragment 有bug
< 24: fragment 重叠问题 onActivityResult分发结果(fragment嵌套) 出栈(popstack(tag,id) popstackimmdate )
转场动画
= 28
注意点:
- getActivity == null 请求网络接口
解决方案: 不建议fragment要使用宿主activity getActivity
//TODO: [解决方案]在onAttach(Activity activity)里赋值,使用mActivity代替getActivity(),
// 保证Fragment即使在onDetach后,仍持有Activity的引用(
// 有引起内存泄露的风险,但是异步任务没停止的情况下,本身就可能已内存泄漏,相比Crash,这种做法“安全”些)
@Override
public void onAttach(Context context)
super.onAttach(context);
Log.i(“Zero”, "onAttach : " + getActivity());
bugly
-
Can not perform this action after onSaveInstanceState
解决方案:
不能在onSaveInstanceState之后的生命周期里面commit fragment
不要在子线程commit fragment 已经走完onSaveInstanceState -
fragment 重叠
-
屏幕旋转 activity 生命周期
竖屏 -》 横屏 1
横屏 -》 竖屏 2
android:configChanges=“orientation” sdk > 23 sdk < 23
走 onConfigurationChanged原因:
onCreate add fragment
onDestroy
屏幕旋转 onCreate 又会执行 又会重新add一次 fragment (系统自动恢复了一个 )
why?
fragment 自动有一个恢复机制解决方案:
- onSaveInstanceState activity失去自动存储的功能 super
- if(savedInstanceState == null)add fragment
内存重启: fragment 重叠 ( 接了个电话,系统内存不足,杀掉了你的activity )
打开手机上的“开发者选项”中的“不保留活动”选项,模拟内存重启
fragment 常见操作
add(@NonNull Fragment fragment, @Nullable String tag)
tag : findFragmentByTag
add(@IdRes int containerViewId, @NonNull Fragment fragment,
@Nullable String tag)
containerViewId: 指定fragment添加到那个viewgroup findFragmentById
fragment 传参问题:不要写有参数的构造函数,这是错误的写法
内存重启 自动恢复:只会调用无参的构造函数 fragment 成员变量没有保存
public void setArguments(@Nullable Bundle args)
Bundle getArguments()
添加到回退栈
addToBackStack(@Nullable String name)
popBackStack()
name:
popBackStack(@Nullable final String name, final int flags)
fragment嵌套 回退栈问题 (单activity + fragment )
解决方案:
-
自定义
open class LifeCycleFragment : Fragment(), OnBackPressed
interface OnBackPressed
fun onBackPressed()
在activity
override fun onBackPressed()
super.onBackPressed()
//自己管理回退
-
使用navigation
多次add fragment 到同一个位置
重叠问题
fragment 根布局 设置背景
调用hide隐藏上一个添加的
add 与 replace的区别
add 往containerViewId的容器里面添加fragment view
replace将containerViewId的容器里面之前添加的view全部清空
add replace 千万不要混合使用 要么全部用add 要么全部用replace
remove 操作
if (fragment != null && fragment.isAdded)
fragment a
add … remove +1 + -1 = 0 show hide show
popBackStack() 按照栈 弹出的顺序回退 abcd d c b a
popBackStack(@Nullable final String name, final int flags)
abcd popBackStack(b,0) ab
popBackStack(b,0) a
保存数据
setRetainInstance(true)
add replace hide show -> commit
简单API 背后隐藏了什么操作
FragmentActivity: AMS控制Activity的生命周期,FragmentActivity在一系列的dispatchXXX
调用FragmentController来控制Fragment的生命周期
FragmentController:是一个代理
FragmentHostCallback: 被FragmentController持有,有一个FragmentManagerImpl,真正的进行fragment操作
FragmentContainer: :view容器
FragmentTransaction:
Fragment操作的事务,每个FragmentTransaction对象,代表着系列Fragment操作的事务。
- 操作Fragment的添加,删除,隐藏,显示时,都要使用FragmentTransaction。
- FragmentTransaction其实是个抽象类,真正的实现类为BackStackRecord
BackStackRecord: BackStackRecord实现了FragmentTransaction,每一个BackStackRecord对象,都代表了一次Fragment操作事务。
Op: Op对象,主要保存了FragmentTransaction操作事务中的单次操作,是相对于Fragment而言的。每个Op对象,保存了操作的Fragment对象,切换动画等对象
add -> new Op
把fragment 和操作的命令 OP_ADD 映射
vip handler源码分析 post (runnable,msg)
commitNow 为什么不运行添加到回退栈
commit
1237456 -> 654321
开启一个事务
。。。。。 N 个 Op
commit
事务操作
操作 command 意义
add OP_ADD 添加fragment
remove OP_REMOVE 删除fragment
replace OP_REPLACE 替换fragment
show OP_SHOW 显示fragment
hide OP_HIDE 隐藏fragment
attach OP_ATTACH 依附activity
detach OP_DETACH 从activity分离
cmd firstOutFragments lastInFragements
OP_ADD - 被添加的fragment
OP_REPLACE 被替换的fragment 新的fragment
OP_REMOVE 被删除的fragment -
OP_HIDE 被隐藏的fragment -
OP_SHOW - 被显示的fragment
OP_DETACH 被detach的fragment -
OP_ATTACH - 被attach的fragment
executeOps
cmd 调用FragmentManager方法
OP_ADD addFragment
OP_REPLACE removeFragment->addFragment
OP_REMOVE removeFragment
OP_HIDE hideFragment
OP_SHOW showFragment
OP_DETACH detachFragment
OP_ATTACH attachFragment
moveToState
状态表格
值 状态 意义 入口方法
0 INITIALIZING Fragment尚未初始化或者已经被销毁 dispatchDestroy
1 CREATED Fragment已被创建 dispatchDestoryView
2 ACTIVITY_CREATED Fragemtn所在Activity已经创建成功 dispatchActivityCreated
3 STARTED Fragment已经可见,但是还不可以接收点击事件 dispatchPause
4 RESUMED Fragment已经可见并且可以接收点击事件 dispatchResume
已经废弃
3 STOPPED Fragment已经被创建,但是尚未不可见 dispatchStop
fragment的state 与Activity 的生命周期不是等同
可见 与可交互
moveToState() Activity的生命周期
oncreate调用的时候,不管fragments 之前的状态 xxx -> CREATED Index
以上是关于Fragment笔记的主要内容,如果未能解决你的问题,请参考以下文章