一、介绍

Fragment是Android3.0以后引进,称为碎片。它与Activity非常相似,用一个Activity中描述一些行为或者一部分用户界面,使用多个Fragment可以在一个单独的Activity中建立多个UI面板,也可以在多个Activity中使用Fragment。

Fragment的引入主要是处理UI展示,所以在理解的时候,可以将它理解成布局控件,常见的fragment搭配有:

1.引入布局,作为布局中控件,通过fragmentmanager来控制

2.导航内容:Navigation组件

3.作为viewpage的子view:viewpage

二、功能介绍

1.作为布局

作为布局控件,加载到布局中展示,通过我们先把fragment开发完毕,然后在Activity中加入即可。

通过fragmentManage提交进去。

getSupportFragmentManager().beginTransaction().add(R.id.fragment,fragments).commitNow();

这种做法是最常见的,但是如何判断当前fragment的是否已添加进去呢?通过isAdd()方法。

注意:

很多人在使用这种方法,特别是延迟处理和耗时处理的回调,发现当前fragment被销毁了,如果处理这些可以通过isAdd()来判断一下。避免对象销毁,业务还在进行。

2.ViewPager

Viewpage是我们比较常见的,fragment作为viewItem使用,但是viewpage的滑动功能,导致会对fragment进行提前加载到内存的机制,如果不提前添加进行,在滑动计算是一个不好控制的局面。

正常的Activity都是当前窗口只有一个,如果是fragment可能出现多个,这就会导致提前加载会引起View的提前曝光,数据提前请求等,这和所见即所得还有有区别的。这个就需要我们去理解这个懒加载机制,当页面真的添加,并展示出来才会处理。这里面只是介绍了懒加载与viewpage存在的问题,为什么会,接下我们会核心的去介绍懒加载。

3.导航Navigation

关于导航的使用,可以查看我的以前文章:

Android JetPack底部导航Navigation 组件的介绍与使用_android 导航_蜗牛、Z的博客-CSDN博客

三、懒加载

想知道懒加载,先要了解fragment的一些特性。

1.require:

在获取变量的时候,不能调用这个方法,否则会抛异常

会主动给你检查一下,对空指针直接抛异常,这就会导致在复杂的场景下,应用的兼容性更差,特别是在kotlin语言中,不懂的以为都是调用一样,其实不然。

2.页面可见

2.1添加:

fragment是作为view控件来使用的,虽然 看似与Activity有着一样的方法与功能,但是不能单独存在,它自身是没有窗口,依托Activity来完成。

选配:Viewpage+FragmentPagerAdapter

这里面的adapter选取了FragmentPagerAdapter,FragmentPagerAdapter对PagrAdapter进行了扩展,在页面的提交和保活做了支持。

FragmentPagerAdapter的创建:

创建的时候behavior有两种

public static final int BEHAVIOR_SET_USER_VISIBLE_HINT = 0;
public static final int BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT = 1;

第一种,behavior=0在页面创建通过调用setUserVisibleHint

第一种,behavior=1在页面创建通过调用setMaxLifecycle(fragment, State.STARTED)

正常,我们通过setUserVisibleHint来判断页面,那么在创建adapter的时候,behavior默认是0.

fragment:

在fragment中,我们需要处理

override fun setUserVisibleHint(isVisibleToUser: Boolean) 

的回调。

FragmentPagerAdapter

2.2源码分析

由于fragment在viewpage中相当于view,viewpage又是一个支持滑动的,所以viewpage提供了一个

1.public void setOffscreenPageLimit(int limit)

的方法,默认至少需要提前初始化一个。

所以,在初始化的时候,回调的

override fun setUserVisibleHint(isVisibleToUser: Boolean)

默认都是false。只有在adapter

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

中才会去确定做回调

当adapter回调时,这时,我们的fragment在ViewGroup中处于可见状态。

至于setUserVisibleHint(isVisibleToUser: Boolean)回调多少次false,取决于

setOffscreenPageLimit(int limit)的大小。

2.初始化规则是:

从选中位置开始,左右两边初始化limit个,如果左右两边的数量小于limit

左边:Math.min(currentIndex,limit),右边Math.min(count-currentIndex,limit)

最多一次初始化=limit*2+1;最后会落在currentIndex的fragment上。

懒加载核心

第一种:behavior=0

setUserVisibleHint(isVisibleToUser: Boolean),在fragment创建的时候,都会收到回调为false。

