zoukankan      html  css  js  c++  java
  • Fragment的setUserVisibleHint方法实现懒加载,但setUserVisibleHint 不起作用?

          我们在做应用开发的时候,一个Activity里面可能会以viewpager(或其他容器)与多个Fragment来组合使用,而如果每个fragment都需要去加载数据,或从本地加载,或从网络加载,那么在这个activity刚创建的时候就变成需要初始化大量资源。这样的结果,我们当然不会满意。那么,能不能做到当切换到这个fragment的时候,它才去初始化呢?
    答案就在Fragment里的setUserVisibleHint这个方法里。请看关于Fragment里这个方法的API文档:

    该方法用于告诉系统,这个Fragment的UI是否是可见的。所以我们只需要继承Fragment并重写该方法,即可实现在fragment可见时才进行数据加载操作,即Fragment的懒加载。根据网友们提供的方法,代码如下(本人稍作修改了下):

    复制代码
     1 import android.os.Bundle;
     2 import android.support.v4.app.Fragment;
     3
     4 /**
     5  * Author: wangjie
     6  * Email: tiantian.china.2@gmail.com
     7  * Date: 1/23/15.
     8  */
     9 public abstract class BaseLazyFragment extends Fragment {
    10     private static final String TAG = BaseLazyFragment.class.getSimpleName();
    11     private boolean isPrepared;
    12
    13     @Override
    14     public void onActivityCreated(Bundle savedInstanceState) {
    15         super.onActivityCreated(savedInstanceState);
    16         initPrepare();
    17     }
    18
    19
    20     /**
    21      * 第一次onResume中的调用onUserVisible避免操作与onFirstUserVisible操作重复
    22      */
    23     private boolean isFirstResume = true;
    24
    25     @Override
    26     public void onResume() {
    27         super.onResume();
    28         if (isFirstResume) {
    29             isFirstResume = false;
    30             return;
    31         }
    32         if (getUserVisibleHint()) {
    33             onUserVisible();
    34         }
    35     }
    36
    37     @Override
    38     public void onPause() {
    39         super.onPause();
    40         if (getUserVisibleHint()) {
    41             onUserInvisible();
    42         }
    43     }
    44
    45     private boolean isFirstVisible = true;
    46     private boolean isFirstInvisible = true;
    47
    48     @Override
    49     public void setUserVisibleHint(boolean isVisibleToUser) {
    50         super.setUserVisibleHint(isVisibleToUser);
    51         if (isVisibleToUser) {
    52             if (isFirstVisible) {
    53                 isFirstVisible = false;
    54                 initPrepare();
    55             } else {
    56                 onUserVisible();
    57             }
    58         } else {
    59             if (isFirstInvisible) {
    60                 isFirstInvisible = false;
    61                 onFirstUserInvisible();
    62             } else {
    63                 onUserInvisible();
    64             }
    65         }
    66     }
    67
    68     public synchronized void initPrepare() {
    69         if (isPrepared) {
    70             onFirstUserVisible();
    71         } else {
    72             isPrepared = true;
    73         }
    74     }
    75
    76     /**
    77      * 第一次fragment可见(进行初始化工作)
    78      */
    79     public abstract void onFirstUserVisible();
    80
    81     /**
    82      * fragment可见(切换回来或者onResume)
    83      */
    84     public abstract void onUserVisible();
    85
    86     /**
    87      * 第一次fragment不可见(不建议在此处理事件)
    88      */
    89     public abstract void onFirstUserInvisible();
    90
    91     /**
    92      * fragment不可见(切换掉或者onPause)
    93      */
    94     public abstract void onUserInvisible();
    95
    96 }
    复制代码

    如上代码,使用setUserVisibleHint方法作为回调的依据,
    暴露出来让子类使用的新的生命周期方法为:


    - onFirstUserVisible();
    第一次fragment可见(进行初始化工作)


    - onUserVisible(); 
    fragment可见(切换回来或者onResume)


    - onFirstUserInvisible();
    第一次fragment不可见(不建议在此处理事件)


    - onUserInvisible();
    fragment不可见(切换掉或者onPause)

    据说具体的效果是:

    1. 首先加载ViewPager,回调FragmentA(第一个默认呈现的Fragment)的onFirstUserVisible(),可以在这里进行FragmentA的初始化工作,其他Fragment保持不变。

    2. 用户从FragmentA滑动到FragmentB,回调FragmentA的onUserInvisible()、FragmentB的onFirstUserVisible()(因为第一次切换到FragmentB,可以在这里进行初始化工作)。

    3. 用户从FragmentB滑动到FragmentC,回调FragmentB的onUserInvisible()、FragmentC的onFirstUserVisible()(因为第一次切换到FragmentC,可以在这里进行初始化工作)。

    4. 用户从FragmentC滑动到FragmentB,回调FragmentC的onUserInvisible()、FragmentB的onUserVisible()(因为FragmentB之前已经被加载过)。

    5. 因为到此为止,suoyou的Fragment都已经被加载过了,所以以后这3个Fragment互相任意切换,只会回调原来Fragment的onUserInvisible()和切换后的Fragment的onUserVisible()。

    6. 用户处于FragmentB,关闭手机屏幕,回调FragmentB的onUserInvisible()。

    7. 用户处于FragmentB,手机屏幕处关闭状态,然后开启手机屏幕解锁,只回调FragmentB的onUserVisible()。

    可我TM无论怎么调试都没这个效果好吗,TMD setUserVisibleHint()就是不调用,不执行!!!

    问度娘TMD都有是千篇一律的是使用fragment的setUserVisibleHint()方法实现懒加载,使用fragment的setuservisiblehint ()方法实现懒加载,使用fragment的setUserVisibleHint()方法实现懒加载;我去!!!我都快崩溃了好吗。

    无果只能求助国外的网友了,竖上梯子问google(搜索 fragment setuservisiblehint not called)我的男神去了,打开第一条搜索结果,这个结果是我的另一个男神:,这就是我正想要的,国外的网友给的答案如下:

    答案大致意思是:需要 FragmentPagerAdapter 显示的对setUserVisibleHint()方法的调用,查看自己的adapter原来是继承的PagerAdapter 而不是FragmentPagerAdapter,于是果断重新生成一个继承 FragmentPagerAdapter 的 adapter,

    代码如下:

    复制代码
     1
     3 import android.support.v4.app.Fragment;
     4 import android.support.v4.app.FragmentManager;
     5 import android.support.v4.app.FragmentPagerAdapter;
     6
     7 import java.util.ArrayList;
     8 import java.util.List;
     9
    10 public class SimpleFragmentPagerAdapter  extends FragmentPagerAdapter {
    11     private List<Fragment> listFragments;
    12     private List<String> mTitleList = new ArrayList<>();//页卡标题集合
    13
    14     public SimpleFragmentPagerAdapter(FragmentManager fm,
    15                                   List<Fragment> al,
    16                                   List<String> titleList) {
    17         super(fm);
    18         listFragments = al;
    19         mTitleList =  titleList;
    20     }
    21
    22     public SimpleFragmentPagerAdapter(FragmentManager fm) {
    23         super(fm);
    24     }
    25
    26     @Override
    27     public Fragment getItem(int position) {
    28         return listFragments.get(position);
    29     }
    30
    31     @Override
    32     public int getCount() {
    33         return listFragments.size();
    34     }
    35
    36     @Override
    37     public int getItemPosition(Object object) {
    38         return super.getItemPosition(object);
    39     }
    40
    41     @Override
    42     public CharSequence getPageTitle(int position) {
    43         return mTitleList.get(position);//页卡标题
    44     }
    45 }
    复制代码

    然后将该adapter赋予Viewpager ,经调试成功了,setUserVisibleHint()方法终于起作用了,懒加载也有了。

     项目源码:https://github.com/Leevey/LazyLoadFragment

    参考文献:

    实现类似微信的延迟加载的Fragment——LazyFragment

    stackoverflow:Is Fragment.setUserVisibleHint() called by the android System?

    FragmentPagerAdapter.java的源码






  • 相关阅读:
    uart协议--Verilog及仿真
    DC综合的流程
    modelsim将vcd文件转换成wlf文件并查看波形
    将系统盘还原成原来的普通u盘
    Ubuntu的操作命令
    gvim快捷键
    dc_shell环境下TCL语言的使用
    AHB总线学习
    Ubuntu文件共享
    Linux基础学习 | 目录及文件
  • 原文地址:https://www.cnblogs.com/jeffen/p/6709133.html
Copyright © 2011-2022 走看看