ViewPager 懒加载 lazyload

 ViewPager 懒加载 lazyload

abstract class LazyFragment5() : Fragment() {
    lateinit var fragmentDelegater: FragmentDelegater
    lateinit var root: View
    var isViewCreated = false
    var isVisibleToUser = false
    var isVisibleStateLastTime = false  //TODO 4 增加变量 需要在onPause onResume中判断 onDestroyView管不了了

    abstract fun i(str: String)
    abstract fun initView()
    abstract fun getLayoutRes(): Int
    abstract fun onFragmentLoadData()
    abstract fun onFragmentStopLoadingData()
    fun set(fragmentDelegater: FragmentDelegater) {
        this.fragmentDelegater = fragmentDelegater
    }

    // TODO 1.2
    fun dispatchUserVisibleHint(state: Boolean) {
        if (state && isParentInvisible())     //TODO 5.2 过滤后inner fragments不会加载数据 停止加载了  ×××××××  判断 state 没用 不需要
            return
        if (state) {
            isVisibleStateLastTime=true
            onFragmentLoadData()
            dispatchChildVisibleState(true)   //TODO 5.2 解决
        } else {
            isVisibleStateLastTime=false
            onFragmentStopLoadingData()
            dispatchChildVisibleState(false)   //TODO 5.2 解决
        }
    }
    //TODO 5.2 解决
    private fun dispatchChildVisibleState(state: Boolean) {
        val childFragmentManager = childFragmentManager
        val fragments = childFragmentManager.fragments
        if (fragments!=null){
//            fragments.foreach
            for ( fragment in fragments){
                if (fragment is LazyFragment5  && ! fragment.isHidden  && fragment.userVisibleHint && !(fragment as LazyFragment5).isVisibleStateLastTime){ //TODO  要加这个 isVisibleStateLastTime   cast 竟然是 多余的
                    (fragment as LazyFragment5).dispatchUserVisibleHint(state)
                }else if(fragment is LazyFragment5  && ! fragment.isHidden  && !fragment.userVisibleHint && (fragment as LazyFragment5).isVisibleStateLastTime){// TODO 要加这个 isVisibleStateLastTime
                    (fragment as LazyFragment5).dispatchUserVisibleHint(state)
                }
            }

            /*for (fragment in fragments) { // 循环遍历 嵌套里面的 子 Fragment 来分发事件操作
                if (fragment is LazyFragment5 &&
                    !fragment.isHidden() &&
                    fragment.getUserVisibleHint()
                ) {
                    (fragment as LazyFragment5).dispatchUserVisibleHint(state)
                }
            }*/
        }
    }

