AndroidX Fragment 感知生命周期

时间:2021-7-21 作者:qvyue

前言

在阅读ViewPager源码的过程中,偶然间发现Fragment#setUserVisibleHint()方法过时,所以带着好奇看了下注释如下:

/**
 * 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.
 *
 * 

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.

* *

Note: This method may be called outside of the fragment lifecycle. * and thus has no ordering guarantees with regard to fragment lifecycle method calls.

* * @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()代替,因此产生了这篇文章。

发现点

当我阅读到ViewPager#populate()计算滑动距离的方法时,最终会调用一个setPrimaryItem()方法

void populate(int newCurrentItem) {
    //... 省略超级多的代码
    calculatePageOffsets(curItem, curIndex, oldCurInfo);
    mAdapter.setPrimaryItem(this, mCurItem, curItem.object);
}

跟进看下,发现一个PagerAdapter抽象类,我们很熟知了,在我们使用VP嵌套Fragment时,经常使用它派生出的两个子类作为适配器。

AndroidX Fragment 感知生命周期
PagerAdapter.png

这两个派生出的子类中实现的setPrimaryItem()实现方式相同,我就以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;
    }
}

会发现在配置事务时,会先去if判断一下mBehavior,是否是BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,若当前的fragment为空,则setMaxLifecycle(Lifecycle.State.STARTED), 若已经创建过了,则setMaxLifecycle(fragment, Lifecycle.State.RESUMED),否则会去兼容老的setUserVisibleHint()逻辑。由前言可见setUserVisibleHint()方法过时了,因此好奇,这个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;
}

由此发现,在提交事务时,将开发者设置的LifeCycle#State枚举值存入了Op中,在最终提交事务时,根据这个State枚举去判断调用目标Fragment相关的生命周期方法,这个详细流程由于篇幅原因就不追源码了。之后我们看下这个枚举。

/**
 * 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
     * right before 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:
     * 
    *
  • after {@link android.app.Activity#onCreate(android.os.Bundle) onCreate} call; *
  • right before {@link android.app.Activity#onStop() onStop} call. *
*/ CREATED, /** * Started state for a LifecycleOwner. For an {@link android.app.Activity}, this state * is reached in two cases: *
    *
  • after {@link android.app.Activity#onStart() onStart} call; *
  • right before {@link android.app.Activity#onPause() onPause} call. *
*/ 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; } }

我们依次来看下。

  • 不设置
getSupportFragmentManager().beginTransaction()
                    .add(R.id.fl_container, mInvoiceManagerFragment)
                    .commit();
AndroidX Fragment 感知生命周期
不设置
  • CREATED
    getSupportFragmentManager().beginTransaction()
            .add(R.id.fl_container, mInvoiceManagerFragment)
            .setMaxLifecycle(mInvoiceManagerFragment, State.CREATED)
            .commit();
AndroidX Fragment 感知生命周期
CREATED
  • STARTED
getSupportFragmentManager().beginTransaction()
        .add(R.id.fl_container, mInvoiceManagerFragment)
        .setMaxLifecycle(mInvoiceManagerFragment,State.STARTED)
        .commit();
AndroidX Fragment 感知生命周期
STARTED
  • RESUMED
getSupportFragmentManager().beginTransaction()
        .add(R.id.fl_container, mInvoiceManagerFragment)
        .setMaxLifecycle(mInvoiceManagerFragment,State.RESUMED)
        .commit();
AndroidX Fragment 感知生命周期
RESUMED

所以 在设置最大周期后,最终Fragment生命周期变的可控。总结一下,

static final int INITIALIZING = 0;     // 还没有创建,初始状态
static final int CREATED = 1;          // 已创建
static final int ACTIVITY_CREATED = 2; // 完全创建但是还没有start
static final int STARTED = 3;          // 创建并启动,可见但是不能操作
static final int RESUMED = 4;          // 创建启动并且可以操作

Fragment所有的生命周期顺序:

onCreate->onCretateView->onStart->onResume->onPause->onStop-> onDestoryView->onDestory

CREATED->STARTED->RESUMED

根据注释中的LifeCycle状态注释,我们可以知道

  • CREATED
    CREATED即已创建状态,生命周期方法走到onCreate,如果当前fragment状态已大于CREATED,则会使fragment生命周期方法走到onDestoryView,如果小于CREATED,则走到onCreate。
  • STARTED
    如果当前fragment状态已大于STARTED,则会使fragment生命周期方法走到onPause,如果小于STARTED,则走到onStart;
  • RESUMED
    无论什么情况,都只调用到onResume;

ViewPager 懒加载

  • FragmentStatePagerAdapter
private static class FragmentPagerAdapter extends FragmentStatePagerAdapter {
    private final ArrayList mFragments;
    private final ArrayList mFragmentTitles;
    FragmentPagerAdapter(FragmentManager fm, ArrayList fragmentTitles, ArrayList 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;
    }
}

构造方法中传入BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT这个标记,其中有两个标记,默认为BEHAVIOR_SET_USER_VISIBLE_HINT,setUserVisible()方法是正常被调用的。

/**
 * 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中进行数据懒加载
        initLoadData();
    }
   
    private void initLoadData() {
        if (isCreate && isFirst) {
            requestData();
            isFirst = !isFirst;
        }
    }
}
声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:qvyue@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。