您真的懂fragment的onResume,setUserVisibleHint,onHiddenChanged,isVisible方法吗!

写在开头

最近公司的一个项目须要的Fragment可见的时候处理一些逻辑,UI结构并不是Tablayout+viewPager+Fragment结果,而是FragmentTabHost+Fragment的结构,因此有了一些坑,不知道你是否遇到过,从源码层面看一下这些问题,写出来但愿你们判断好与坏。bash

思考:

公司以前代码是在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源码了,以下:ide

@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的结构的时候,你会发现这个方法压根不会被调用。ui

采坑二

onHiddenChanged方法。源码的注释写的很清楚了。this

/**
     * 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,故不会走。spa

采坑三:

isVisible方法code

若是使用这个方法判断当前页面是否隐藏了呢?我试了也是不行的,先看下这个方法的源码:orm

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();
        }
    }

    //isVisible()  重点是源码中isHidden的值
    //若是该Fragment对象已经被隐藏,也就是执行fragment执行hide()对象后,那么它返回true。
    @Override
    public void onResume() {
        super.onResume();
        if (isVisible()) {
            onResumeCommon();
        }
    }

    private void onResumeCommon() {
            StatusBarUtil.setStatusBarColor(mActivity, R.color.white);
            StatusBarUtil.StatusBarLightMode(mActivity);
    }
复制代码

写在最后

知识没有学完了的一天,继续努力!!!

相关文章
相关标签/搜索