Android 性能优化之启动优化

news2024/11/15 10:06:13

文章目录

  • Android 性能优化之启动优化
    • 启动状态
      • 冷启动
      • 温启动
      • 热启动
    • 耗时检测
      • 检测手段
      • TraceView
        • 使用方式
        • 缺点
      • Systrace
        • 环境配置
        • 使用方式
        • TraceView和Systrace比较
      • AOP统计耗时
        • 环境配置
        • 使用
    • 优化
      • 白屏优化
      • 异步加载优化
        • 环境配置
        • 使用
      • 延迟加载优化
      • AppStartup
    • 源码下载

Android 性能优化之启动优化

启动状态

在这里插入图片描述

冷启动

冷启动是应用程序启动的默认方式。当用户首次启动应用程序时,或者系统彻底杀死了应用程序进程后再次启动应用程序时,会经历冷启动。在冷启动过程中,系统需要创建一个新的进程,并初始化所有必要的资源。这包括加载应用程序的代码、数据,以及初始化应用程序的环境。冷启动的时间相对较长,因为系统需要执行一系列初始化操作。用户能感受到明显的等待时间,这段时间从点击应用图标到看到应用程序主界面出现。

在冷启动开始时,系统有以下三项任务:

  1. 加载并启动应用。
  2. 在启动后立即显示应用的空白启动窗口。
  3. 创建应用进程。

系统一创建应用进程,应用进程就负责后续阶段:

  1. 创建应用对象。
  2. 启动主线程。
  3. 创建主 activity。
  4. 膨胀视图。
  5. 创建屏幕布局。
  6. 执行初步绘制。

在这里插入图片描述

温启动

温启动是指应用程序已经在后台运行,但由于系统资源紧张等原因被系统终止。当用户再次启动应用程序时,系统会重新加载应用程序。与冷启动相比,温启动不需要重新创建进程,因此启动时间较短。

热启动

热启动是指应用程序处于前台运行状态,用户通过返回键或应用程序内部的逻辑退到后台,然后又重新显示到前台。在这种情况下,应用程序的进程仍然在运行,所以不需要进行任何初始化操作。热启动是最快的启动方式,因为系统只需要恢复应用程序的前台状态。

耗时检测

检测手段

  • TraceView
  • Systrace
  • AOP统计耗时

TraceView

TraceView 是 Android SDK 中提供的性能分析工具,它可以帮助开发者分析应用程序的方法调用和线程活动。TraceView 专注于应用程序的内部行为,提供了方法执行时间、调用次数、CPU 使用率等详细信息。它通常用于分析应用程序的特定部分或特定场景。

使用方式
public class BaseApp extends Application {  
    @Override
    public void onCreate() {
        super.onCreate();
        // TraceView开始
        Debug.startMethodTracing("myTrace001");
        initRefresh();
        initTitleBar();
        initToast();
        initActivites();
        // TraceView结束
        Debug.stopMethodTracing();
    }
}

运行程序后生成文件:/sdcard/Android/data/com.example.android_performance_optimization/files/myTrace001.trace

在这里插入图片描述

将 trace 文件到处,用 AndroidStudio的 Profiler 工具打开,可以清楚看到各个方法的执行时间:

在这里插入图片描述

缺点
  • 运行时开销严重,整体会变慢。
  • 可能带偏优化方向。

Systrace

Systrace 是 Android SDK 中提供的另一个性能分析工具,它提供了系统级别的跟踪信息,包括内核调度、硬件I/O、进程/线程调度等。Systrace 专注于整个 Android 系统的行为,帮助开发者了解系统资源的使用情况和潜在的瓶颈。

环境配置

https://blog.csdn.net/Donald_Zhuang/article/details/118771191

https://blog.csdn.net/jdsjlzx/article/details/134179374

使用方式
public class BaseApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // Systrace开始
        Trace.beginSection("myTrace002");
        initRefresh();
        initTitleBar();
        initToast();
        initActivites();
        // Systrace结束
        Trace.endSection();
    }
}

先执行命令:python D:\dev\AndroidSDK\platform-tools\systrace\systrace.py -t 10 -o mytrace.html -a com.example.android_performance_optimization sched freq idle am wm gfx view binder_driver hal dalvik camera input res

然后运行程序,大概10秒后会生成 mytrace.html 文件。

打开 html 文件过滤相关信息后可以看到 Wall Duration 耗时:

在这里插入图片描述

TraceView和Systrace比较

性能消耗

  • TraceView:由于它收集所有方法的耗时信息和嵌套关系,因此本身的性能消耗很大,可能会影响到实际的运行环境,统计的耗时可能不准确。
  • Systrace:采用了不同的思路,通过有限的Label先粗略统计出一个阶段的耗时,定位到问题后再进一步细化和测算分析。这种方式相对于TraceView来说,对性能的影响较小。

