十二、其他
ATask
BlackMagic
开发中的黑魔法,提高开发效率,同时显得高大上
Job
跳槽求职面试
BlackMagic_Reverse
逆向
参考文章:
1 | <script type="text/javascript"> |
1 | <div id="header"></div> |
1 | 如何抽离出公用的部分呢?(有点类似Vue,React等框架的组件化)我选的是运用jquery的load方法,还有很多其他方法,如iframe ,include等等网上都能搜到。 |
主要是启动耗时,处理的主要方式是
代码方面:
其他方面:
排查工具:Time Profiler
及时释放(不要只持有,但不释放,如避免单例持有大对象)
autorelease
大量小对象 → 一次性加载/渲染过多 cell、图片、富文本。(Cell 复用)
少量大对象 → 单个对象占用内存非常大(加载大图/视频,例如单张图片 100MB,或一个大 Data blob)
短时间内创建大量对象或加载大资源,造成内存占用过多,可能引发系统回收甚至崩溃。
示例:
JSON 解析时递归错误,不断循环创建对象;
请求没做分页/单页数量极大(之前遇到为了省去Flutter中列表的数据处理,直接单页请求4000个数据)
加载大图,大图直接解码显示原始位图,占用内存太大。优化:Downsampling(缩放解码),只解码需要显示的尺寸/缩略图,而不是原图全尺寸。
1 解码成位图 (bitmap): 4000 x 4000 图片 (RGBA8888) = 4000 * 4000 * 4 bytes ≈ 64 MB
之前在发布内容时候(Flutter应用)涉及到多视频的压缩
内存抖动(Memory Churn):
APP 被系统 Kill(Jetsam):
排查工具:Instruments 的 Leaks 和 Allocations 分析内存泄漏
1、正确的地方使用 reuseIdentifier
2、内存泄漏
1、使用Product-Analyze分析内存泄
利用Product-Analyze分析内存泄露,并不能把所有的内存泄露查出来,因为有的内存泄露是在运行时,用户操作时才产生的。那就需要用到Instruments了。
《卡顿监控.md》
《列表优化.md》
《网络框架.md》
后台得到符合指定条件的所有记录,然后再截取位置。常见的截取位置方法为分页和指定第几页。
为避免请求非第一页数据时候,后台在得到符合指定条件的所有记录和第一页得到的不一样,需要前台或者后台需要记录与第一页一样的请求时间。
常见方案:
| 备注 | ||
|---|---|---|
| pageIndex | ||
| pageSize | 缺点:只能index变,size不能变,不然返回的数据会错误 | |
| timestamp | 此为优化点,为的是避免请求非第一页数据时候,后台在得到符合指定条件的所有记录和第一页得到的不一样 没此参数的时候,后台应该是缓存了第一次请求后所有记录,只有再次重新请求或过期才释放这些所有记录。 |
timestamp 的记录方式:
1、后端记录(需要结合过期时间)
需要结合过期时间,以处理为每个用户记录的这个第一页请求时间。有额外开销
2、前端记录
缺点:需要集合过期时间
信息方法1:上次最后一条的id,此方法不通。因为新增的记录后台id目前已经不是自增的了
信息方法2:上次最后一条的modifyTime,此方法可以,前提需要后台的时间单位为更为精确的mm级或者um等。
结论:此时所需字段如下
| 不需要,已通过最后一条的modifyTime 处理 | ||
| 不需要,已通过最后一条的modifyTime 处理 | ||
| 最后一条的modifyTime | ||
| pageSize | 可灵活变动 |
管理相关:详见管理相关 主要包含以下内容。
账号管理
目录结构规范的必要性在于:
- 便于团队协作:在团队协作中,规范的目录结构可以让所有人都能够快速地找到他们需要的文件和资源,提高开发效率。
- 便于维护:有一致的目录结构可以让项目更易于维护。例如,如果您需要添加一个新的功能,您可以很快地找到添加到哪个文件夹中。
- 可读性更高:良好的目录结构可以让代码更易于阅读和理解,这对于代码的维护和升级非常重要。
在项目开发中,基础框架分层是非常重要的,可以帮助我们将代码分成多个层次,每个层次都有自己的职责和责任,从而提高代码的可维护性、可扩展性、可重用性和可测试性。同时,基础框架分层也可以帮助我们解耦不同部分的代码,减少代码之间的依赖关系,从而提高代码的灵活性和可靠性。
解耦的必要性在于:
- 减少代码之间的依赖关系:解耦可以帮助我们减少代码之间的依赖关系,降低代码的耦合度,从而提高代码的灵活性和可靠性。
- 提高代码的可维护性:解耦可以帮助我们将代码分成多个独立的部分,每个部分都有明确的职责和责任。这样,我们可以更容易地测试、修改和维护应用程序的不同部分,从而提高代码的可维护性。
- 提高代码的可扩展性:解耦可以帮助我们将应用程序的不同部分分离开来,以便于单独测试和修改。这样,我们可以更容易地扩展应用程序的功能和特性,而不会影响到其他部分的代码。
- 提高代码的可重用性:解耦可以帮助我们将可复用的代码和组件集中在公用组件层中,方便其他部分的代码进行复用。
Flutter 空安全(Null Safety)是指在代码中添加了对空值的非空断言、空值检查等机制,从而使代码更加健壮和安全性。Flutter 空安全升级的必要性主要体现在以下几个方面:
因此,Flutter 空安全升级是非常必要的,它可以提高代码的健壮性和安全性,改进开发体验,为未来的 Flutter 版本做好准备,并适应 Dart 语言的发展。
以下是一些在不升级 Flutter 空安全的情况下可能出现的问题或隐患:
因此,升级 Flutter 空安全是非常必要的,它可以提高应用程序的健壮性和安全性,改进用户体验,提高代码的可读性、可维护性和可扩展性,并减少开发过程中出现的错误和异常。
详见:app打包保证
主要处理问题:
1、操作日志:app记录所有的记录,方便排查,接入游戏的地方也要有日志 [p1]
2、崩溃率、卡顿检测 [p1]
3、app接入apm [p2]
弱网测试:
5、全站埋点:有现成工具最好,从核心业务开始 [p2]
4、值班:记录每个人的能力,碰到问题找对应的人,值班热线电话号码,24小时随时待命 【p0】
项目应包含以下分支:
master
该分支为项目主分支,此分支只作为稳定版本发布使用,不允许在此分支上修改 bug ,开发功能等。并且该分支每次发布时需根据项目的版本号打上 tag ,例如 v1.0.0。
develop
该分支为各开发人员的开发合并分支,各开发人员在各自开发分支/功能分支/bug分支上开发/调试代码,完成相关工作后即可合并到 develop 分支,不允许各位在此分支上直接开发。此分支无需打 tag 。
qa-test
该分支是交由 QA 进行测试的分支,每次交由 QA 测试时,从 dev 分支合并到该分支,合并的最后一次 commit 需要打 tag ,例如 v1.0.0-test-num,num 为 1.0.0 版本提交测试的序号。QA 测试稳定后,merge 到 master 并打上 tag,待发布。
feture_xxx
该分支用于开发新功能,比如新版本迭代时,有一个较大的功能模块,可以不在 dev_hzxxx 分支开发,相关开发同学可在此类分支上开发,有两个优点:(1)可以多人协同 (2)可以防止模块较大时导致原来代码混乱。
issue_xxx
该分支用于解决 jira 上 bug,修改完成并验证后合并到 dev 分支,等待 QA 验证。
说明:关于以上 feature_xxx 和 issue_xxx 分支的使用说明可以根据实际情况进行参考,不是规定死的,在开发过程中有疑问可以跟大家讨论。
1 | master |
在前一节 弱网测试 中,我们罗列了网络测试的各种问题。而本节我们针对弱网单独的进行说明。
本节的其他参考文章:
API接口增加缓存
针对不同的网络:做不同超时,重试设置,以及取不同质量的图片数据。
图片降低质量
弱网下:如何让我们的app不受弱网的影响,以使得用户能够继续”正常”使用我们的网络?
通过竞品分析,App网络测试&竞品对比.xlsx,测试各APP在各相同网络环境下的表现。对存在的不足进行发现和优化。
看看其他APP都是在什么网络(什么值)下大概不行?
| 最佳网络质量 | 开始出现问题 | 基本不可用的网络 | |
|---|---|---|---|
| 带宽(kbps) | > | > & < | > & < |
| 丢包率(%) | < | > & < | > & < |
| 延迟(ms) | < | > & < | > & < |
对此我们从弱网下的事件开始前、事件执行中及事件执行结束对结果的处理三个阶段来分析。
| 阶段 | 概述 | 处理位置 | 优化方案 |
|---|---|---|---|
| 1 | 弱网下,事件开始前可考虑的优化 | 数据上 | 用户体验优化 + 网络状态/网络质量 |
| 2 | 弱网下,事件执行过程中可考虑的优化 | 数据上 | 缓存 + 降低质量 |
| 3 | 弱网下,事件执行结束对结果的处理可考虑的优化 | 界面上 | UI和Toast的显示 |
原图为 

