1.微信APP首页UI结构设计思想
交互界面
fragment渲染速度快 有缓存 attach dettach 绑定 解绑
dettach不会销毁掉fragment 只会销毁掉fragment里面的view 但是fragment仍旧存在,效率更高 生命周期更加可控 由activity管控
activity 由 ams管理
fragment 本质就是view 可以利用缓存解决 提升显示和处理效率,
都会写 如何保证他的效率 有人建议用jetpack
navigation也可以处理滑动,但是他有很多缺陷 学习成本比较高
jetpack 只是会把我们的app开发越来越简单,他把这个都封装好了
默认加载数量为什么会影响?
为什么宁愿滑动让他看到的是空白页面?提高性能?为什么能够提高性能 他是为了懒加载 为了提升性能 每个页面占用内存最少5m 页面进app的时候加载 预加载 页面看上去更加顺滑 舒服,先加载进来 没有显示之前我进行加载,那么以头条为例 头条一个页面至少是5m 假设 加载5个页面 要加载25m数据,每一个页面的显示要很多内存 如果有预加载 一上来加载网络数据 缓存数据 需要内存 不要预加载 而是用懒加载 滑动当前页面 只是显示空白页面 结果会损失用户的观赏性,但是他并不会影响性能 会节约能量,节约内存 节约cpu 让我们app滑动的时候不会卡顿,
最早的是pageview 小米 推出功能 让用户惊艳 、
为什么设置预加载 因为当时是3g 网络很慢 想办法先加载数据
现在是4g 5g了 网络随处存在 越来越快 viewpager viewpager2默认是懒加载的
技术在变化的
navigation paging 只是把功能集中起来,不算是技术的革新
现在如果没有短视频 不算是好app
2.ViewPager 预加载原理解析
移动端变化非常快 ,学不动也要学 学不动就被淘汰
viewpager 是view ,viewpager 我要适配的是viewpager上面的内容 为什么fragment可以 因为fragment本质也是view 本质懂得原理
知识体系理解 viewpager只能显示view activity 本质不是view
fragment对view的封装不是继承 而是组合
activity 本质是上下文 会有很多上下文的变量context 整个包含着运行的上下文 管理上下文 学东西一定学本质
viewpager如何管理这些view 呢 是设计思想 pageadapter 适配器模式,vsaicview 和viewpager算不算?不算 那个是别人写好的
网络请求 bean 如何string'转bean 如果不是gson xml 自定义序列化格式呢?
服务端 给你返回的数据 它里面包含词汇 null为空的时候 可能测试环境给你返回的是null 在生产环境呢返回时{} 或者# 他是null没问题 如果是# 是谁的问题?为什么ios为什么没有问题 就是数据的adapter适配的问题,我们没有设置好这个数据,典型的序列化 序列化 所使用的技术 原理 包括gson的原理 他最终都是使用的适配器模式 ,考虑各种情况 各种异常 把有益的数据留下来 把没用的数据去拦截没用的数据,把有用的数据留下来 这个地方就必须用适配器模式 如果没学过看gson源码 一个一个适配 get set 看原理 理解源码
viewpager如何适配view呢 使用的是populate函数 populate其实就是对adapter 适配器的调度 适配器发生什么东西呢?
adapter有很多函数 准备适配 正在适配 销毁一个item 把某一个item设置成为一个当前的item
finishupdate 就是调用这几个函数 在populate怎么调用呢?判断它我要开始了适配
有开始适配就有finishupdate
完成适配这个过程是怎么样的呢? 当我滑动界面的时候 会发生
滑动页面之后,当前页面是5 原来的当前页面现在缓存了 原来的缓存页面销毁了,同时原来的销毁页面7现在加入进来变成了 缓存页面
基于当前页面,把当前页面做中间页面,然后左右两边页面适配 就是适配缓存的过程
看源码的方向 看看他是如何做适配左右两边的
进入这个函数之后先做适配工作
第一次进入页面 一个页面也没有,先add一个页面进来
初始化一个页面,作为当前要显示的页面,👆 默认的一个页面
左右适配的过程
先计算左边需要适配页面的数量 然后用for循环去适配左边的页面,在适配左边的页面的时候,
第一个缓存有没有 够不够? 够的话缓存就不管了,左边有没有销毁掉,如果销毁掉 我就把你销毁掉,所以
左边需要销毁的页面remove掉
如果需要添加缓存页面就用addnewItem
开始缓存👆 这个时候 通过adapter 调用instantiateitem 然后构建一个object
如果这个fragment 没有被销毁,这个时候就只需要attach一下👇
为什么fragment!=null 就只需要attach一下 attach生命周期意味着什么?
如果这个fragment =null 这个时候需要getitem 所以需要去实现getitem 通过getitem我传的是fragment 创建了构建fragment 然后把这个fragment visiblehint 设置为false 然后把这个fragment 返回,也就是说这个instantiateitem他返回的是fragment 换句话说 他这个二objetc 是fragment
他会把这个fragment 填入到iteminfo里面 在 ii 会填入到mitems里面 mitems是arraylist
通过arraylist add的方式 会把这个item add进来 所以换句话说,我们viewpager 对view 的缓存是怎么缓存的 用一个arraylist 保存进来的
左滑的时候,如果2不在缓存范围之内了,所以这个时候要去缓存,
去缓存👆
需要把当前的fragment 4切换成fragment5 怎么去切换?需要又给setprimaryitem
通过把当前的页面展示出来,而这个当前的setprimaryitem做什么事?
把原来的fragment 4设置成非当前的,然后再把5设置成当前的,5是以前就缓存了的,所以现在我就是把界面4设为不可见00133,把5设置可见, 00137
finishUpdate调用了commit
setUSerVisibhint没有调show 看他生命周期
我add 00105 的时候 fragment 会走什么生命周期? 什么生命周期都不会走 因为这个过程是迭代器 触发器 mcurtransaction 没有atatch 所以
在finishupdate执行attch的时候 就会在这个触发器里面所有缓存 的保存的行为 去完成一次全面的触发 只有finishupdate才会走他的生命周期 所以在这个时候 setprimaryitem的时候我觉得目的不是让他show 我的目的是告诉用户这个页面不可见,00137 最终谁可见?谁不可见 commit的时候00146 他来处理
思考本质 记住本质 需要时间去学习
当我去instantiateItem 的时候,这个fragment 走他这个add过程 add走完之后他会走fragment .setuservisiblehint 0110
然后在我这个setprimaryitem的时候00128 也会走setuservisiblehint00137
setuservisiblehint 就变成非常重要的标志 标志一个
当我们去进行viewpager的缓存的时候 缓存第一个会缓存页面,第二个是会设置当前页面,销毁页面,对于我们来说我们 什么时候会加载数据
当我们缓存页面的时候 add fragment的过程 在这个过程里面会触发fragment的加载 在这个add fragment的过程 他会触发数据加载 ,而这个数据加载 就会是我们的预加载
设置当前页面的时候干什么事情? 他是调用setuservisiblehint来表明这个fragment是否可见, setuservisiblehint=true说明这个fragment可见 为false 说明不可见
这个时候我们就可以setuservisiblehint 给这个状态值 来进行懒加载代码实现
可以通过setuservisiblehint这个值来进行懒加载的代码实现,
避免预加载 显示的时候加载,不显示的时候不加载,
fragment加载数据 activity的生命周期和fragment的生命周期的关系
activity在oncreate后加载数据,在onresume 为什么你的fragment不在onresume 呢?
因为fragment的生命周期oncreate oncatvcreatd 都属于 activity的oncreate的声明周期
onresume对应的生命周期就是fragment的onresume 吗?既然你的activity可以在onresume里加载 你为什么fragment不在onresume加载?统一的管理嘛
activity 启动流程 启动优化 wms 启动 分析 ams 拓扑结构
onresume里面加载数据,现在懒加载,需要懒加载加载方案,那么我们还能在onresume展示数据吗? 不能够用 ,如果所有的数据都在onresume去加载,那么我们能够控制fragment加载过程吗?控制不了fragment的加载过程 那么怎么控制懒加载? 懒加载不就是控制这个加载过程 让他只有在可见的时候才加载 不可见不加载,所以这个时候我们不能够把加载数据的动作丢给onresume 这个生命周期来完成,
如何控制呢?
为什么变成空函数 而不是abstract?面向对象设计思想
单一职责原则 规范 如果有一个类 fragment 它并不想实现懒加载,只是他是一个basefragment 所以我才继承了他 这个时候他不需要去实现 load 和loadstop 这两个函数 那么意味着,他就会 自己在自己的onresume去实现,所以不让他变成抽象函数,
dispathchUserVisibleHint:为什么单独定义一个函数 其实是由拓展的原因的 后面讲
第二点:onCreateVieW是fragment 的view创建过程,他返回一个view 为什么他返回一个view?
fragment本身他是一个view fragment其实就是对view的封装
所以onCreateView return 给00208 他 创建这个view 为了避免内存抖动 定义rootView;
为什么避免内存抖动呢? 为什么解决内存泄漏 其实跟生命周期有关 我们的这个fragment 和activity是不同的,fragment 的生命周期,他会有一个,detach:他并不会让fragment销毁的,同时我们activity在fragment里面除了在ondetach 他还有一个生命周期 只会让这个view进行一个重新加载 并不会把这个view销毁掉,不会走view的 destory这个函数,这个onCreateView所创建的这个view 他更多的重新给他加载数据,而不是重新让他xml解析,如果频繁的调用onCreateView的生命周期,他就会频繁的每一次,如果没有这个判断,而且每次都会解析xml 解析 rootview 把这个rootview 又重新赋值给00208 而这个view 他其实已经创建来的 所以这个时候他就频繁的把创建的新解析的这个里面,他会把原来的那个view 就像 我这边定义一个view = new view 频繁的调用new 这个view 如果频繁的调用这个函数,本来这个view 已经存在了,你只需要改数据,就可以重新显示了,但是你非得new 一个view重新给他,意味以前的那个view 就会被gc 而这个过程就会带来 创建new 销毁 下次又new 又导致以前的销毁 因为这个地方决定他的生命周期决定他的这个view 并不一定 每次都销毁 很多时候他不消毁 他可以复用的,这个是fragment的源码特性告诉我们的,所以我们需要做这个事情,getLayoutRes是一个抽象函数,为什么他是一个抽象函数? 必须是由子类去完成,因为这个地方我解析xml 32 -35 这个xml到底是什么样子呢?由子类去提供给我 当然除了提供xml之外 还有一个函数叫initView(rootView); 我为什么要提供这个函数也是抽象函数?为什么?
我真正要懒加载这个view 我知道长相是怎么样的 这个长相只有我知道,所以必须是抽象的
initview 我xml解析出来 我是不是要findviewbyid 提供个东西给我用?所以initview 我必须实现个抽象的
调用栈 这个是在ViewPager.populate里面分发出去的,他这个事件是由ViewPager里面发送出去,ViewPager怎么发送出去呢?
当populate的时候一上来 先调用 mAdapter.startUpdate(this) 然后接下来会调用00958 这行代码.
如果curitem=null 也就是说我刚 第一次进入fragment的时候,第一次进入这个app的时候,这个时候就会默认给他创建一个fragment 当他默认创建fragment的时候这个fragment instantiateItem
在instantiateItem里面执行setUserVisibleHint(false);
页面还没有创建 他运行的是flase
对应的调用这个函数, 就导致了这个分发事件,也就是说在我onCreateView生命周期在执行之前,这个函数没执行的时候 他就执行了setUserVisibleHint
dispathchUserVisibleHint(isVisble: false)
为什么先执行setUserVisibleHint函数 为什么没有先执行onCreateView
这个地方不是 把这个fragment add到进来了吗? add进来会触发我们的fragment 一旦调用mCurTransaction.add就会触发 fragment的oncreatview onresoum onactivitycreated 这些函数都会执行吗?
为什么先执行 fraCIment,setUserVisibleHint (fa1se) 00110这个函数?
我没有走 00144这个 地方,所以导致先执行setUserVisibleHint这个函数,执行完之后当他去走这个finishUpdate的时候 这个时候执行commitnow 执行完commitnow 的时候,这个时候他才会真正执行这个00105add工作,所以oncreate 会晚于setUserVisibleHint的生命周期,当你在setUserVisibleHint调用onFragmentLoadStop的时候,报异常 所以这个时候我们就需要加一个判断
view是否创建
只有创建了我才需要分发这一系列事件 否则一概不管 ,这个时候我直接用这个rootview这个变量行不行啊?不行,为什么?每一个变量干一件事
每一个人的职责是不同的,所以不要为了代码少 而把这个变量共用
在代码界 你的代码写的好不好是你的逻辑和思想
而不是代码多与少 一个activity 打天下他类很少 他是好代码吗?
不是 用mvvm 用mvp构建的
虽然他很多类很多接口,但是他结构清晰 易于拓展 activity
isViewCreated什么时候会false 一定要记住,在他走生命周期结束的时候 ondestory的时候
一直处于loding是什么原因?
loding是我默认提供的界面
生命周期管理的原因 导致setUservisblehint先调用 先调用完后才会走finishUpdate 走finishUpdate 才会走fragment的生命周期
页面1跳页面4 4跳2也没问题,
开机页面1跳到页面4 也没有问题,
如果 注销isViewCreated =false 页面5消失 跳2 加载 其他页面不应该缓存数据,
页面2加载两次数据,
混乱了 页面5跳过来的 5停止加载 2加载 其他东西都不用管,所以2停止了一次 更新了一次 更新了两次,更新两次意味着两次网络请求 页面1停止 页面三停止 1和3应该是页面2加载的时候缓存页面,缓存页面 不管他就对了,跟数据没有关系 所以混乱了 因为懒加载的状态没搞清楚,什么是懒加载?最大的问题在于严谨性不够
加载前 可见的时候加载:之前不可见 现在可见 从不可见变成可见 这个时候加载,
不可见的时候不加载:之前可见&现在不可见 这个时候停止加载有一个切换状态的一瞬间
两个前后的状态
保存之前的可见状态👆
现在可见 setUserVisibleHint true 51
不可见变成可见 不可见为false 55
再页面1跳3 没问题 从5跳2 2更新了2次
我补了一次dispathchUseiVeHint(isVisbfe: true) 补了一次又加载进来了,本来自己有 又再补了一次
不符合之前不可见 现在可见加载 所以这一个判断在这 57生效了👇 在 39 40没生效
两个办法 第一个办法加判断:
策略 不断的优化 画图也不好解决 是思想问题 一个一个代码加进去是非常严谨的 如果自己网上cp 网上代码
下次能写出来吗?cv 1-2年 技术有提升 后面再也没提升
6.activity 介入懒加载的原理
fragment 跳转activity然后又返回fragment数据会重新加载
懒加载是思想
头条进页面每次都更新吗 时间更新
50min更新
拉 更新
第一次 上次更新的时间 我记录这个时间
下次要不要分发?
所有代码 都是这个过程 app架构 不要期待一口气胖子 逐步 文章来源:https://www.toymoban.com/news/detail-469749.html
等等再看 立刻学习 时间挤出来了 程序员时间是最宝贵的文章来源地址https://www.toymoban.com/news/detail-469749.html
到了这里,关于1.微信APP首页UI结构设计思想viewpager的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!