寫在開頭
最近公司的一個項目需要的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();
? ? ? ? }
? ? }
? ? //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);
? ? }
```
寫在最后
知識沒有學完了的一天,繼續努力!!!