最近公司的一个项目需要的Fragment可见的时候处理一些逻辑,UI结构并非Tablayout+viewPager+Fragment结果,而是FragmentTabHost+Fragment的结构,所以有了一些坑,不知道你是否遇到过,从源码层面看一下这些问题,写出来希望大家判断好与坏。
公司之前代码是在onResume方法中写逻辑,后来想了下,这明显是不对的,大家都知道Fragment的onResume是依赖于附属Activity的onResume方法的,当你从fragment的跳转到另一个Activity再次返回的时候,fragment附属的Activity下的所有Fragment都会走onResume方法,我们项目中onResume方法都是一些必须的网络请求和一些与逻辑无关的操作,所以并未发现错误,在我动态适配状态的过程发现了这个问题并研究了一下,下面来看这些方法!
setUserVisibleHint方法,先看一下源码:
public void setUserVisibleHint(boolean isVisibleToUser) {
if (!mUserVisibleHint && isVisibleToUser && mState < STARTED
&& mFragmentManager != null && isAdded()) {
mFragmentManager.performPendingDeferredStart(this)
mUserVisibleHint = isVisibleToUser
mDeferStart = mState < STARTED && !isVisibleToUser
复制代码
我们可以看到,他只是Fragment源码中的一个方法,这说明他是需要手动调用的,那为什么Fragment+ViewPager架构的可以用这个方法来判断Fragment是否可见呢?那么就需要看一下Viewpager和与之结合的FragmentPagerAdapter源码了,如下:
@Override
public Object instantiateItem (ViewGroup container, int position ) {
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility (false );
fragment.setUserVisibleHint (false );
return fragment;
@Override
public void setPrimaryItem (ViewGroup container, int position, Object object ) {
Fragment fragment = (Fragment )object ;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null ) {
mCurrentPrimaryItem.setMenuVisibility (false );
mCurrentPrimaryItem.setUserVisibleHint (false );
if (fragment != null ) {
fragment.setMenuVisibility (true );
fragment.setUserVisibleHint (true );
mCurrentPrimaryItem = fragment;
复制代码
这个方法调用实际在FragmentPagerAdapter中。那么当你是FragmentTabHost+Fragment的结构的时候,你会发现这个方法压根不会被调用。
onHiddenChanged方法。源码的注释写的很清楚了。
* Return true if the fragment has been hidden. By default fragments
* are shown. You can find out about changes to this state with
* {
@link
#onHiddenChanged}. Note that the hidden state is orthogonal
* to other states -- that is, to be visible to the user, a fragment
* must be both started and not hidden.
如果该Fragment对象已经被隐藏,那么它返回
true
。默认情况下,Fragment是被显示的。能够用
onHiddenChanged
(
boolean
)回调方法获取该Fragment对象状态的改变,要注意的是隐藏状态与其他状态是正交的---也就是说,要把该Fragment对象显示给用户,Fragment对象必须是被启动并不被隐藏。
这里的隐藏或者显示是指Fragment调用show或者hider的时候才会改变mHidden的值得
复制代码
在FragmentTabHost+Fragment的结构的时候,当你跳转到另一个Activity再次返回的时候你会发现这方法并没有走,因为当前Fragment并没有改变show或者hide,故不会走。
isVisible方法
如果使用这个方法判断当前页面是否隐藏了呢?我试了也是不行的,先看下这个方法的源码:
final public boolean isVisible () {
return isAdded () && !isHidden () && mView != null
&& mView.getWindowToken () != null && mView.getVisibility () == View.VISIBLE ;
复制代码
如果你懂了onHiddenChanged方法,这应该就知道只使用它也是不行的,因为isHidden()的值和onHiddenChanged方法是有联系的。当你切换tab的时候,isVisible()放回是false。
趁这次需求,也详细看了下这些生命周期的详细理论,所以在FragmentTabHost+Fragment的结构的时候我是这样解决的,如下:能适配第一次创建,tab切换,跳转Activity再次返回多种情况。
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged (hidden);
if (!hidden) {
onResumeCommon ();
@Override
public void onResume() {
super.onResume ();
if (isVisible()) {
onResumeCommon ();
private void onResumeCommon () {
StatusBarUtil.setStatusBarColor (mActivity, R.color.white);
StatusBarUtil.StatusBarLightMode (mActivity);
复制代码
写在最后
知识没有学完了的一天,继续努力!!!
1732
say_from_wen
Android
GitHub
2203
say_from_wen
Android
LeakCanary
200
cofbro
Android
RxJava
2494
Android
Android Jetpack
284
二流小码农
Flutter
Django
Android