写点什么

ViewPager 中使用 Fragment 时防止数据预加载,腾讯架构师深入讲解 Android 开发

用户头像
Android架构
关注
发布于: 2021 年 11 月 05 日

*/


public void setUserVisibleHint(boolean isVisibleToUser) {


if (!mUserVisibleHint && isVisibleToUser && mState < STARTED


&& mFragmentManager != null && isAdded()) {


mFragmentManager.performPendingDeferredStart(this);


}


mUserVisibleHint = isVisibleToUser;


mDeferStart = mState < STARTED && !isVisibleToUser;


}


以上是来自 support v4 包中的 Fragment 源码, 大概的意思是调用这个方法来设置 Fragment 当前是否是对用户可见的,这个方法只有一个参数,visible 就传 true,否则就传 false。可是在 Fragment 源码搜索发现并没有地方调用这个方法,那这个方法可能是给用户来调用的。


由此,我们可以猜想肯定是在 ViewPager 使用的过程中的某个地方调用了这个方法,我们看下 ViewPager 使用 Fragment 的流程一般是:


mAdapter = new BaseFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList);


mViewPager.setAdapter(mAdapter);


于是,我先到 FragmentPagerAdapter 的源码中搜索了下,果不其然,发现了踪迹:


@SuppressWarnings("ReferenceEquality")


@Override


public Object instantiateItem(ViewGroup container, int position) {


if (mCurTransaction == null) {


mCurTransaction = mFragmentManager.beginTransaction();


}


final long itemId = getItemId(position);


// Do we already have this fragment?


String name = makeFragmentName(container.getId(), itemId);


Fragment fragment = mFragmentManager.findFragmentByTag(name);


if (fragment != null) {


if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);


mCurTransaction.attach(fragment);


} else {


fragment = getItem(position);


if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);


mCurTransaction.add(container.getId(), fragment,


makeFragmentName(container.getId(), itemId));


}


if (fragment != mCurrentPrimaryItem) {


fragment.setMenuVisibility(false);


fragment.setUserVisibleHint(false);


}


return fragment;


}


在 instantiateItem 方法的最后我们发现了调用的地方:


if (fragment != mCurrentPrimaryItem) {


fragment.setMenuVisibility(false);


fragment.setUserVisibleHint(false);


}


这里有个判断fragment != mCurrentPrimaryItem这个时候会把 Fragment 的 Visible 设为 false, 那这个mCurrentPrimaryItem又是什么呢,继续搜索源码:


@SuppressWarnings("ReferenceEquality")


@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;


}


}


在一个setPrimaryItem的方法中找到这个变量的赋值,这个方法将传进来的 fragment 的 visible 设置为 true, 同时会更新 mCurrentPrimaryItem 变量的值。我们再继续搜索setPrimaryItem这个方法的调用,结果在当前 FragmentPagerAdapter 的源码中没有找到,但是在它的父类 PagerAdapter 的源码中找到了它的定义:


/**


  • Called to inform the adapter of which item is currently considered to

  • be the "primary", that is the one show to the user as the current page.

  • @param container The containing View from which the page will be removed.

  • @param position The page position that is now the primary.

  • @param object The same object that was returned by

  • {@link #instantiateItem(View, int)}.


*/


public void setPrimaryItem(ViewGroup container, int position, Object object) {


setPrimaryItem((View) container, position, object);


}


看注释大概明白了这个方法的含义是设置为 ViewPager 中当前展示给用户的那一页。


继续到 ViewPager 的源码中搜索,找到了调用它的地方:


![这里写图片描述](https://img-blog.csdn.net/20180823102720567?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2x5YWJjMTIzNDU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/7


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码



    是在一个populate()的方法中调用的,搜索发现好多地方调用了它,但是发现了有两个关键的地方:


    /**


    • Set a PagerAdapter that will supply views for this pager as needed.

    • @param adapter Adapter to use


    */


    public void setAdapter(PagerAdapter adapter) {


    //...忽略部分源码


    if (mAdapter != null) {


    //...忽略部分源码


    if (mRestoredCurItem >= 0) {


    mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);


    setCurrentItemInternal(mRestoredCurItem, false, true);


    mRestoredCurItem = -1;


    mRestoredAdapterState = null;


    mRestoredClassLoader = null;


    } else if (!wasFirstLayout) {


    populate();


    } else {


    requestLayout();


    }


    }


    //...忽略部分源码


    }


    /**


    • Set the currently selected page.

    • @param item Item index to select

    • @param smoothScroll True to smoothly scroll to the new item, false to transition immediately


    */


    public void setCurrentItem(int item, boolean smoothScroll) {


    mPopulatePending = false;


    setCurrentItemInternal(item, smoothScroll, false);

    用户头像

    Android架构

    关注

    还未添加个人签名 2021.10.31 加入

    还未添加个人简介

    评论

    发布
    暂无评论
    ViewPager中使用Fragment时防止数据预加载,腾讯架构师深入讲解Android开发