您真的懂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);
    }
複製代碼

寫在最後

知識沒有學完了的一天,繼續努力!!!

相關文章
相關標籤/搜索