适用范围

  • TraceView:更适用于从软件跟踪的角度分析应用程序的性能。
  • Systrace:则更侧重于从系统整体的角度分析Android系统的性能,包括各个关键子系统和服务的运行情况。

AOP统计耗时

环境配置

这里使用第三方框架:https://github.com/FlyJingFish/AndroidAOP

添加依赖库:

implementation 'io.github.FlyJingFish.AndroidAop:android-aop-core:1.8.8'
implementation 'io.github.FlyJingFish.AndroidAop:android-aop-annotation:1.8.8'
annotationProcessor 'io.github.FlyJingFish.AndroidAop:android-aop-processor:1.8.8'
使用

定义注解:

@AndroidAopPointCut(CostTimePointcut.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CostTime {
}

定义切面类:

public class CostTimePointcut implements BasePointCut<CostTime> {
    @Nullable
    @Override
    public Object invoke(@NonNull ProceedJoinPoint proceedJoinPoint, @NonNull CostTime costTime) {
        long startTime = System.currentTimeMillis();
        proceedJoinPoint.proceed(); // 继续执行原方法
        long time = System.currentTimeMillis() - startTime;
        Class<?> targetClass = proceedJoinPoint.getTargetClass();
        String className = targetClass.getName();
        AopMethod targetMethod = proceedJoinPoint.getTargetMethod();
        String methodName = targetMethod.getName();
        String builder = className + "#" + methodName + " [" + time + "ms" + "] ";
        Log.e("CostTime", builder);
        return null;
    }
}

使用AOP:

public class BaseApp extends Application {

    @CostTime
    @Override
    public void onCreate() {
        super.onCreate(); 
        initRefresh(); 
        initTitleBar(); 
        initToast(); 
        initActivites(); 
    }

    @CostTime
    private void initActivites() {
        ActivityManager.getInstance().init(instance);
    }

    @CostTime
    private void initToast() {
        ToastUtils.init(instance, new ToastStyle());
        ToastUtils.setDebugMode(AppConfig.isDebug());
        ToastUtils.setInterceptor(new ToastLogInterceptor());
    }

    @CostTime
    private void initTitleBar() {
        TitleBar.setDefaultStyle(new TitleBarStyle());
    }

    @CostTime
    private void initRefresh() {
        SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {
            @Override
            public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {
                layout.setPrimaryColorsId(R.color.black, android.R.color.white);//全局设置主题颜色
                return new ClassicsHeader(context);
            }
        });
        SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {
            @Override
            public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) {
                return new ClassicsFooter(context).setDrawableSize(20);
            }
        });
    }
}

输出:

com.example.android_performance_optimization.BaseApp#initRefresh [1ms] 
com.example.android_performance_optimization.BaseApp#initTitleBar [0ms] 
com.example.android_performance_optimization.BaseApp#initToast [0ms] 
com.example.android_performance_optimization.BaseApp#initActivites [1ms] 
com.example.android_performance_optimization.BaseApp#onCreate [2ms] 

优化

  • 白屏优化
  • 异步加载优化
  • 延迟加载优化

白屏优化

在启动时提供一个简洁的初始界面给用户,增强用户体验。

定义主题:

<style name="SplashTheme" parent="AppTheme">
    <!--        设置背景图-->
    <item name="android:windowBackground">@drawable/shape_splash</item>
    <!--        取消标题栏-->
    <item name="windowNoTitle">true</item>
    <item name="windowActionBar">false</item>
    <!--        设置window不透明-->
    <item name="android:windowIsTranslucent">false</item>
    <!--        禁用窗口的预览动画-->
    <item name="android:windowDisablePreview">true</item>
    <!--        取消遮盖-->
    <item name="android:windowContentOverlay">@null</item>
    <!--        全屏-->
    <item name="android:windowFullscreen">true</item>
</style>

配置AndroidManifest.xml:

<activity
    android:name=".SplashActivity"
    android:exported="true"
    android:launchMode="singleTop"
    android:theme="@style/SplashTheme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

异步加载优化

环境配置

这里使用第三方框架:https://github.com/aiceking/AppStartFaster

添加依赖库:

implementation 'com.github.aiceking:AppStartFaster:2.2.0'
使用
public class BaseApp extends Application {
    private static BaseApp instance;

    public static BaseApp getInstance() {
        return instance;
    }

    @CostTime
    @Override
    public void onCreate() {
        super.onCreate();
        instance = this; 
        AppStartTaskDispatcher.create()
            .setShowLog(true)
            .addAppStartTask(new ActivityTask(instance))
            .addAppStartTask(new ToastTask(instance))
            .addAppStartTask(new TitleBarTask())
            .addAppStartTask(new RefreshTask())
            .start()
            .await();
    }
}

延迟加载优化

IdleHandler 是一个用于在主线程(UI 线程)空闲时执行任务的接口。

