现在越来越多的应用会使用viewpager+fragment显示自己的内容页,fragment和activity有很多共同点,如下图就是fragment的生命周期

但是fragment和activity不同的是当调用本身的onResume和onPause方法的时候可能并不是当前的fragment在显示,例如当加载下面这张图时,当我打开MainActivity时显示的是第一个fragment 但此时调用的方法步骤如下:

08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-11 11:33:36.159    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated

08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onResume()

可见此时虽然用户看到的是第一个fragment 但第二个fragment onAttech onCreate onCreateView onActivityCreater onStart(“这个我没油打印log”)onResume 方法已经调用,这会导致如果我们要统计用户更喜欢哪个fragment的内容时,虽然fragment已经创建并且onResume但其实并没有显示这一页,那么是什么原因呢,这是因为v4包下的viewpager,为了让用户在切换过程中不会卡顿,谷歌官方默认当创建第一个fragment方法时回创建第二个fragment以确保用户滑动时第二个view已经被创建,保持viewPager的平滑滑动效果。

翻阅谷歌api发现viewpager有一个方法即 setOffscreenPageLimit。但当在viewpager设置以下代码

viewPager.setOffscreenPageLimit(0);

运行时打印的log和上面完全一致,即就算你设置只加载一个fragment还是会加载第二个fragment,原因是setOffscreenPageLimit中的源码时这样写的

public void setOffscreenPageLimit(int limit) {  
        if (limit < DEFAULT_OFFSCREEN_PAGES) {  
            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to " +  
                    DEFAULT_OFFSCREEN_PAGES);  
            limit = DEFAULT_OFFSCREEN_PAGES;  
        }  
        if (limit != mOffscreenPageLimit) {  
            mOffscreenPageLimit = limit;  
            populate();  
        }  
    }  

这个 DEFAULT_OFFSCREEN_PAGES 定义如下 private static final intDEFAULT_OFFSCREEN_PAGES;

就是如果你设置为0 也没用。!!!

为了解决判断是否fragment当前显示问题 可以在fragment重写 setUserVisibleHint(boolean isVisibleToUser)

在fragment添加log日志

public class Fragment1 extends Fragment {  
    private static final String TAG = "Fragment1";  
  
    @Override  
    public void onAttach(Activity activity) {  
        super.onAttach(activity);  
        L.v(TAG, "onAttach");  
    }  
  
    @Override  
    public void setUserVisibleHint(boolean isVisibleToUser) {  
        L.v(TAG, "setUserVisibleHint " + isVisibleToUser);  
    }  
  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        L.v(TAG, "onCreate");  
    }  
  
    @Override  
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
        L.v(TAG, "onCreateView");  
        View view = inflater.inflate(R.layout.fragment_layout,null);  
        TextView tv = (TextView) view.findViewById(R.id.tv1);  
        tv.setText(TAG);  
        return view;  
    }  
  
    @Override  
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {  
        super.onActivityCreated(savedInstanceState);  
        L.v(TAG,"onActivityCreated");  
    }  
  
    @Override  
    public void onResume() {  
        super.onResume();  
        L.v(TAG, "onResume()");  
    }  
  
    @Override  
    public void onPause() {  
        super.onPause();  
        L.v(TAG,"onPause");  
    }  
  
    @Override  
    public void onStop() {  
        super.onStop();  
        L.v(TAG,"onStop");  
    }  

启动activity打印日志如下:

08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-11 11:33:36.157    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-11 11:33:36.159    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onResume()

当切换到第二个fragment时打印日志:

08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ setUserVisibleHint false
08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint true
08-11 11:33:54.084    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onAttach
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onCreate
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onCreateView
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onActivityCreated
08-11 11:33:54.085    7162-7162/com.example.yinsgo.myui V/Fragment3﹕ onResume()

可见当fragment显示时回调用方法 setUserVisibleHint中的isVisibleToUser = true 当fragment被切换隐藏时回 isVisibleToUser = false;

