前言
生命周期
http://www.codeceo.com/article/android-fragment-circle.html
##
懒加载
场景
场景前提:Fragment里有个ViewPager,vp里有三个Fragment的情况.
我需要的情况是,第一次加载的时候就第一页去请求数据,而其他两页不去请求直到滑动到该界面.
预备知识
public void setUserVisibleHint(boolean isVisibleToUser)isVisibleToUser代表fragment是否可见.
实践
动手,先研究一下它在什么时候调用的
第一次加载
即app刚启动,刚到这个界面
PS:LiveFragment在第一个位置.1
2
3
4
5
6
7
8
9
10
11
12
13D/ChildFragment: LiveFragment setUserVisibleHint() called with: isVisibleToUser = [false]
D/ChildFragment: FollowFragment setUserVisibleHint() called with: isVisibleToUser = [false]
D/ChildFragment: FansFragment setUserVisibleHint() called with: isVisibleToUser = [false]
D/ChildFragment: LiveFragment onAttach:
D/ChildFragment: LiveFragment setUserVisibleHint() called with: isVisibleToUser = [true]
D/ChildFragment: LiveFragment onCreateView:
D/ChildFragment: LiveFragment onResume:
D/ChildFragment: FollowFragment onAttach:
D/ChildFragment: FollowFragment onCreateView:
D/ChildFragment: FansFragment onAttach:
D/ChildFragment: FansFragment onCreateView:
D/ChildFragment: FollowFragment onResume:
D/ChildFragment: FansFragment onResume:
可以看到,方法的调用顺序:
setUserVisibleHint->onAttach->(setUserVisibleHint如果可见)/onCreateView(不可见)->onResume
需要注意,第一次调用的时候连onCreateView都没执行,即view都没有初始化.
另外,每个Fragment在一开始,都先调用了setUserVisibleHint()并且传入了false,即还是不可见状态.
第二次and more
而后,滑动viewpager或者点击tab则会导致相关的fragment调用setUserVisibleHint(这里的相关指的是,即将不可见的fragment与即将可见的fragment,也即可见性会发生变化的fragment)
通过日志也可以看到true,false,成对出现,每次也只有两个相关fragment出现在日志里:
1 | D/ChildFragment: FansFragment setUserVisibleHint() called with: isVisibleToUser = [false] |
封装使用
大致的流程在这里,可以根据自己调用Fragment的生命周期需求可以适当修改
1 | public abstract class LazyFragment extends Fragment { |
使用,以LiveFragment为例:
1 |
|
知识点总结
- 第一次调用
setUserVisibleHint的时候它比onCreateView之前,这时候控件都没有初始化,需要小心. - onResume的时候,三个fragment都会调用onResume,但是
setUserVisibleHint只涉及到可见性改变的fragment - 滑动vp或者点击tab都会触发setUserVisibleHint
- 需要根据需要处理
onResume和lazyload
Fragment重叠问题
使用add hide show来控制显示fragment,但是一旦activity被回收,那些被hide的Fragment,也全部处于可见状态,并且无法操控,即出现fragment重叠问题.
原因:fragment被回收,然后 变透明了
解决办法
重写activity的onSaveInstanceState并且不调用super1
2
3
protected void onSaveInstanceState(Bundle outState) {
}
参考
关于Activity被回收,Fragment还在的问题
让多个Fragment 切换时不重新实例化
Exceptions
记录我遇到的坑
remove(null).commit()
当我试图在解决fragment被回收后出现重叠的状况的时候,我试着去移除原先老的fragment,但是发现如果被回收两次,olds虽然有size,但是它所包含的数据都是null!,导致remove(null).commit()报错!
报错日志:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19java.lang.NullPointerException
at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:707)
at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManag
at android.support.v4.app.FragmentController.execPendingActions(FragmentContro
at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:511)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1174)
at android.app.Activity.performStart(Activity.java:5203)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2198)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2286)
at android.app.ActivityThread.access$600(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1259)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5166)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
at dalvik.system.NativeStart.main(Native Method)
场景:activity里有两个fragment,一个fragment里有viewpager+3个fragment
Activity的onCreate 部分源码如下:
1 | if (savedInstanceState == null) { |
所以需要再加一层判断:1
2
3if (null != old) {
manager.beginTransaction().remove(old).commit();
}
完美!~
资料
android-fragmentmanager-backstackrecord-run-throwing-nullpointerexception
activity被回收,fragment的onActivityCreated调用两次
场景:
Activity里有两个Fragment,其中一个里有viewpager+3个fagment.
当activity被回收,fragment的onActivityCreated被调用了两次(另外一个fragment也不例外):
- 第一次 savedInstanceState 不为null 保存的数据还在
- 第二次 savedInstanceState 为null 丢失了
这导致我在该fragment的onSaveInstanceState(Bundle outState)里保存的数据失效了
日志如:1
2onActivityCreated: TLToplistFragment{43ceb940
onActivityCreated: TLToplistFragment{43cf7048
找了很久,但是并没有找到原因以及解决办法,原本是用来保存数据的,现在没办法了,
最后通过在activity的onSaveInstanceState里获取fragment的数据,然后再在重新创建的时候通过setArguments传入的方式替代.
这个坑的原因还不知道,暂时用其他方法给解决了需求.
参考资料
http://stackoverflow.com/questions/12453710/lazy-load-data-for-viewpager-items
http://blog.csdn.net/myatlantis/article/details/42643733