前言
在閱讀ViewPager源碼的過程中,偶然間發(fā)現(xiàn)Fragment#setUserVisibleHint()方法過時(shí),所以帶著好奇看了下注釋如下:
/**
* Set a hint to the system about whether this fragment's UI is currently visible
* to the user. This hint defaults to true and is persistent across fragment instance
* state save and restore.
*
* <p>An app may set this to false to indicate that the fragment's UI is
* scrolled out of visibility or is otherwise not directly visible to the user.
* This may be used by the system to prioritize operations such as fragment lifecycle updates
* or loader ordering behavior.</p>
*
* <p><strong>Note:</strong> This method may be called outside of the fragment lifecycle.
* and thus has no ordering guarantees with regard to fragment lifecycle method calls.</p>
*
* @param isVisibleToUser true if this fragment's UI is currently visible to the user (default),
* false if it is not.
*
* @deprecated Use {@link FragmentTransaction#setMaxLifecycle(Fragment, Lifecycle.State)}
* instead.
*/
使用setMaxLifecycle()代替,因此產(chǎn)生了這篇文章。
發(fā)現(xiàn)點(diǎn)
當(dāng)我閱讀到ViewPager#populate()計(jì)算滑動(dòng)距離的方法時(shí),最終會(huì)調(diào)用一個(gè)setPrimaryItem()方法
void populate(int newCurrentItem) {
//... 省略超級(jí)多的代碼
calculatePageOffsets(curItem, curIndex, oldCurInfo);
mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
}
跟進(jìn)看下,發(fā)現(xiàn)一個(gè)PagerAdapter抽象類,我們很熟知了,在我們使用VP嵌套Fragment時(shí),經(jīng)常使用它派生出的兩個(gè)子類作為適配器。
這兩個(gè)派生出的子類中實(shí)現(xiàn)的setPrimaryItem()實(shí)現(xiàn)方式相同,我就以FragmentPagerAdapter為例。
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.setMaxLifecycle(mCurrentPrimaryItem, Lifecycle.State.STARTED);
} else {
mCurrentPrimaryItem.setUserVisibleHint(false);
}
}
fragment.setMenuVisibility(true);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.RESUMED);
} else {
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
會(huì)發(fā)現(xiàn)在配置事務(wù)時(shí),會(huì)先去if判斷一下mBehavior,是否是BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,若當(dāng)前的fragment為空,則setMaxLifecycle(Lifecycle.State.STARTED), 若已經(jīng)創(chuàng)建過了,則setMaxLifecycle(fragment, Lifecycle.State.RESUMED),否則會(huì)去兼容老的setUserVisibleHint()邏輯。由前言可見setUserVisibleHint()方法過時(shí)了,因此好奇,這個(gè)setMaxLifecycle()是什么東東?
FragmentTransaction#setMaxLifecycle()
@NonNull
public FragmentTransaction setMaxLifecycle(@NonNull Fragment fragment,
@NonNull Lifecycle.State state) {
addOp(new Op(OP_SET_MAX_LIFECYCLE, fragment, state));
return this;
}
由此發(fā)現(xiàn),在提交事務(wù)時(shí),將開發(fā)者設(shè)置的LifeCycle#State枚舉值存入了Op中,在最終提交事務(wù)時(shí),根據(jù)這個(gè)State枚舉去判斷調(diào)用目標(biāo)Fragment相關(guān)的生命周期方法,這個(gè)詳細(xì)流程由于篇幅原因就不追源碼了。之后我們看下這個(gè)枚舉。
/**
* Lifecycle states. You can consider the states as the nodes in a graph and
* {@link Event}s as the edges between these nodes.
*/
@SuppressWarnings("WeakerAccess")
public enum State {
/**
* Destroyed state for a LifecycleOwner. After this event, this Lifecycle will not dispatch
* any more events. For instance, for an {@link android.app.Activity}, this state is reached
* <b>right before</b> Activity's {@link android.app.Activity#onDestroy() onDestroy} call.
*/
DESTROYED,
/**
* Initialized state for a LifecycleOwner. For an {@link android.app.Activity}, this is
* the state when it is constructed but has not received
* {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} yet.
*/
INITIALIZED,
/**
* Created state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call;
* <li><b>right before</b> {@link android.app.Activity#onStop() onStop} call.
* </ul>
*/
CREATED,
/**
* Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached in two cases:
* <ul>
* <li>after {@link android.app.Activity#onStart() onStart} call;
* <li><b>right before</b> {@link android.app.Activity#onPause() onPause} call.
* </ul>
*/
STARTED,
/**
* Resumed state for a LifecycleOwner. For an {@link android.app.Activity}, this state
* is reached after {@link android.app.Activity#onResume() onResume} is called.
*/
RESUMED;
/**
* Compares if this State is greater or equal to the given {@code state}.
*
* @param state State to compare with
* @return true if this State is greater or equal to the given {@code state}
*/
public boolean isAtLeast(@NonNull State state) {
return compareTo(state) >= 0;
}
}
我們依次來看下。
- 不設(shè)置
getSupportFragmentManager().beginTransaction()
.add(R.id.fl_container, mInvoiceManagerFragment)
.commit();
- CREATED
getSupportFragmentManager().beginTransaction()
.add(R.id.fl_container, mInvoiceManagerFragment)
.setMaxLifecycle(mInvoiceManagerFragment, State.CREATED)
.commit();
- STARTED
getSupportFragmentManager().beginTransaction()
.add(R.id.fl_container, mInvoiceManagerFragment)
.setMaxLifecycle(mInvoiceManagerFragment,State.STARTED)
.commit();
- RESUMED
getSupportFragmentManager().beginTransaction()
.add(R.id.fl_container, mInvoiceManagerFragment)
.setMaxLifecycle(mInvoiceManagerFragment,State.RESUMED)
.commit();
所以 在設(shè)置最大周期后,最終Fragment生命周期變的可控。總結(jié)一下,
static final int INITIALIZING = 0; // 還沒有創(chuàng)建,初始狀態(tài)
static final int CREATED = 1; // 已創(chuàng)建
static final int ACTIVITY_CREATED = 2; // 完全創(chuàng)建但是還沒有start
static final int STARTED = 3; // 創(chuàng)建并啟動(dòng),可見但是不能操作
static final int RESUMED = 4; // 創(chuàng)建啟動(dòng)并且可以操作
Fragment所有的生命周期順序:
onCreate->onCretateView->onStart->onResume->onPause->onStop-> onDestoryView->onDestory
CREATED->STARTED->RESUMED
根據(jù)注釋中的LifeCycle狀態(tài)注釋,我們可以知道
- CREATED
CREATED即已創(chuàng)建狀態(tài),生命周期方法走到onCreate,如果當(dāng)前fragment狀態(tài)已大于CREATED,則會(huì)使fragment生命周期方法走到onDestoryView,如果小于CREATED,則走到onCreate。 - STARTED
如果當(dāng)前fragment狀態(tài)已大于STARTED,則會(huì)使fragment生命周期方法走到onPause,如果小于STARTED,則走到onStart; - RESUMED
無(wú)論什么情況,都只調(diào)用到onResume;
ViewPager 懶加載
- FragmentStatePagerAdapter
private static class FragmentPagerAdapter extends FragmentStatePagerAdapter {
private final ArrayList<EasyMockDataFragment> mFragments;
private final ArrayList<String> mFragmentTitles;
FragmentPagerAdapter(FragmentManager fm, ArrayList<String> fragmentTitles, ArrayList<EasyMockDataFragment> fragments) {
super(fm, FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
this.mFragments = fragments;
this.mFragmentTitles = fragmentTitles;
}
@Override
public int getCount() {
return mFragments.size() == mFragmentTitles.size() ? mFragments.size() : 0;
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitles.get(position);
}
@NonNull
@Override
public Fragment getItem(int i) {
return mFragments.get(i);
}
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
}
構(gòu)造方法中傳入BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT這個(gè)標(biāo)記,其中有兩個(gè)標(biāo)記,默認(rèn)為BEHAVIOR_SET_USER_VISIBLE_HINT,setUserVisible()方法是正常被調(diào)用的。
/**
* Indicates that {@link Fragment#setUserVisibleHint(boolean)} will be called when the current
* fragment changes.
*
* @deprecated This behavior relies on the deprecated
* {@link Fragment#setUserVisibleHint(boolean)} API. Use
* {@link #BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT} to switch to its replacement,
* {@link FragmentTransaction#setMaxLifecycle}.
* @see #FragmentStatePagerAdapter(FragmentManager, int)
*/
@Deprecated
public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0;
/**
* Indicates that only the current fragment will be in the {@link Lifecycle.State#RESUMED}
* state. All other Fragments are capped at {@link Lifecycle.State#STARTED}.
*
* @see #FragmentStatePagerAdapter(FragmentManager, int)
*/
public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1;
- BaseFragment
public class BaseFragment extends Fragment{
private boolean isFirst = true;
private boolean isCreate = false;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
isCreate = true;
}
@Override
public void onResume() {
super.onResume();
// 在onResume中進(jìn)行數(shù)據(jù)懶加載
initLoadData();
}
private void initLoadData() {
if (isCreate && isFirst) {
requestData();
isFirst = !isFirst;
}
}
}