懒加载的核心是所见即所得,显然isVisibleToUser为false不是我们想要的结果。所以我们应该在fragment记录上一次的状态,如果状态不一致,可以肯定当前页面没有发生变化,页面没变化,直接不处理任何数据逻辑。即,当前页面是不可见。

    override fun UserVisibleHint(isVisibleToUser: Boolean) {if (visibleToUser == isVisibleToUser)returnMyLog.log("lazy", "===${isVisibleToUser}")visibleToUser = isVisibleToUserarguments?.let {MyLog.log("lazy", "${it.get("key")}===${isVisibleToUser}")}}

所以日志输出,只有当前选中的页面,其他都被拒了

    override fun initView() {adapter= MyViewPageAdapter(list,supportFragmentManager)bind.myviewpage.offscreenPageLimit=2bind.myviewpage.adapter=adapterbind.myviewpage.currentItem=5}

这样,当 UserVisibleHint(isVisibleToUser: Boolean)回调为true,当前fragment是可见的。

第二种:behavior=1

当behavior=1是,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT

Adapter走的LifecycleRegistry进行监听,状态也是通过lifecycle进行回调。

所以:

在fragment的源码中也有进行解释。

fragment

在adapter中,如果当前fragment可见,回到的状态是:RESUME

所以:我们只要进行监听:

     (lifecycle as LifecycleRegistry).addObserver(object : LifecycleEventObserver{override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {}})

从日志可以看出Event

  1. CREATE,START:当页面被创建,首先回调的是这两个状态
  2. RESUME:当前页面可见
  3. PAUSE:从可见到不可见
  4. STOP:页面被销毁

所以,当你采用behavior=1时,只需要判断RESUME这个即可。

参考Demo:

abstract class BaseLazyFragment<V : ViewDataBinding> : Fragment() {var visibleToUser: Boolean = falselateinit var bind: Voverride fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {bind = DataBindingUtil.inflate(inflater, getLayoutResId(), container, false)return bind.root}override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)arguments?.let { initData(it) }(lifecycle as LifecycleRegistry).addObserver(object : LifecycleEventObserver{override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {onStateChangeds(source,event)}})}override fun setUserVisibleHint(isVisibleToUser: Boolean) {super.setUserVisibleHint(isVisibleToUser)UserVisibleHint(isVisibleToUser)}@LayoutResabstract fun getLayoutResId(): Intabstract fun UserVisibleHint(isVisibleToUser: Boolean)abstract fun initData(bund: Bundle)abstract fun  onStateChangeds(source: LifecycleOwner, event: Lifecycle.Event)}
class MyLazyChildFragment : BaseLazyFragment<MyLazyViewBind>() {override fun getLayoutResId(): Int {return R.layout.fragment_lazy_test}var key = ""var mEvent: Lifecycle.Event? = nulloverride fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)activity?.runOnUiThread {arguments?.let {bind.textTitle.text = "当前页面序号${it.getString("key")}"}}}override fun initData(bund: Bundle) {bund?.let {key = it.getString("key", "")}}override fun UserVisibleHint(isVisibleToUser: Boolean) {if (visibleToUser == isVisibleToUser)returnvisibleToUser = isVisibleToUserarguments?.let {MyLog.log("lazy", "${it.get("key")}===${isVisibleToUser}")}}override fun onStateChangeds(source: LifecycleOwner, event: Lifecycle.Event) {MyLog.log("lazy", "${key}===Event=${event.name}")if (mEvent == event)returnmEvent = eventif (mEvent == Lifecycle.Event.ON_RESUME) {MyLog.log("lazy", "${key}===Event=${event.name},可见")}else{MyLog.log("lazy", "${key}===Event=${event.name},不可见")}}companion object {@Synchronizedfun getInstance(index: Int): Fragment {var fragment = MyLazyChildFragment()var bundle = Bundle()bundle.putString("key", "${index}")fragment.arguments = bundlereturn fragment}}}

Adapter:

class MyViewPageAdapter : FragmentPagerAdapter {var list = mutableListOf<Fragment>()constructor(list: MutableList<Fragment>, fm: FragmentManager) : super(fm,BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {this.list = list}override fun getCount(): Int {return list?.size}override fun getItem(p0: Int): Fragment {return list?.get(p0)}
}

Page的初始化:

    override fun initView() {adapter= MyViewPageAdapter(list,supportFragmentManager)bind.myviewpage.offscreenPageLimit=1bind.myviewpage.adapter=adapterbind.myviewpage.currentItem=5}

注意:

Demo的代码是kotlin与DataBinding写法,在代码demo整理的时候需要小心,不会这两种语法的可以查看我的文章。

Android Fragment懒加载机制分析与详解相关推荐