使用场景:

  • 数据预加载。
  • 清理资源。
  • 日志上传。
  • 检查更新。
  • 性能分析。

使用:

首先,你需要创建一个实现了IdleHandler接口的类或使用匿名内部类。在queueIdle()方法中定义你希望在空闲时执行的代码逻辑。该方法的返回值决定了IdleHandler的生命周期:

  • 返回true表示IdleHandler将继续保留在集合中,下次消息队列空闲时还会再次调用queueIdle()
  • 返回false表示执行完毕后将从集合中移除,不再重复调用。

定义延迟加载启动器:

public class DelayInitDispatcher {
    private DelayInitDispatcher() {
    }

    public static DelayInitDispatcher newInstance() {
        return new DelayInitDispatcher();
    }

    private LinkedList<Task> mDelayTasks = new LinkedList<>();

    private MessageQueue.IdleHandler mIdleHandler = new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            if (mDelayTasks.size() > 0) {
                Task task = mDelayTasks.poll();
                task.run();
            }
            return !mDelayTasks.isEmpty();
        }
    };

    public DelayInitDispatcher addTask(Task task) {
        mDelayTasks.add(task);
        return this;
    }

    public void start() {
        Looper.myQueue().addIdleHandler(mIdleHandler);
    }
}

定义Task接口:

public interface Task extends Runnable{
}

定义2个任务:

public class PreloadTask implements Task {
    @Override
    public void run() {
        try {
            Thread.sleep(1000L);
            Log.e("TAG", "预加载数据");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
public class ClearTask implements Task {
    @Override
    public void run() {
        try {
            Thread.sleep(2000L);
            Log.e("TAG", "清理资源");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

使用:

DelayInitDispatcher.newInstance()
        .addTask(new PreloadTask())
        .addTask(new ClearTask())
        .start();

AppStartup

  • AppStartup 是一个可以用于加速App启动速度的 Jetpack 组件。
  • AppStartup 是借助 ContentProvider 进行提前初始化操作

https://blog.csdn.net/qq_14876133/article/details/119247723

源码下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1907110.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VMware取消中文支持,替换vSAN解决方案提上日程!

What is vSAN &#xff1f; 是一款软件定义的企业存储解决方案&#xff0c;支持超融合基础架构系统。vSAN与VMware vSphere 完全集成在一起&#xff0c;作为ESXi Hypervisor内的分布式软件层&#xff0c;通过整合、池化ESXi各个主机上的存储资源&#xff0c;为vSphere虚拟化平…

厦门大学-中央空调分户计费预付费管理系统案例

厦门大学-中央空调分户计费预付费管理系统案例 实现中央空调节能与舒适的双重目标随着社会的发展和人们生活水平的提高&#xff0c;空调已成为现代建筑中不可或缺的设备。传统的集中计费方式已无法满足多样化的用户需求和节能减排的市场趋势。中央空调如何公平、公正、合理的收…

必剪APP视频剪辑的字幕制作方法教程!

你是否还在用pr听一句打一句的制作字幕&#xff1f;你是否还在用ps做字幕然后拉到pr里一句一句的对时间轴&#xff1f;快别用那些老方法啦&#xff0c;繁琐又浪费时间&#xff01;今天给大家推荐一个方便速度的制作字幕的方法&#xff0c;赶快来看看吧&#xff01; 第一步&…

【数据结构】单链表:数据结构中的舞者,穿梭于理论与实践的舞池

欢迎来到白刘的领域 Miracle_86.-CSDN博客 系列专栏 数据结构与算法 先赞后看&#xff0c;已成习惯 创作不易&#xff0c;多多支持&#xff01; 一、链表的概念和结构 1.1 链表的概念 在上一篇文章中&#xff0c;我们了解了线性表(linear list)&#xff0c;并且学习了其…

后端学习(一)

添加数据库包&#xff1a; 数据库连接时 发生错误&#xff1a; 解决方式&#xff1a; SqlConnection conn new SqlConnection("serverlocalhost;databaseMyBBSDb;uidsa;pwd123456;Encryptfalse;") ;conn.Open();SqlCommand cmd new SqlCommand("SELECT * FROM…

算法012:将x减到0的最小操作数

将x减到0的最小操作数. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/ 这个题使用到的是滑动窗口。 乍一看&#xff0c…

JAVA Tesseract OCR引擎

Tess4j是一个基于Tesseract OCR引擎的Java库, Tesseract库最初由惠普实验室于1985年开发&#xff0c;后来被Google收购并于2006年开源。识别效果不好&#xff0c;速度还慢&#xff0c;但是好早好早了。 一、POM依赖 <!--OCR识别https://digi.bib.uni-mannheim.de/tesserac…

MySQL篇四:表的约束

文章目录 前言1. 空属性2. 默认值3. 列描述4. zerofill5. 主键6. 自增长7. 唯一键8. 外键 前言 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性。…

26.6 Django模型层

1. 模型层 1.1 模型层的作用 模型层(Model Layer)是MVC或MTV架构中的一个核心组成部分, 它主要负责定义和管理应用程序中的数据结构及其行为. 具体职责包括: * 1. 封装数据: 模型层封装了应用程序所需的所有数据, 这些数据以结构化的形式存在, 如数据库表, 对象等. * 2. 数据…

20K star!手把手教会你搞定 LLM 微调,超详细收藏我这篇就够了

LLM&#xff08;大语言模型&#xff09;微调一直都是老大难问题&#xff0c;不仅因为微调需要大量的计算资源&#xff0c;而且微调的方法也很多&#xff0c;要去尝试每种方法的效果&#xff0c;需要安装大量的第三方库和依赖&#xff0c;甚至要接入一些框架&#xff0c;可能在还…

HR8870:H桥PWM直流电机驱动IC性能指标和应用方案选型

HR8870芯片描述 HR8870是一款直流有刷电机驱动器&#xff0c;适用于打印机、电器、工业设备以及其他小型机器。两个逻辑输入控制H桥驱动器&#xff0c;该驱动器由四个N-MOS组成&#xff0c;能够以高达4.5A的峰值电流双向控制电机。利用电流衰减模式&#xff0c;可通过对输入进行…

MySQL资源组的使用方法

MySQL支持创建和管理资源组&#xff0c;并允许将服务器内运行的线程分配给特定的组&#xff0c;以便线程根据组可用的资源执行。组属性允许控制其资源&#xff0c;以启用或限制组中线程的资源消耗。DBA可以针对不同的工作负载适当地修改这些属性。 目前&#xff0c;CPU时间是一…

Python自动化与系统安全

信息安全是运维的根本&#xff0c;直接关系到企业的安危&#xff0c;稍有不慎会造成灾难性的后果。比如经年发生的多个知名网站会员数据库外泄事件&#xff0c;信息安全体系建设已经被提到了前所未有的高度。如何提升企业的安全防范水准是目前普遍面临的问题&#xff0c;主要有…

Flutter-实现悬浮分组列表

在本篇博客中&#xff0c;我们将介绍如何使用 Flutter 实现一个带有分组列表的应用程序。我们将通过 CustomScrollView 和 Sliver 组件来实现该功能。 需求 我们需要实现一个分组列表&#xff0c;分组包含固定的标题和若干个列表项。具体分组如下&#xff1a; 水果动物职业菜…

Java面试八股之MySQL主从复制机制简述

MySQL主从复制机制简述 MySQL的主从复制机制是一种数据复制方案&#xff0c;用于在多个服务器之间同步数据。此机制允许从一个服务器&#xff08;主服务器&#xff09;到一个或多个其他服务器&#xff08;从服务器&#xff09;进行数据的复制&#xff0c;从而增强数据冗余、提…

Spring cloud 中使用 OpenFeign:让 http 调用更优雅

注意&#xff1a;本文演示所使用的 Spring Cloud、Spring Cloud Alibaba 的版本分为为 2023.0.0 和 2023.0.1.0。不兼容的版本可能会导致配置不生效等问题。 1、什么是 OpenFeign Feign 是一个声明式的 Web service 客户端。 它使编写 Web service 客户端更加容易。只需使用 F…

maven-surefire-report-plugin插件生成测试报告

目录 官网 pom.xml配置 测试类 执行测试结果 修改测试类 pom文件更改配置maven-jxr-plugin xref xref-test ​Source Xref​ ​Test Source Xref​ 再此验证 有凭&#xff08;有理&#xff09;有据 官网 Maven Surefire Report Plugin – Showing Only Fail…

分享四种CAD图纸加密方法,防止盗图!

保护CAD图纸不受盗用和非法传播是设计行业中的一个重要课题&#xff0c;以下四种CAD图纸加密方法可以帮助防止图纸被未授权使用。 1.使用专业的加密软件&#xff08;最安全的方法&#xff09; 专门的加密软件&#xff0c;如安企神软件&#xff0c;可以提供更高级别的保护。它使…

EPICS数据库示例

本文目标是使用EPICS数据库示例帮助新手理解如何使用不同的示例。 1、使用seq和mbbo的简单选择器 这个简单示例展示了如何使用一个mbbo和一个seq来旋转哪个值将被设置到一个PV。 # 这个mbbo记录将选择将运行seq的哪段 record(mbbo, "CHOOSE") {field(VAL, "…

使用树莓派进行python开发,控制电机的参考资料

网站连接&#xff1a;https://www.cnblogs.com/kevenduan?page1 1、简洁的过程步骤&#xff0c; 2、有代码示例&#xff0c; 3、有注意事项&#xff0c;