所以当我们要统计是否用户看到一个fragment时可以执行一下代码

@Override  
public void setUserVisibleHint(boolean isVisibleToUser) {  
        L.v(TAG, "setUserVisibleHint " + isVisibleToUser);  
        if (isVisibleToUser) {  
            //统计代码 或者 fragment显示操作  
        } else {  
              
        }  
 }  

同时根据这个方法还可以进行数据的延迟加载,后面再写。

今天又看了一下发现单纯的执行上面的代码是有问题的,因为如果我们在else中认为用户是离开界面其实是不对的,因为根据启动第一个Fragment的log日志

08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-11 11:33:36.156    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-11 11:33:36.157    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-11 11:33:36.158    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-11 11:33:36.159    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-11 11:33:36.160    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated
08-11 11:33:36.161    7162-7162/com.example.yinsgo.myui V/Fragment2﹕ onResume()

第一次setUserVisibleHint 方法 isVisibleToUser 是false 但其实这个时候只是还未初始化,并不是用户已经浏览界面准备离开,于是这里我们需要一个辅助标记变量具体代码如下:

/** 
     * 判断是否是初始化Fragment 
     */  
    private boolean hasStarted = false;  
    @Override  
    public void setUserVisibleHint(boolean isVisibleToUser) {  
        super.setUserVisibleHint(isVisibleToUser);  
        L.v(TAG, "setUserVisibleHint " + isVisibleToUser);  
        if (isVisibleToUser) {  
            hasStarted = true;  
            L.v(TAG,"开始界面");  
        } else {  
            if (hasStarted) {  
                hasStarted = false;  
                L.v(TAG,"结束界面");  
            }  
        }  
    }  

当我们启动MainActivity时 Log打印如下:

08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onAttach
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onCreate
08-13 17:55:45.850  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint true
08-13 17:55:45.860  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ 开始界面
08-13 17:55:45.860  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onCreateView
08-13 17:55:45.870  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onActivityCreated
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onResume()
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onAttach
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onCreate
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onCreateView
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onActivityCreated
08-13 17:55:45.880  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ onResume()

切换到第二个fragment时,此时离开第一个fagment  log打印如下

08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ setUserVisibleHint false
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ setUserVisibleHint false
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ 结束界面
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint true
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ 开始界面
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onAttach
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onCreate
08-13 17:57:04.310  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onCreateView
08-13 17:57:04.320  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onActivityCreated
08-13 17:57:04.320  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ onResume()

切换到第三个fragment时,此时离开第二个fragment log打印如下:

08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ setUserVisibleHint false
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment2﹕ 结束界面
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ setUserVisibleHint true
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment3﹕ 开始界面
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onPause
08-13 17:58:15.040  21467-21467/com.example.yinsgo.myui V/Fragment1﹕ onStop

可见这样就可以准确统计用户是否离开或者开始浏览界面了。根据这些开始和离开可以统计用户停留界面的时间等数据。

  

  

 

  

  