    // 判断fragment是否可见  TODO 1.1
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        i("setUserVisibleHint isVisibleToUser: $isVisibleToUser")
        // isVisibleToUser为true,viewpager中呈现该page,可见,其他不可见
        //onCreateView之后,才可以更新UI,if(isViewCreated && isVisibleToUser)
        //第一个默认显示的page 在onCreateView之后 会再执行本方法,会执行到下面
        //但可以控制其他的缓存的fragment不加载数据,即懒加载数据,
        //这是加载数据 的入口,运行处
//        if(isVisibleToUser  ){
//            if (isViewCreated)
//            onFragmentLoadData()
//
//        }else{
//            onFragmentStopLoadingData()
//        }

//        this.isVisibleToUser = isVisibleToUser // get方法代替声明flag标记  getUserVisibleHint()
        /*if (isViewCreated) {   //移到 onCreateView中 默认选中的page会加载,已缓存的、执行了ligecycle的就不会执行了  放2个?
            if (isVisibleToUser) {
//                onFragmentLoadData()
                dispatchUserVisibleHint(true)
            } else {
//                onFragmentStopLoadingData()
                dispatchUserVisibleHint(false)
            }
        }*/
//        if (isParentInvisible())  //TODO 5.1 检查放到dispatch里边 ×××××    可以放这 ×××××× 为防止切换activity 在pause resume中还有dispatch  只判断它就可以
//            return                  // TODO 这两行包括本方法 仅限制数据的加载与停止,不限制lifecycle方法包括resume 预加载界面
        if (isViewCreated) {  // TODO view create后才能更新数据
            if (isVisibleToUser && !isVisibleStateLastTime) {  // TODO 4 从不可见到可见     onDestroyView里的赋值不需要了
                dispatchUserVisibleHint(true)
            } else if (isVisibleStateLastTime && !isVisibleToUser){  //TODO 4 直接else不可以, 必须从可见到不可见,否则会多余地执行 停止加载数据
                dispatchUserVisibleHint(false)
            }
        }

    }

    // TODO 5
    fun isParentInvisible():Boolean{
        val parentFragment= parentFragment
        if (parentFragment is LazyFragment5)
        {
            val fragment =parentFragment  // as LazyFragment5   No cast needed
            return !fragment.isVisibleStateLastTime

        }
        return false
    }
    //TODO 5
    //TODO 5      t2 有个viewpager 里面有4个fragment 。显示到t1时,t2里的 内部fragments会加载数据 停止加载数据
    //TODO 5     Fragment2_vp_1: 20 fragment -> onCreateView -> isVisibleToUser: true ->  onFragmentLoadData 开始加载数据
    // ->onActivityCreated -> Fragment2: 2 fragment -> onStart  ->  Fragment2_vp_1: 20 fragment - onStart
    // ->   Fragment2: 2 fragment - onResume   ->   Fragment2_vp_1: 20 fragment - onResume
    // ->Fragment2_vp_1: 20 fragment - setUserVisibleHint isVisibleToUser: false
    // ->   Fragment2_vp_1: 20 fragment - onFragmentStopLoadingData 将暂停一切操作
    // ->Fragment2_vp_1: 20 fragment - setUserVisibleHint isVisibleToUser: true
    // ->Fragment2_vp_1: 20 fragment -> onFragmentLoadData 开始加载数据

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        i("onCreateView")
        root = inflater.inflate(getLayoutRes(), container, false)
        initView()

        isViewCreated =
            true  //FragmentPagerAdapter只销毁fragment视图   FragmentStatePagerAdapter销毁fragment对象,
        // 为应对FragmentPagerAdapter,应在onDestroyView 置isViewCreated为false   TODO 3 t3 切换到t1 再从t1 切换t3 时 t4会执行停止加载
        //  TODO 3 因为没有销毁掉已经缓存的 isViewCreated==true,再执行setUserVisibleHint(false)就会执行一次onFragmentStopLoadingData()
        //  TODO 3 解决 在onDestroyView 置isViewCreated为false
        //  TODO 3 或者加上一个 isVisibleStateLastTime成员变量 确认从可见到不可见 或 从不可见到可见 才执行数据加载 或 停止加载
        //  TODO 3 dispatchUserVisibleHint(state: Boolean)中 赋值isVisibleStateLastTime=state  并在setUserVisibleHint 修改如下
        /*if (isViewCreated) {

            // TODO 3 记录上一次可见的状态: && isVisibleStateUP
            if (isVisibleToUser && !isVisibleStateLastTime) {
                dispatchUserVisibleHint(true)
            } else if (!isVisibleToUser && isVisibleStateLastTime) {
                dispatchUserVisibleHint(false)
            }
        }*/
//        if(isViewCreated)  TODO 可以不用写,这时一定 为true
        /*if (isVisibleToUser && !isVisibleStateLastTime) {
            dispatchUserVisibleHint(true)
        } else {
            dispatchUserVisibleHint(false)
        }*/
        // TODO userVisibleHint 为false,fragment不可见,可能走lifecycle,默认fragment时 为true 再走lifecycle
        // TODO 缓存的fragment 为false 后会走lifecycle 为true 就可见了
        if (userVisibleHint) this.setUserVisibleHint(userVisibleHint) //this.dispatch  xxx  // TODO 2.1 代替下面再写一次代码  去其中判断
                                                                                            // TODO 默认的fragment先hint 为true,再走lifecycle,错过setUserVisibleHint的时机,修正,挽回
//        if (isViewCreated) {
//            if (isVisibleToUser) {
                onFragmentLoadData()
//                dispatchUserVisibleHint(true)
//            } else {
                onFragmentStopLoadingData()
                dispatchUserVisibleHint(false)  // TODO 第一版 这会产生bug,textview 会显示 退出加载数据
//                                                        // 已缓存的fragment,由于hint为false,到onCreateView,,就会执行到这 ,注释掉
//            }
//        }
        return root

    }

    override fun onDestroyView() {
        isViewCreated = false    // TODO 3
        super.onDestroyView()
        i("onDestroyView")
    }


    override fun onAttach(context: Context) {
        super.onAttach(context)
        i("onAttach")
    }

    override fun onPause() {

        super.onPause()
        i("onPause    isHidden: $isHidden")
        if (userVisibleHint && isVisibleStateLastTime) {  //TODO 4 从可见到不可见
            dispatchUserVisibleHint(false)
        }
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        i("onActivityCreated")
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        i("onCreate")
    }

    override fun onStart() {
        super.onStart()
        i("onStart    isHidden: $isHidden")
    }

    override fun onResume() {
        super.onResume()
        i("onResume    isHidden: $isHidden")
        if (userVisibleHint && !isVisibleStateLastTime) {  //TODO 4 从不可见到可见
            dispatchUserVisibleHint(true)
        }
    }

    override fun onDetach() {
        super.onDetach()
        i("onDetach")
    }


    override fun onAttachFragment(childFragment: Fragment) {
        super.onAttachFragment(childFragment)
        i("onAttachFragment")
    }


    override fun onStop() {
        super.onStop()
        i("onStop")
    }

    override fun onDestroy() {
        super.onDestroy()
        i("onDestroy")
    }



