前言

无论是启动,内存,布局等等这些优化,最终的目的就是为了应用不卡顿。应用的体验性好坏,最直观的表现就是应用的流畅程度,用户不知道什么启动优化,内存不足,等等,应用卡顿,那么这个应用就不行,被卸载的概率非常大。所以说为了保证用户留存率,卡顿优化是非常非常的重要。在这篇文章,咱们不讨论是什么原因造成卡顿,其实在前面写的性能优化文章中,都是造成卡顿的原因,需要需要做好卡顿优化,最好从头开始一步一步来处理。今天我们主要是介绍一些针对卡顿检测的一些工具使用。

检测卡顿常用工具

Systrace

Systrace这个工具在《布局优化》一章节中已经介绍过了,这里就不在赘述。地址:https://www.cnblogs.com/huangjialin/p/13353541.html

StrictMode的使用

StrictMode,严苛模式。StrictMode是在Android开发过程中不可缺少的性能检测工具,它能够检测出在开发过程中不合理的代码块,非常方便。

策略分类

StrictMode分为线程策略(ThreadPolicy)和虚拟机策略(VmPolicy)

使用方式
 //开启Thread策略模式
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectNetwork()//监测主线程使用网络io
// .detectCustomSlowCalls()//监测自定义运行缓慢函数
// .detectDiskReads() // 检测在UI线程读磁盘操作
// .detectDiskWrites() // 检测在UI线程写磁盘操作
.detectAll()
.penaltyLog() //写入日志
.penaltyDialog()//监测到上述状况时弹出对话框
.build()); //开启VM策略模式
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
// .detectLeakedSqlLiteObjects()//监测sqlite泄露
// .detectLeakedClosableObjects()//监测没有关闭IO对象
// .setClassInstanceLimit(MainActivity.class, 1) // 设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露
// .detectActivityLeaks()
.detectAll()
.penaltyLog()//写入日志
.build());

上面基本都注释好了,这里就不在一一说明了。如果我们在开发过程中,能够通过StrictMode这个工具类来规避掉这些问题,那么将会大大的减少很多性能相关的问题。

BlockCanary使用

我们先看看怎么使用,然后在看BlockCanary

依赖

debugImplementation 'com.github.bzcoder:blockcanarycompat-android:0.0.4'

在application中

BlockCanary.install(mContext, appBlockCanaryContext).start();

appBlockCanaryContext类

/**
* BlockCanary配置的各种信息
*/
public class AppBlockCanaryContext extends BlockCanaryContext { /**
* Implement in your project.
*
* @return Qualifier which can specify this installation, like version + flavor.
*/
public String provideQualifier() {
return "unknown";
} /**
* Implement in your project.
*
* @return user id
*/
public String provideUid() {
return "uid";
} /**
* Network type
*
* @return {@link String} like 2G, 3G, 4G, wifi, etc.
*/
public String provideNetworkType() {
return "unknown";
} /**
* Config monitor duration, after this time BlockCanary will stop, use
* with {@code BlockCanary}'s isMonitorDurationEnd
*
* @return monitor last duration (in hour)
*/
public int provideMonitorDuration() {
return -1;
} /**
* Config block threshold (in millis), dispatch over this duration is regarded as a BLOCK. You may set it
* from performance of device.
*
* @return threshold in mills
*/
public int provideBlockThreshold() {
return 500;
} /**
* Thread stack dump interval, use when block happens, BlockCanary will dump on main thread
* stack according to current sample cycle.
* <p>
* Because the implementation mechanism of Looper, real dump interval would be longer than
* the period specified here (especially when cpu is busier).
* </p>
*
* @return dump interval (in millis)
*/
public int provideDumpInterval() {
return provideBlockThreshold();
} /**
* Path to save log, like "/blockcanary/", will save to sdcard if can.
*
* @return path of log files
*/
public String providePath() {
return "/blockcanary/";
} /**
* If need notification to notice block.
*
* @return true if need, else if not need.
*/
public boolean displayNotification() {
return true;
} /**
* Implement in your project, bundle files into a zip file.
*
* @param src files before compress
* @param dest files compressed
* @return true if compression is successful
*/
public boolean zip(File[] src, File dest) {
return false;
} /**
* Implement in your project, bundled log files.
*
* @param zippedFile zipped file
*/
public void upload(File zippedFile) {
throw new UnsupportedOperationException();
} /**
* Packages that developer concern, by default it uses process name,
* put high priority one in pre-order.
*
* @return null if simply concern only package with process name.
*/
public List<String> concernPackages() {
return null;
} /**
* Filter stack without any in concern package, used with @{code concernPackages}.
*
* @return true if filter, false it not.
*/
public boolean filterNonConcernStack() {
return false;
} /**
* Provide white list, entry in white list will not be shown in ui list.
*
* @return return null if you don't need white-list filter.
*/
public List<String> provideWhiteList() {
LinkedList<String> whiteList = new LinkedList<>();
whiteList.add("org.chromium");
return whiteList;
} /**
* Whether to delete files whose stack is in white list, used with white-list.
*
* @return true if delete, false it not.
*/
public boolean deleteFilesInWhiteList() {
return true;
} /**
* Block interceptor, developer may provide their own actions.
*/
public void onBlock(Context context, BlockInfo blockInfo) {
Log.i("lz","blockInfo "+blockInfo.toString());
}
}

