@martin0207
2018-12-11T08:46:42.000000Z
字数 4108
阅读 1090
android

开发过程中,不可避免的会遇到ViewPager + Fragment组合。由于ViewPager的机制,会将ViewPager容器中当前Fragment的左右两个Fragment进行初始化,生命周期到达onResume,这时候我们在Fragment写的初始化方法,早已经调用,后面的Fragment没有展示,这时候初始化对用户并不友好。
不仅如此,如果我们还想保持Fragment的存活,使用vp.offscreenPageLimit = mAdapter.count,每个Fragment的初始化再带有个网络请求……爆炸
Fragment类中,含有setUserVisibleHint(boolean isVisibleToUser)方法,该方法由系统自动调用.
我们可以通过getUserVisibleHint()方法获取Fragment当前是否对用户可见
接下来,咱们就围绕该方法对Fragment进行封装。
我们将到onResume之前的生命周期打印一下:
// 第一次创建E/LazyInitFragment: InheritZeroFragment setUserVisibleHint falseE/LazyInitFragment: InheritZeroFragment setUserVisibleHint trueE/LazyInitFragment: InheritZeroFragment onAttachE/LazyInitFragment: InheritZeroFragment onCreateE/LazyInitFragment: InheritZeroFragment onCreateViewE/LazyInitFragment: InheritZeroFragment onActivityCreatedE/LazyInitFragment: InheritZeroFragment onResume//划出(隐藏)E/LazyInitFragment: InheritZeroFragment setUserVisibleHint false//划入(展示)E/LazyInitFragment: InheritZeroFragment setUserVisibleHint true
可以看出
setUserVisibleHint默认值为false setUserVisibleHint先于生命周期方法调用 setUserVisibleHint方法中直接调用初始化方法一不小心分析出了这么多东西,条件差不多了,下面开始冻手
我总觉得,独立的文字写再多,都不如配合代码读来的真切。所以,我将想要说的内容,都放在代码的注释当中。
上面的分析可以不看,请将代码注释看的仔细些。
将lazyInit()以及Fragment在onResume及之前的生命周期状态值提取出来。
interface ILazyInitFragment {/*** fragment的状态* 延迟初始化一般都在这几种状态下(ATTACH除外)* 所以只添加了这些状态*/companion object {/*** fragment依附于Activity(默认状态)* 一般处于该状态下,不做任何操作*/const val ON_ATTACH = 0const val ON_CREATED = 1const val ON_CREATED_VIEW = 2const val ON_ACTIVITY_CREATED = 3const val ON_RESUME = 4}/*** 延迟初始化*/fun lazyInit()}
之所以费劲提取出来,是因为考虑到,已经成型的项目,替换BaseFragment类很费劲,我希望能够让Fragment只实现一个接口就可以实现这个功能。
当然,后话了。
abstract class LazyInitFragment : Fragment(), ILazyInitFragment {val TAG = this.javaClass.simpleName/*** 测试时控制生命周期的日志展示*/val mShowLog = true/*** fragment的当前状态* 用来控制lazyInit的调用*/var mCurrentState = ILazyInitFragment.ON_ATTACH/*** 调用lazyInit的状态判定* 即mCurrentState>=mLazyInitState时,调用*/fun getLazyInitState() = ILazyInitFragment.ON_ACTIVITY_CREATED/*** 是否已经初始化*/var mInitialized = false/*** 设置fragment是否对用户可见* Android自带的方法,且会自动调用*/override fun setUserVisibleHint(isVisibleToUser: Boolean) {super.setUserVisibleHint(isVisibleToUser)if (mShowLog) Timber.e("$TAG setUserVisibleHint $isVisibleToUser")doLazyInit()}override fun onAttach(context: Context?) {super.onAttach(context)mCurrentState = ILazyInitFragment.ON_ATTACHif (mShowLog) Timber.e("$TAG onAttach")doLazyInit()}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)mCurrentState = ILazyInitFragment.ON_CREATEDif (mShowLog) Timber.e("$TAG onCreate")doLazyInit()}override fun onActivityCreated(savedInstanceState: Bundle?) {super.onActivityCreated(savedInstanceState)mCurrentState = ILazyInitFragment.ON_ACTIVITY_CREATEDif (mShowLog) Timber.e("$TAG onActivityCreated")doLazyInit()}override fun onResume() {super.onResume()mCurrentState = ILazyInitFragment.ON_RESUMEif (mShowLog) Timber.e("$TAG onResume")doLazyInit()}private fun doLazyInit() {/*若达到我们设置的状态条件,则调用方法:未初始化 且用户可见 且当前状态>= 懒加载触发状态*/if (!mInitialized && userVisibleHint && mCurrentState >= getLazyInitState()) {lazyInit()mInitialized = true}}override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {if (mShowLog) Timber.e("$TAG onCreateView")mCurrentState = ILazyInitFragment.ON_CREATED_VIEWreturn inflater.inflate(getLayoutRes(), container, false)}/*** 获取fragment的布局Id*/abstract fun getLayoutRes(): Intoverride fun onPause() {super.onPause()if (mShowLog) Timber.e("$TAG onPause")}override fun onStop() {super.onStop()if (mShowLog) Timber.e("$TAG onStop")}/*** 这里是个小坑* ViewPager的规则,默认会销毁当前Fragment及左右两个之外的Fragment视图。* 即:滑到第3个Fragment时,第1个Fragment会被销毁视图,且只调用到这一步*/override fun onDestroyView() {super.onDestroyView()mInitialized = falseif (mShowLog) Timber.e("$TAG onDestroyView")}override fun onDestroy() {super.onDestroy()if (mShowLog) Timber.e("$TAG onDestroy")}override fun onDetach() {super.onDetach()if (mShowLog) Timber.e("$TAG onDetach")}}
setUserVisibleHint这个方法,之前不知道,所以卡了好长时间。Timber日志工具,也推荐使用。mShowLog设为flase。