Android 性能优化之卡顿优化

news/2024/8/26 10:21:15 标签: android, 性能优化, 卡顿优化

文章目录

  • Android 性能优化卡顿优化
    • 卡顿检测
      • TraceView
        • 配置
        • 缺点
      • StricktMode
        • 配置
        • 违规代码
      • BlockCanary
        • 配置
        • 问题代码
        • 缺点
    • ANR
      • ANR原因
      • ANRWatchDog监测
      • 解决方案

Android 性能优化卡顿优化

卡顿检测

  • TraceView
  • StricktModel
  • BlockCanary

TraceView

配置
Debug.startMethodTracing("myTrace");
Debug.stopMethodTracing();

生成的 trace 文件保存在:/storage/self/primary/Android/data/<包名>/files/myTrace.trace

缺点
  • 运行时开销大,整体变慢。
  • 容易带偏优化方向。

StricktMode

StricktMode 严苛模式,是 Android 提供的一种运行时检测机制。

策略:

  • 线程策略:
    • 自定义耗时调用:detectCustomSlowCalls
    • 磁盘读取操作:detectDiskReads
    • 网络操作:detectNetwork
  • 虚拟机策略:
    • Activity泄露:detectActivityLeaks()
    • Sqlite对象泄露:detectLeakedSqlLiteObjects
    • 检测实例数量:setClassInstanceLimit()

在 LogCat 中过滤 “StrictMode” 即可查看日志信息。

配置
public class BaseApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        initStrictMode();
    }

    private void initStrictMode() {
        if (BuildConfig.DEBUG) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectCustomSlowCalls() //API等级11,使用StrictMode.noteSlowCode
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()// or .detectAll() for all detectable problems
                    .penaltyLog() //在Logcat 中打印违规异常信息
                    .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectActivityLeaks()
                    .detectLeakedSqlLiteObjects()
//                    .setClassInstanceLimit(Person.class, 1)
                    .detectLeakedClosableObjects() //API等级11
                    .penaltyLog()
                    .build());
        }
    }
}
违规代码

主线操作IO问题:

File externalStorage = getFilesDir();
File destFile = new File(externalStorage, "hello.txt");
try {
    OutputStream output = new FileOutputStream(destFile, true);
    output.write("I am testing io".getBytes());
    output.flush();
    output.close();
} catch (IOException e) {
    e.printStackTrace();
}

日志:

在这里插入图片描述

可以看到违规的原因和位置。

Activity内存泄露问题:

BaseApp.addActivity(this);

日志:

2024-07-15 17:50:48.075 19900-19900/com.example.anr D/StrictMode: StrictMode policy violation: android.os.strictmode.InstanceCountViolation: class com.example.anr.StuckActivity; instances=12; limit=2
        at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

多次进出后输出日志,存在12个实例。

BlockCanary

BlockCanary 是一个用于 Android 应用开发者的性能分析工具,它可以帮助开发者发现和解决应用中的卡顿问题。BlockCanary 通过在应用中植入检测逻辑,监控应用运行时的线程状态,并在检测到卡顿发生时记录相关信息。它的主要目的是帮助开发者追踪和分析应用中可能导致卡顿的代码段或操作。

配置

添加依赖库:

implementation 'com.github.markzhai:blockcanary-android:1.5.0'

配置:

public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        BlockCanary.install(this, new AppBlockCanaryContext()).start();
    }
}
问题代码

依次执行问题代码:

private void testSleep() {
    Log.e("TAG", "sleep前");
    try {
        Thread.sleep(2000L);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    Log.e("TAG", "sleep后");
}
private void testMath() {
    Log.e("TAG", "math前");
    long start = System.currentTimeMillis();
    double result = 0;
    for (int i = 0; i < 10000000; i++) {
        result += Math.acos(Math.cos(i));
        result -= Math.asin(Math.sin(i));
        result += Math.acos(Math.cos(i));
        result -= Math.asin(Math.sin(i));
    }
    Log.e("TAG", "math" + result);
    Log.e("TAG", "耗时 " + (System.currentTimeMillis() - start));
}

BlockCanary 依次生成2个信息:

在这里插入图片描述

点击第一个进去可以看到,阻塞时间和阻塞代码:

在这里插入图片描述

点击第二个进去同样也能看到相关信息:

在这里插入图片描述

缺点
  • BlockCanary 需要在应用中植入检测逻辑,这会带来一定的性能开销。
  • 卡顿堆栈可能不准确。

ANR

ANR(Application Not Responding)是指应用程序未响应,Android 系统对于一些事件需要在一定时间范围内完成,如果超过预定时间未能得到有效响应或者响应时间过长,都会造成 ANR。

ANR原因

  • 数据导致的 ANR:频繁 GC 导致线程暂停,处理事件时间被拉长。
  • 线程阻塞或死锁导致的 ANR。
  • Binder 导致的 ANR:Binder 通信数据量过大。

在这里插入图片描述

ANRWatchDog监测

ANRWatchDog是一个用于监测Android应用程序中的ANR(应用程序无响应)的开源库。

添加依赖库:

implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'

配置:

public class BaseApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate(); 
        new ANRWatchDog().start(); // 默认5000毫秒
    }
}