就是这么简单,一旦发生卡顿,那么将会以通知的形式在通知栏中显示出对应的堆栈信息(和leakcanary类似,但是两者没有任何关系)。或者在

SD卡中的blockcanary文件夹中生成对应的log日志

那么,问题来了BlockCanary是怎么检测卡顿的呢?大家注意AppBlockCanaryContext类中有一个provideBlockThreshold()方法,return了一个500ms。我们知道Android中消息的分发处理都是通过handler来的,handler中有一个looper对象,looper对象中有一个loop方法,看一下源码

...

 for (;;) {
Message msg = queue.next(); // might block
...//省略若干
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
} ...//省略若干 try {
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...//省略若干 if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
} ...//省略若干
} ...

应用中的所有事件都是通过dispatchMessage这个方法来进行处理,那么是不是说dispatchMessage执行的时间就是某个事件执行的时间。如果这个时间大于我们在provideBlockThreshold()定义的时间,我们就认为发送了卡顿了,需要优化,就会获取到对应的堆栈信息保存起来并提示。

ANR-WatchDog介绍

发生卡顿,严重时很容易导致anr,我们知道发生anr的情况基本上就是以下几种情况

1、触摸事件在5s没有得到响应。

2、Bradcast 是10s,后台广播是60s

3、service:前台service 20s 后台service 200s

用户在使用应用时,出现ANR,那么体验将会是非常非常差,现在很多手机厂商为了用户体验,去掉了这个ANR弹框,但是还是会一直卡在这里。

ANR-WatchDog 使用

添加依赖

implementation 'com.github.anrwatchdog:anrwatchdog:1.3.0'

在application中的onCreate()方法

new ANRWatchDog().setIgnoreDebugger(true).start();

setIgnoreDebugger 是指忽略点断点的情况

当然如果这样设置的话,一旦出现ANR,那么ANR-Watchdog是会将应用杀死的,如果不想杀死应用那么需要设置一个监听