  1. Fragment的懒加载与生命周期详解

    提示:本文仅为笔者学习记录 Fragment的懒加载与生命周期详解 什么是懒加载 了解Fragment的生命周期 onAttach onCreate onCreateView onActivityCr ...

  2. android fragment加载布局的方式,Android中Fragment的加载方式与数据通信详解

    Android中Fragment的加载方式与数据通信详解 发布时间:2020-08-22 18:55:57 来源:脚本之家 阅读:155 作者:Joah 一.加载方式 1. 静态加载 1.1 加载步骤 ...

  3. Android——Fragment懒加载

    Fragment懒加载 简述 LazyFragment 简述 大部分APP框架由一个单例MainActivity和多个Fragment组成:在实际开发中常使用BottomNavigationView+ ...

  4. Android Fragment懒加载

    懒加载思路 在Fragment布局创建的时候调用懒加载方法,创建之后将isViewPrepared设置为true. /**标记Fragment视图是否已经初始化完毕*/private boolean ...

  5. Android 6种加载网络图片的第三方详解

    一. Glide加载 Glide.with(this).load("http://p0.qhimg.com/t015f3654b694ad2f8a.jpg").into(image ...

  6. 【Android】再来一篇Fragment懒加载(只加载一次哦)

    本篇文章已授权微信公众号 dasu_Android(大苏)独家发布 使用前需知 2017-7-14更新: 目前有人使用后出现了诸如首次打开显示空白界面,但点击有反应:或来回切换又变空白界面的问题.这些 ...

  7. Android apk动态加载机制的研究(二):资源加载和activity生命周期管理

    转载请注明出处:http://blog.csdn.net/singwhatiwanna/article/details/23387079 (来自singwhatiwanna的csdn博客) 前言 为了 ...

  8. Fragment 懒加载

    为何懒加载 在很多 App 都会有ViewPage + Fragment 的基本组合,但是众所周知 viewPager 的 预加载机制,即使设置函数 setOffscreenPageLimit(0) ...

  9. 带你深入了解Fragment懒加载

    Fragment懒加载是一种优化技术,用于在Android应用中延迟加载和初始化Fragment的内容,以提高应用性能和用户体验.它的核心思想是只有在Fragment可见时才加载数据和执行相关操作,而 ...

最新文章

  1. 计算机网络知识点1——计算机网络概述
  2. Java实现类似C/C++中的__FILE__、__FUNC__、__
  3. 重定向和转发之间的区别
  4. 分而治之_编写干净的测试–分而治之
  5. 美团科技 Java工程师_美团Java工程师面试题(2018秋招)
  6. Hibernate自动事务揪出的编码不规范
  7. 嵌入式linux设备驱动程序是,嵌入式Linux设备驱动开发之:按键驱动程序实例-嵌入式系统-与非网...
  8. Spring Rdbms操作(二)——SqlFunction 获取表数据条数
  9. python lambda函数 与 函数式编程
  10. MATLAB 工具箱傻瓜式求解 NS(Navier Stoke)方程
  11. 【LKJ】LKJ2000型记录装置显示界面说明
  12. Profinet IO设备
  13. Pickit 3D视觉定位抓取系统 -硅步机器人
  14. 深度学习CTR模型粗略记录
  15. 酷派改变者S1(C105/C105-6/C105-8) 解锁BootLoader 并刷入recovery root
  16. 蓝桥杯2017 包子凑数
  17. vue纯前端增删改查分页
  18. 关于springmvc静态资源常被忽视,有可能致命的点
  19. 流媒体分析之rtmp协议srs服务器数据收发
  20. 数学 {有界性定理,最值定理,零点定理,介值定理}

热门文章

  1. LeetCode 297. 二叉树的序列化与反序列化 | Python
  2. oracle创建dblink连接达梦
  3. Buck工作原理分析,连续模式,断续模式
  4. 相机(Camera)图标缺失
  5. 《点亮ISINK三色灯》
  6. How to be a under-graduate student
  7. linux,centos7.2,/etc/profile文件详解
  8. 我的世界e 服务器怎么注册,我的世界E世界RPG生存服 电脑版1.6.2群组云服务器
  9. 企业使用多大的光纤宽带合适呢-光纤接入
  10. 沪股通连续八日净流入 累计净流入58.67亿元