当前位置:网站首页>Summary of mobile page optimization in seconds
Summary of mobile page optimization in seconds
2022-08-01 03:04:00 【Little Sheep Chong Chong Chong Chong】
前言
App优化,是一个工作、面试或KPI都绕不开的话题,如何让用户使用流畅呢?今天谨以此篇文章总结一下过去两个月我在工作中的优化事项到底有那些,优化方面还算小白,有不对的地方还望指出海涵, 该文章主要通过讲述Native跳转到Flutter界面秒开率提升.
问题分析
当你拿到反馈App页面渲染时间长的工单的时候,第一步想到的不应该是有那些那些方法可以降低耗时,我们应该根据自己的真实业务触发,第一步 验证 通过打点或者工具去验证这个问题,了解 一个页面打开耗时的统计方式,分析一个打开耗时是由那些方面组成,通过那些技术手段去解决80%的问题,抓大放小去处理问题.
通过工具分析启动链路耗时,发现部分必要接口RT时间较长,Flutter引擎冷启耗时较长和View渲染耗时为主要耗时项.接下来就围绕着三个大方面去做一些优化.
网络优化
以Android 界面跳转链路来说 ,具体链路看下图(模拟数据 主要明白思想)
看到串行,就知道这里肯定可以有文章做
可以看到在网络请求可以提前到 Router环节去解析并进行预加载,并行的话可以优化 必要接口RT的时长,节省的时间在页面秒开链路中占比最多.
在这里需要兼容网络返回较慢的情况,我们可以引入骨架图,提升上屏率.
数据预请求
Router和请求
通过拦截路由地址,判断路径是否属于预请求白名单.如果匹配,进入预请求逻辑,发起网络拼接和请求,在获取到结果进行本地缓存,供消费界面去消费.因为考虑到网络返回如果慢与界面,可以提供回调,消费界面进来进行绑定.
端侧通讯
由于Native 跳转到 Flutter ,所以这里需要借助 Channel来进行管道传递,这里我们没有使用MethodChannel 而是选择 可以Native主动通知Flutter 的EventChannel来接收消息.
public class EventChannelManager implements IFlutterProphetPlugin {
private static Map<String, EventChannel.EventSink> cachedEventSinkMap = new HashMap<>();
private static LinkedList<Object> dataList = new LinkedList<>();
public final static String CHANNEL_REQUEST_PRE = "event_channel";
private static EventChannelManager instance;
public static EventChannelManager getInstance() {
if (null == instance) {
instance = new EventChannelManager();
}
return instance;
}
@Creator
public static IFlutterProphetPlugin create() {
return new EventChannelManager();
}
//初始化
@Override
public void initChannel(FlutterEngine engine) {
try {
EventChannel eventChannel_pre = new EventChannel(engine.getDartExecutor(), CHANNEL_REQUEST_PRE);
eventChannel_pre.setStreamHandler(new ProphetStreamHandler(CHANNEL_REQUEST_PRE));
} catch (Exception ex) {
Log.e(TAG, "init channel err :" + ex.getMessage());
}
}
//发送消息
@Override
public void sendEventToStream(String eventChannel, Object data) {
synchronized (this) {
try {
EventChannel.EventSink eventSink = cachedEventSinkMap.get(eventChannel);
if (null != eventSink) {
eventSink.success(data);
} else {
dataList.add(data);
}
} catch (Exception ex) {
}
}
}
//关闭
public void cancel(String eventChannel) {
EventChannel.EventSink eventSink = cachedEventSinkMap.get(eventChannel);
if (null != eventSink) {
eventSink.endOfStream();
}
}
public static class ProphetStreamHandler implements EventChannel.StreamHandler {
private String eventChannel;
public ProphetStreamHandler(String eventChannel) {
this.eventChannel = eventChannel;
}
@Override
public void onListen(Object arguments, EventChannel.EventSink events) {
cachedEventSinkMap.put(eventChannel, events);
if (dataList.size() != 0) {
for (Object obj : dataList) {
events.success(obj);
}
dataList.clear();
}
}
@Override
public void onCancel(Object arguments) {
cachedEventSinkMap.remove(eventChannel);
}
}
}
上述代码为通用EventChannel创建和发送消息工具类,接口不贴了…
缓存
预请求模块中,如果网络请求结果成功,可以将结果写入缓存SDK中(可以根据缓存SDK策略,内存和磁盘缓存都做好处理).结合缓存策略,再次进入界面即可先读取缓存数据上屏,通过顶部Load状态提醒用户 预请求的数据正在加载中,来缩短秒开时间.
端智能
通过大数据和算法对用户习惯性的使用链路进行分析,判断用户下一个节点将会进入哪个界面,匹配到预请求白名单,也可以更早的进行预请求逻辑 (没有集团SDK支撑的话可以不列为主要优化方式).
数据后带
以自己维护的App来说,首屏商品列表会返回很多数据包括但不限于:商品Url、商品名称、价格等核心信息,在进入商品详情中,我们通常会把商品id发送到详情界面,并再次进行商品详情接口的请求,那么我们可以通过数据后带的方式,先让详情页核心数据显示出来,然后通过局部骨架图来等待详情信息的返回,感官上缩短界面等待时长.
数据延后
首屏中还会有很多二级弹窗列表数据接口的请求,其实这里的接口可以通过延后的方式来加载并渲染出来,减少首屏刚开始的CPU使用,为核心View渲染让步,减少CPU竞争.
业务逻辑优化
部分不重要接口除了可以延后处理外,还可以通过推动后端合理缩小数据结构,减少不必要的网络消耗产生.对于部分小量接口,可以通过搭车的方式 进行接口合并 一块返回,部分数据可能不需要实时更新的,可以减少不必要请求来进行优化.
布局优化
异步加载
假设场景是搜索结果列表,我们可以在数据请求前置的同时,去异步 inflate 一些 recyclerview 的 itemview,渲染阶段就可以节约 createViewHolder 的时间.(这里只是进行一个场景举例,更多的使用方法和业务强耦合,需要自行分析和合理设计避免负向优化)
递进加载
顾名思义,其实递进加载和数据延后请求原理相似,每个界面可能都会有重要View,以商品列表为例,我可能更希望商品列表数据先返回回来,其他的接口可以延后,提升界面渲染速度.
其他优化
TODO 文章不断完善中,文章思想比重较多,欢迎大佬们互相讨论
边栏推荐
- HIRO: Hierarchical Reinforcement Learning 】 【 Data - Efficient Hierarchical Reinforcement Learning
- 解决IDEA默认情况下新建文件时,右击,new,没有XML文件的问题
- 链式编程、包、访问权限
- 【uniCloud】云对象的应用与提升
- IDEA does not recognize the module (there is no blue square in the lower right corner of the module)
- MYSQL master-slave replication
- Unity在BuildIn渲染管线下实现PlanarReflection的初级方法
- pdb药物综合数据库
- Chinese version of Pylint inspection rules
- 一个service层需要调用另两个service层获取数据,并组装成最后的数据,数据都是list,缓存如何设计?
猜你喜欢
Beijing suddenly announced that yuan universe big news
How to download the Keil package
leetcode: 1562. Find latest grouping of size M [simulation + endpoint record + range merge]
IDEA modifies the annotation font
Ordinary users cannot access HGFS directory
Data Middle Office Construction (VII): Data Asset Management
IDEA does not recognize the module (there is no blue square in the lower right corner of the module)
项目越写越大,我是这样做拆分的
Elastic Stack的介绍
【uniCloud】云对象的应用与提升
随机推荐
MYSQL transactions
How is the tree structure of the device tree reflected?
785. Quick Sort
情人节浪漫3D照片墙【附源码】
初出茅庐的小李第114篇博客项目笔记之机智云智能浇花器实战(3)-基础Demo实现
IDEA 找不到或无法加载主类 或 Module “*“ must not contain source root “*“ The root already belongs to module “*“
pdb药物综合数据库
带你体验一次类型编程实践
Browser download shortcut to desktop (PWA)
Soft Exam Senior System Architect Series: Basic Knowledge of Information Systems
手写二叉查找树及测试
【搜索专题】看完必会的BFS解决最短路问题攻略
RTL8762DK RTC (5)
787. 归并排序
Unity在BuildIn渲染管线下实现PlanarReflection的初级方法
Daily practice of LeetCode - Circular linked list question (interview four consecutive questions)
更换树莓派内核
Flink deploys and submits jobs
[cellular automata] based on matlab interface aggregation cellular automata simulation [including Matlab source code 2004]
Guys, MySQL cdc source recycles replication slave and r in incremental process