//注意 position 和 index 差1 ,映射menu item Image 、pager item,handler tabIndex ,menu item Image别映射错了

//第二点  tabIndex 与Fragment 共同打印log,放在static里 companion object里 共享由于生命周期方法先于tabIndex赋值语句执行,
// 所以打印的多个fragment的几个生命周期方法的tabIndex全为0,
// 所以将tabIndex在构造函数中传入赋值,init中,可行,不知道先执行init 还是super()
// (先有父类,再有子类,先 调用super() 父类构造方法,这时会执行声明周期方法?
// 不一定,setUserVisibleHint()先于lifecycle ,不过是自带方法,不在viewpager,创建后,也没有关联attach到activity,就不会执行lifecycle了吧)
// 或在viewpager fragment的setUserVisibleHint()方法执行时,赋给tabIndex值 ,
// 使用viewpager时,这个方法 先于 生命周期方法执行,之后再执行一次,执行两次
// setOffscreenPageLimit 为2时,1 2 3 fragment为false,
// 然后1 为true,开始执行各fragment的声明周期,其他的2 3 不为true,也执行lifecycle方法,界面等相关,再然后加载数据getData()加载数据
//切换page时,当前page true 变 false ,目标 和 缓存页面 为false若已执行则不再执行,再然后目标page 为 true
//setUserVisibleHint()为true时,已缓存的fragment可能已执行了相关lifecycle 方法,未缓存的,第一次加载的 则没有执行,


open class MyFragment(position:Int) : LazyFragment5() {


     var iv: ImageView? =null  // TODO 在 Fragment5中 lateinit property iv has not been initialized
     var tv: TextView? =null
    var tabIndex: Int? = 0//声明 放在 init前面 否则找不到  Variable cannot be initialized before declaration
                            //或放在setUserVisibleHint() 也行 但会多次执行
init {
    tabIndex=position
}

    companion object{
        val POSITION = "position"
        fun newInstance(position: Int): MyFragment {
//        var bundle= Bundle()
            val bundle = bundleOf(Pair(POSITION, position))

            var fragment = MyFragment(position)
            fragment.fragmentDelegater = FragmentDelegater(fragment)
            fragment.arguments = bundle
            return fragment
        }
    }

    override fun initView() {
        if (root != null) {
            iv = root.findViewById(R.id.iv_content) as ImageView
            tv = root.findViewById(R.id.tv_loading) as TextView
            tabIndex = arguments?.getInt(POSITION)
        }

    }

    override fun getLayoutRes(): Int {
        return R.layout.fragment_lazy_load
    }

    override fun i(info: String) {
        if (fragmentDelegater != null) {   //always true
            fragmentDelegater.dumpLifeCycle(
                "BAT ${this.javaClass.simpleName} ",
                "$tabIndex fragment -> $info"
            )
        }
    }

    override fun onFragmentLoadData() {
        i("onFragmentLoadData 开始加载数据")
        getData()
    }

    override fun onFragmentStopLoadingData() {
        i("onFragmentStopLoadingData 将暂停一切操作")
        handler.removeMessages(10)
        if (timer !=null){
            timer.cancel()
        }
        tv?.visibility=View.VISIBLE
        tv?.text="退出加载数据"
    }

    override fun onResume() {
        super.onResume()
//        getData()  //TODO 第0版 都加载数据,不做懒加载,不做控制
    }

    private fun getData() {

        timer.start()
    }
    var timer = object : CountDownTimer(1000, 100) {
        override fun onFinish() {
            handler.sendEmptyMessage(0)
        }

        override fun onTick(millisUntilFinished: Long) {

        }

    }
//    companion object {

        var handler: Handler = object : Handler(Looper.myLooper()!!) {
            override fun handleMessage(msg: Message) {
                var drawableId: Int = 0
                when (tabIndex) {
                    1 -> drawableId = R.drawable.a
                    2 -> drawableId = R.drawable.b
                    3 -> drawableId = R.drawable.c
                    4 -> drawableId = R.drawable.d
                    5 -> drawableId = R.drawable.a

                }
//                if (iv!=null){
                iv?.setImageResource(drawableId)
                iv?.visibility = View.VISIBLE
//                }
//                if (tv !=null){
                tv?.visibility = View.GONE
//                }

                //模拟耗时操作
//                try {
//                    Thread.sleep(1000)
//                }catch ( e:InterruptedException){
//                    e.printStackTrace()
//                }

            }
        }
//    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值