new ANRWatchDog().setANRListener(new ANRWatchDog.ANRListener() {
@Override
public void onAppNotResponding(ANRError error) {
// Handle the error. For example, log it to HockeyApp: }
}).start();

ANR-WatchDog 原理

我用自己的话来总结一下原理:前面我们说了所有的消息都是通过handler中的dispatchMessage方法进行分发的,而ANR-WatchDog 原理就是通过dispatchMessage的时间长度来判断是否出现anr的,过程大概是这样的:ANR-WatchDog 开启一个监控线程,并向主线程发一个消息,然后自己休眠5s,5s后看主线程有没有处理这个消息,如果处理了,那么继续发送,进入一下次检查。如果没有处理,说明主线程发生了阻塞,收集对应的anr信息。

Lancet的介绍

前面写的几篇性能优化文章基本都介绍有对应的hook框架,这里再介绍一个AOP框架---Lancet,这几个框架的比对,后面会再开一篇。这里先看看怎么使用。Lancet是一个轻量级Android AOP框架,特点:

1、编译速度快,并且支持增量编译

2、简洁的API,几行代码完成注入需求

3、没有任何多余代码插入apk

4、支持用于SDK,可以在SDK编写注入代码来修改依赖SDK的APP

使用方式

在根目录的build.gradle

dependencies{

classpath 'me.ele:lancet-plugin:1.0.5'

}

在APP目录的build.gradle

apply plugin: 'me.ele.lancet'

dependencies {

provided 'me.ele:lancet-base:1.0.5'

}

开一个类aaaa.java

@Proxy("i")

@TargetClass("android.util.Log")

public static int anyName(String tag, String msg){

msg = msg + "lancet";

return (int) Origin.call();

}

这样,就完成了,当我们通过Log.i("lancet","你好“);来打印日志的时候,输出的文本先被Lancet出来后,在输出。"你好,lancet"

常见卡顿问题解决方案

1、内存抖动的问题,GC过于频繁

2、方法太耗时了(CPU占用)

3、布局过于复杂,渲染速度慢

....

Android性能优化----卡顿优化的更多相关文章

  1. android中app卡顿优化问题

     所谓app卡顿原因就是在运行时出现了丢帧,还可能是UI线程被阻塞.首先来一下丢帧现象,android每16ms会对界面进行一次渲染,如果app的绘制.计算等超过了16ms那么只能等下一个16ms才能 ...

  2. Android TextView setText卡顿问题

    TextView 是经常使用控件之中的一个,最经常使用的方法是setText()  . 可是 我们在显示大量的文本的时候,使用setText还是会有一些性能的问题. 这篇文章 关于TextView的s ...

  3. android TextView SetText卡顿原因

    [android TextView SetText卡顿原因] 不要用wrap_content即可. 参考:http://blog.csdn.net/self_study/article/details ...

  4. Android 界面滑动卡顿分析与解决方案(入门)

    Android 界面滑动卡顿分析与解决方案(入门) 导致Android界面滑动卡顿主要有两个原因: 1.UI线程(main)有耗时操作 2.视图渲染时间过长,导致卡顿 目前只讲第1点,第二点相对比较复 ...

  5. Android 卡顿优化 2 渲染优化

    1.概述 2015年初google发布了Android性能优化典范,发了16个小视频供大家欣赏,当时我也将其下载,通过微信公众号给大家推送了百度云的下载地址(地址在文末,ps:欢迎大家订阅公众号),那 ...

  6. Android 卡顿优化 1 卡顿解析

    1, 感知卡顿 用户对卡顿的感知, 主要来源于界面的刷新. 而界面的性能主要是依赖于设备的UI渲染性能. 如果我们的UI设计过于复杂, 或是实现不够好, 设备又不给力, 界面就会像卡住了一样, 给用户 ...

  7. Android 卡顿优化 3 布局优化 工具 Hierarchy Viewer

    欲善其事, 先利其器. 分析布局, 就不得不用到Hierarchy Viewer了. 本文工具使用皆以GithubApp的详情界面RepoDetailActivity为例说明. 为了不影响阅读体验, ...

  8. Android 布局渲染流程与卡顿优化

    文章内容概要 一.手机界面UI渲染显示流程 二.16ms原则 三.造成卡顿的原因 四.过度绘制介绍.检测工具.如何避免造成过度绘制造成的卡顿 一.手机界面UI渲染显示流程 大家都知道CPU(中央处理器 ...

  9. GC 卡顿 优化 三色标记优势

    小结: 1. 三色标记的一个明显好处是能够让用户程序和 mark 并发的进行 Go GC 卡顿由秒级降到毫秒级以下:到底做了哪些优化? https://mp.weixin.qq.com/s/2BMGG ...

随机推荐

  1. 文档翻译经验分享(Markdown)

    该教程基于VSCode 加一些插件 youdao translate https://marketplace.visualstudio.com/items?itemName=Yao-Translate ...

  2. 【实践】如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统)

    如何利用tensorflow的object_detection api开源框架训练基于自己数据集的模型(Windows10系统) 一.环境配置 1. Python3.7.x(注:我用的是3.7.3.安 ...

  3. Spring Security(二) —— Guides

    摘要: 原创出处 https://www.cnkirito.moe/spring-security-2/ 「老徐」欢迎转载,保留摘要,谢谢! 2 Spring Security Guides 上一篇文 ...

  4. Flutter 中渐变的高级用法

    Flutter 中渐变有三种: LinearGradient:线性渐变 RadialGradient:放射状渐变 SweepGradient:扇形渐变 看下原图,下面的渐变都是在此图基础上完成. Li ...

  5. 一文说清 KubeSphere 容器平台的价值

    KubeSphere 作为云原生家族 后起之秀,开源近两年的时间以来收获了诸多用户与开发者的认可.本文通过大白话从零诠释 KubeSphere 的定位与价值,以及不同团队为什么会选择 KubeSphe ...

  6. 奇怪DP之步步为零

    题目 思路 很明显的dp就是不会跑啊,所以最后dfs救了一下场,不出所料,最后果然T了,现在说一下正解. 为什么说是奇怪dp呢,这道题的dp数组是布尔型的,f[i][j][k]代表在到第i行第j列之前 ...

  7. MySQL 快速删除大量数据(千万级别)的几种实践方案

    笔者最近工作中遇见一个性能瓶颈问题,MySQL表,每天大概新增776万条记录,存储周期为7天,超过7天的数据需要在新增记录前老化.连续运行9天以后,删除一天的数据大概需要3个半小时(环境:128G, ...

  8. python入门007

    一.深浅copy 浅拷贝:是把原列表第一层的内存地址完全拷贝一份给新列表.即只能保证对原列表中第一层地址(不可变类型)的改操作不受影响,涉及到原列表中第二层地址(可变类型)的改操作时,原列表变,新列表 ...

  9. requests接口自动化2-url里不带参数的get请求

    最常用的是get,post请求,然后是put,delete,其他方法很少用 1. get请求几种方式 1.1.url里不带参数的get请求 接口请求fiddler返回内容: import reques ...

  10. python 并发专题(二):python线程以及线程池相关以及实现

    一 多线程实现 线程模块 - 多线程主要的内容:直接进行多线程操作,线程同步,带队列的多线程: Python3 通过两个标准库 _thread 和 threading 提供对线程的支持. _threa ...