寫在開頭
最近公司的一個專案需要的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);
}
複製程式碼
寫在最後
知識沒有學完了的一天,繼續努力!!!