setUserVisibleHint-- fragment真正的onResume和onPause方法的更多相关文章

  1. setUserVisibleHint-- fragment真正的onResume和onPause方法

    现在越来越多的应用会使用viewpager+fragment显示自己的内容页,fragment和activity有很多共同点,如下图就是fragment的生命周期 但是fragment和activit ...

  2. Android setUserVisibleHint-- fragment真正的onResume和onPause方法

    这个情况仅适合与多个fragment之间切换时统计,而非activity和fragment同时交互,因当时项目为首页4个fargment时长统计,因此适合,经下面网友评论指出,特在这里写出此问题,因最 ...

  3. Fragment的可见再载入的方法(真正的Fragment的OnResume和OnPause)

    一 起因 我们在做应用的过程中,一个应用的界面可能是多个Fragment切换而成的.可是如果在每次应用启动的时候就去载入大量的网络数据(如果你的每一个Fragment都须要载入网络数据.你也能够理解为 ...

  4. 【Android】Fragment真正意义上的onResume和onPause

    前言 Fragment虽然有onResume和onPause的,但是这两个方法是Activity的方法,调用时机也是与Activity相同,和ViewPager搭配使用这个方法就很鸡肋了,根本不是你想 ...

  5. Android Fragment真正意义上的onResume和onPause

    Fragment虽然有onResume和onPause的,但是这两个方法是Activity的方法,调用时机也是与Activity相同,和ViewPager搭配使用这个方法就很鸡肋了,根本不是你想要的效 ...

  6. Activity 重载方法 onStart和onResume、onPause和onStop的区别

    Activity 重载方法 onStart和onResume.onPause和onStop的区别 首先了解Activity的四种状态 Running状态:一个新的Activity启动入栈后,它在屏幕最 ...

  7. Android Activity为什么要细化出onCreate、onStart、onResume、onPause、onStop、onDesdroy这么多方法让应用去重载?

    原文:http://www.xuebuyuan.com/1608083.html 最近在研究Activity的启动流程,老罗的blog在看,也找了其它资料学习,也跟过Android4.3的源码, 在跟 ...

  8. 【转】【Android UI设计与开发】第07期:底部菜单栏(二)Fragment的详细介绍和使用方法

    原始地址:http://blog.csdn.net/yangyu20121224/article/category/1431917/1 由于TabActivity在Android4.0以后已经被完全弃 ...

  9. Fragment 的生命周期及使用方法详解

    Fragment 的基础知识介绍 1.1 概述 1.1.1 特性 By hebang32624 Fragment 是 activity 的界面中的一部分或一种行为.可以把多个 Fragment 组合到 ...

随机推荐

  1. Django的sitemap

    1.安装 安装Sitemap APP的步骤如下: 在INSTALLED_APPS设置中添加'django.contrib.sitemaps'; 确认你的TEMPLATES设置中包含DjangoTemp ...

  2. Ejb3 + Jboss8 出现Session id hasn't been set for stateful component

    Ejb 3 + JBoss 8  在使用客户端远程访问有状态的Ejb对象时,出现ERROR: Session id hasn't been set for stateful component 出现该 ...

  3. 我的Git教程 之 初始化本地库

    初始化本地库 前言:这个教程只适用于像我一样大致理解Git的原理,但是不太记得住Git命令的同学使用.所以具体原理只会提一下,具体可以参见Pro Git.同时,下面的操作需要先安装相应的Git工具,具 ...

  4. Spring Security构建Rest服务-1205-Spring Security OAuth开发APP认证框架之Token处理

    token处理之二使用JWT替换默认的token JWT(Json Web Token) 特点: 1,自包含:jwt token包含有意义的信息 spring security oauth默认生成的t ...

  5. Spring Boot 日志配置

    Spring Boot 日志配置 默认日志 Logback: 默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台.在运行应用程序和其他例子时,你应该已经看到很 ...

  6. Android 开发工具类 04_KeyBoardUtils

    打开或关闭软键盘: 1.打卡软键盘: 2.关闭软键盘. import android.content.Context; import android.view.inputmethod.InputMet ...

  7. 使用redis的发布订阅模式实现消息队列

    配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://w ...

  8. elasticsearch插件安装之--中文分词器 ik 安装

    /** * 系统环境: vm12 下的centos 7.2 * 当前安装版本: elasticsearch-2.4.0.tar.gz */ ElasticSearch中内置了许多分词器, standa ...

  9. solidity如何拼接字符串?

    当你开始学习使用solidity开发以太坊智能合约之后,很快你会碰到一个问题: 一.在solidity中该如何拼接字符串? 可能你已经试过了,下面的代码试图把两个字符串使用相加的运算符连接起来,但是这 ...

  10. T-SQL 片段收藏

    存储过程 CREATE PROCEDURE spInsertOrUpdateProduct --有则更新,否则插入 ) , ) , @StdCost MONEY AS IF EXISTS ( SELE ...