从上图中,可以看出弱网情况下,我们可以针对不同的网络:做不同超时,重试设置,以及取不同质量的图片数据。
1、网络类型从wifi切换到移动网络/无网络时,全局Toast提示用户当前联网类型切换为移动网络/无网络。
2、弱网情况下(下行网络质量低于某个阀值)提示用户当前网络较差,请检查网络状态。
弱网下的事件结果,主要体现在界面上。尤其是UI提示、toast提示
针对请求超时/请求失败,常见的提示方式有UI提示、或者toast提示。而常出现的可考虑优化的场景如下:
| 序号 | 问题类型/可优化点 | 优化建议 | 优化方案具体描述 |
|---|---|---|---|
| 1 | 弱网view、弱网toast同时都存在 | 只保留弱网view | 请求接口时,自己处理业务失败的toast,而非底层自动toast 接口异常:①业务异常仍然toast、②超时异常去除toast |
| 2 | 弱网view、弱网toast同时不存在 | 至少有弱网toast | 页面接口请求可允许使用底层自动toast机制 |
| 3 | 同接口弱网超时,连弹弱网toast | 优化连弹/重叠 | 接口针对异常区分超时类型,toast使用对应单例优化连弹但不重弹 |
| 4 | 弱网超时\无网,页面空数据兼容 | 兼容空数据 | ①补充空页面 ②点击无反应 –> 改为提示”后台数据异常” |
为了找到确实需要处理的优化点,我们可以在以下表格中先整体罗列弱网下的所有可能是异常的页面,然后再评估哪些需要处理。表格样式如下:
| 优化点概述 | 优化点详细说明 | 待优化处截图/视频 | 页面路径 | 错误重现 | 是否需要处理 | 备注 | 状态 |
|---|---|---|---|---|---|---|---|
待优化处截图/视频示例:
1、提取APP中现有的本地toast。
为此我专门写了个脚本:获取文本中的某些文本并将其整理到excel中:https://gitee.com/dvlpCI/package-size-resource/blob/master/Flutter/example_get_file_some_text.sh
整理的表格完成版示例如下:
https://gitee.com/dvlpCI/package-size-resource/blob/master/Flutter/APP提示语清单表.xlsx
APP提示语清单表:
| 文件(简) | 行号 | 提示文案 | 文案类型 | 触发路径及条件 | 提示方式 | isUse 是否使用中 (//判断) |
创建者 | 修改者 |
|---|---|---|---|---|---|---|---|---|
| xxx_page.dart | 128 | 复制成功 | 成功 | TRUE | ||||
| xxx_page.dart | 81 | 抱歉:图片上传失败 | 失败 | TRUE | ||||
| xxx_page.dart | 105 | 请选择物流公司 | 提示 | TRUE | ||||
| xxx_page.dart | 891 | 正在开发中… | 未确定 | TRUE |
网络区分的方式,主要有网络类型、网络质量。
| 切入点类型(及其原理) | 适用的使用场景 | 库 | 参考文档 | |
|---|---|---|---|---|
| 1 | 实时检测网络类型变化 (移动网络、wifi网络、无网络) |
可在网络类型变化,提示用户注意当前网络环境 | connectivity_plus | Flutter检查连接网络connectivity_plus实现步骤 |
| 2 | 检测网络的可达性和网络延迟时间,探测信号强度。附:Ping测试不能测量网络的带宽容量,只反映延迟。 原理:通过发送ICMP(Internet Control Message Protocol)回显请求到服务器,并测量回显响应的时间,来评估网络的延迟(Ping值)。 |
dart_ping | Flutter Ping检查服务器通讯信号强度实现步骤 | |
| 3.1 | 测试设备的网络速度(包括上传和下载速度) 原理:从选定的服务器下载一定大小的数据包来测试下载速度。测试时会记录下载所需的时间,并据此计算出下载速度。上传计算同理。 |
flutter_internet_speed_test | 见库自身地址 | |
| 3.2 | 测试设备的网络速度(包括上传和下载速度)![]() |
NERTC SDK | 通话前网络质量探测 |
附:上述部分库的使用示例详见: 附1:网络类型、网络质量部分库的使用示例
流程中的优化空间:我们以网络类型、网络质量决定体验的原则,来分析,使得在不同网络状态下,可以有不同的用户体验。
体验举例:
| 处理内容 | 低弱网下处理 | 强弱网下处理 |
|---|---|---|
| 图片 | 加载抵制图:1倍图 | 直接全不加载 |
| 视频 | 降低清晰度 | 直接不播放 |
我们从页面加载流程探索弱网优化的空间。
其中以上述图片加载渲染流程为例(加载视频同理),其过程如下:
1 | // 初始化 |
1 | final ping = Ping('baidu.com', count: 5, interval: 1); // count: ping的次数 interval:每几秒ping一次 |
打印结果:
