记录Fragment的显示时长
Posted -SOLO-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记录Fragment的显示时长相关的知识,希望对你有一定的参考价值。
序言
最近在埋点,需要记录fragment的显示时长。想法很简单,使用我们熟知的fragment的生命周期即可。主需要在onResume记录开始时间,在onPase记录结束时间。相减就可以完成fragment显示时间的记录。但是这是最理想的情况,是在一个activity中只有一个fragment。 fragment不涉及hide和show等方法的情况下。
然后我们实际情况却很复杂,涉及到ViewPager中使用fragment会预加载fragment,此时会有多个fragment处于onResume状态但是真正显示的fragment只有一个,也涉及到hide和show方法的影响,hide是通过将Fragment的View设置为GONE来实现的。会调用onHiddenChanged方法。而不会调用onPause方法。
因此要正确记录Fragment的显示时长,还是很烦的。需要处理各种情况。下面分情况讨论。
android.support.v4.app.Fragment
下面介绍使用了android.support.v4.app.Fragment事的方法。至于Android X有更好的处理办法。
ViewPager的影响
测试代码如下
package com.vincent.testfragment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* Created by zhuguohui
* Date: 2021/6/30
* Time: 10:16
* Desc:
*/
public class TestFragment extends Fragment {
private String title;
public void setTitle(String title) {
this.title = title;
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
Log.i("zzz",title+"执行 setUserVisibleHint:isVisibleToUser="+isVisibleToUser);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.i("zzz",title+"执行 onCreate");
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("zzz",title+"执行 onCreateView");
View view= inflater.inflate(R.layout.test_fragment,container,false);
TextView textView= view.findViewById(R.id.tv_title);
textView.setText(title);
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.i("zzz",title+"执行 onViewCreated");
}
@Override
public void onStart() {
super.onStart();
Log.i("zzz",title+"执行 onStart");
}
@Override
public void onResume() {
super.onResume();
Log.i("zzz",title+"执行 onResume");
}
@Override
public void onPause() {
super.onPause();
Log.i("zzz",title+"执行 onPause");
}
@Override
public void onStop() {
super.onStop();
Log.i("zzz",title+"执行 onStop");
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
Log.i("zzz",title+"执行 onHiddenChanged");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("zzz",title+"执行 onDestroy");
}
}
package com.vincent.testfragment.adapter;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.util.Log;
import com.vincent.testfragment.TestFragment;
import java.util.List;
/**
* Created by zhuguohui
* Date: 2021/6/30
* Time: 10:16
* Desc:
*/
public class TestAdapter extends FragmentStatePagerAdapter {
List<String> titles;
public TestAdapter(FragmentManager fm, List<String> titles) {
super(fm);
this.titles = titles;
}
@Override
public Fragment getItem(int position) {
Log.i("zzz", "new " + titles.get(position));
TestFragment testFragment = new TestFragment();
testFragment.setTitle(titles.get(position));
return testFragment;
}
@Override
public int getCount() {
return titles.size();
}
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
}
使用TabLayout+ViewPager测试,代码很简单就不贴出来。
测试日志
初始化ViewPager 打印的日志
2021-06-30 11:05:58.162 21249-21249/? W/nt.testfragmen: Accessing hidden method Landroid/app/LoadedApk;-><init>(Landroid/app/ActivityThread;Landroid/content/pm/ApplicationInfo;Landroid/content/res/CompatibilityInfo;Ljava/lang/ClassLoader;ZZZ)V (greylist-max-o, linking, denied)
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: new 第1个fragment
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 setUserVisibleHint:isVisibleToUser=false
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: new 第2个fragment
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 setUserVisibleHint:isVisibleToUser=false
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 setUserVisibleHint:isVisibleToUser=true
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onCreate
2021-06-30 11:05:58.486 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onCreate
2021-06-30 11:05:58.487 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onCreateView
2021-06-30 11:05:58.490 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onViewCreated
2021-06-30 11:05:58.491 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onStart
2021-06-30 11:05:58.491 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onResume
2021-06-30 11:05:58.491 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onCreateView
2021-06-30 11:05:58.493 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onViewCreated
2021-06-30 11:05:58.493 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onStart
2021-06-30 11:05:58.493 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onResume
点击第6个fragment执行的日志
2021-06-30 11:07:32.429 21249-21249/com.vincent.testfragment I/zzz: new 第6个fragment
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 setUserVisibleHint:isVisibleToUser=false
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: new 第5个fragment
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: 第5个fragment执行 setUserVisibleHint:isVisibleToUser=false
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: new 第7个fragment
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: 第7个fragment执行 setUserVisibleHint:isVisibleToUser=false
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 setUserVisibleHint:isVisibleToUser=false
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 setUserVisibleHint:isVisibleToUser=true
2021-06-30 11:07:32.430 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 onCreate
2021-06-30 11:07:32.431 21249-21249/com.vincent.testfragment I/zzz: 第5个fragment执行 onCreate
2021-06-30 11:07:32.431 21249-21249/com.vincent.testfragment I/zzz: 第7个fragment执行 onCreate
2021-06-30 11:07:32.432 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 onCreateView
2021-06-30 11:07:32.437 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 onViewCreated
2021-06-30 11:07:32.437 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 onStart
2021-06-30 11:07:32.437 21249-21249/com.vincent.testfragment I/zzz: 第6个fragment执行 onResume
2021-06-30 11:07:32.437 21249-21249/com.vincent.testfragment I/zzz: 第5个fragment执行 onCreateView
2021-06-30 11:07:32.440 21249-21249/com.vincent.testfragment I/zzz: 第5个fragment执行 onViewCreated
2021-06-30 11:07:32.440 21249-21249/com.vincent.testfragment I/zzz: 第7个fragment执行 onCreateView
2021-06-30 11:07:32.443 21249-21249/com.vincent.testfragment I/zzz: 第7个fragment执行 onViewCreated
2021-06-30 11:07:32.443 21249-21249/com.vincent.testfragment I/zzz: 第5个fragment执行 onStart
2021-06-30 11:07:32.443 21249-21249/com.vincent.testfragment I/zzz: 第5个fragment执行 onResume
2021-06-30 11:07:32.443 21249-21249/com.vincent.testfragment I/zzz: 第7个fragment执行 onStart
2021-06-30 11:07:32.443 21249-21249/com.vincent.testfragment I/zzz: 第7个fragment执行 onResume
2021-06-30 11:07:33.099 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onPause
2021-06-30 11:07:33.099 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onStop
2021-06-30 11:07:33.102 21249-21249/com.vincent.testfragment I/zzz: 第2个fragment执行 onDestroy
2021-06-30 11:07:33.102 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onPause
2021-06-30 11:07:33.103 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onStop
2021-06-30 11:07:33.103 21249-21249/com.vincent.testfragment I/zzz: 第1个fragment执行 onDestroy
分析
在ViewPager中使用Fragment 。onResume方法需要加以判断,onReusme方法会有两种方式被调用。一种是Fragment所在的Activity从后台到前台,一种ViewPager预加载。而此时能判断fragment是否显示就需要通过setUserVisibleHint方法中传递过来的参数。只有在fragment显示的时候,并且调用onResume方法的时候。才去调用相关的逻辑代码。当然在setUserVisibleHint方法中如果参数是true也可以判断。不过这个方法第一次调用的时候比onCreate还要早,此时fragment中需要的参数可能还不完整。建议保留到onResume方法。
show hide的影响
使用如下的代码来显示或隐藏fragment时,fragment中的onPause和onResume等方法不会被调用。
只会调用onHiddenChanged方法。需要在这个方法中接受变量,并保存。用于标识当前的fragment是否可见。
FragmentTransaction transaction=fm.beginTransaction();
transaction.hide(fragemnt);
transaction.commit();
特别需要注意的是onHiddenChanged方法 默认是空实现,而且该方法只有直接被**FragmentTransaction **影响到的fragment才会调用。如果你是fragment中还有子fragment,需要自己将调用传递下去。对于一般的使用了ViewPager的fragment。我自己写了一个工具类来实现。
/**
* Created by zhuguohui
* Date: 2021/6/29
* Time: 15:26
* Desc:用于从viewpager中获取正在显示的fragment
*/
public class ViewPagerUtil {
public static Fragment getCurrentFragment(ViewPager viewPager) {
if (viewPager == null) {
return null;
}
try {
Field field = viewPager.getClass().getDeclaredField("mItems");
field.setAccessible(true);
ArrayList arrayList = (ArrayList) field.get(viewPager);
for (int i 以上是关于记录Fragment的显示时长的主要内容,如果未能解决你的问题,请参考以下文章