问题代码一:

public void onClick1(View view) {
    try {
        Thread.sleep(20000L);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

ANRWatchDog警告:

在这里插入图片描述

问题代码二:

public void onClick2(View view) {
    SharedPreferences sp = getSharedPreferences("app", Context.MODE_PRIVATE);
    for (int i = 0; i < 100000; i++) {
        SharedPreferences.Editor edit = sp.edit();
        for (int j = 0; j < 100000; j++) {
            edit.putString("name", "aaaaa")
                    .putInt("age", 18)
                    .putBoolean("sex", true)
                    .commit();
        }
    }
}

ANRWatchDog警告:

在这里插入图片描述

解决方案

  • 将所有耗时操作如访问网络、socket 通信、查询大量 SQL 语句、复杂逻辑计算等都放在子线程中,然后通过 handler.sendMessage、runOnUIThread 等方式更新 UI。无论如何都要确保用户界面的流畅度,如果耗时操作需要让用户等待,可以在界面上显示进度条
  • 将 IO 操作放在异步线程。在一些同步的操作主线程有可能被锁,需要等待其他线程释放响应锁才能继续执行,这样会有一定的 ANR 风险,对于这种情况有时也可以用异步线程来执行相应的逻辑,另外,要避免死锁的发生
  • 使用 Thread 或 HandlerThread 时,调用 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)设置优先级,否则仍然会降低程序响应,因为默认 Thread 优先级和主线程相同
  • 使用 Handler 处理工作线程结果,而不是使用 Thread.wait() 或 Thread.sleep() 来阻塞主线程
  • Activity 的 onCreate() 和 onResume() 回调中避免耗时代码
  • BroadcastReceiver 中 onReceive() 代码也要尽量减少耗时,建议使用 IntentService 处理
  • 各个组件的生命周期函数都不应该有太耗时的操作,即使对于后台 Service 或 ContentProvider 来讲,虽然应用在后台运行时生命周期函数不会有用户输入引起无响应的 ANR,但其执行时间过长也会引起 Service 或 ContentProvider 的 ANR

http://www.niftyadmin.cn/n/5558643.html

相关文章

orcad导出pdf 缺少title block

在OrCAD中导出PDF时没有Title Block 最后确认问题在这里&#xff1a; 要勾选上Title Block Visible下面的print

用Pytorch实现线性回归(Linear Regression with Pytorch)

使用pytorch写神经网络的第一步就是需要准备好数据集&#xff0c;设计模型&#xff08;用于计算y_hat&#xff08;y的预测值&#xff09;&#xff09;&#xff0c;构造损失函数和优化器&#xff08;使用PyTorch API&#xff09;&#xff0c;写训练周期&#xff08;前馈&#xf…

Apollo docker-compose

来源 https://www.apolloconfig.com/#/zh/deployment/quick-start-docker 路径 /usr/apollo Sql 自己复制 Vim docker-compose.yml #如果安装过了 记得删除mysql 历史文件 rm -r /var/lib/mysql version: 2.1services:apollo-quick-start:image: nobodyiam/apollo-quick…

C++比Java,python快的原因

文章目录 一、c的编译方式与Java对比C编译方式&#xff1a;Java编译方式&#xff1a; 一、c的编译方式与Java对比 C和Java是两种不同的编程语言&#xff0c;它们的编译方式也有所不同。 C编译方式&#xff1a; C代码需要先编译后链接。编译过程中&#xff0c;C代码被转换成机…

执行python脚本报错:ModulNotFoundError: No module named “allure“/离线安装allure模块

1、问题概述? 创作时间:2024年7月 本质就是说明你的项目中缺少allure模块,需要安装。分二中情况有网络环境和无网络环境 不管是哪一种都是要将allure安装成功。 2、有网络的安装方式? 在pycharm的Terminal中输入以下命令 pip intall allure-pytest 安装后查看安装情况…

面试题 27. 二叉树的镜像

题目描述 请完成一个函数&#xff0c;输入一个二叉树&#xff0c;该函数输出它的镜像。 示例 例如输入&#xff1a; 4/ \2 7/ \ / \ 1 3 6 9镜像输出&#xff1a; 4/ \7 2/ \ / \ 9 6 3 1输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4…

华为OD算法题汇总

60、计算网络信号 题目 网络信号经过传递会逐层衰减&#xff0c;且遇到阻隔物无法直接穿透&#xff0c;在此情况下需要计算某个位置的网络信号值。注意:网络信号可以绕过阻隔物 array[m][n]&#xff0c;二维数组代表网格地图 array[i][j]0&#xff0c;代表i行j列是空旷位置 a…

Python一对一辅导答疑|Rust 德国

你好&#xff0c;我是悦创。 下面是答疑内容。 在 Rust 中&#xff0c;方法的调用方式通常取决于它们是如何定义的。在你的例子中&#xff0c;print_drink方法最初是作为一个接受Drink类型实例作为参数的关联函数&#xff08;类似于静态方法&#xff09;定义的。后来&#xff…