Android 性能优化之启动优化

文章目录

  • 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.mfbz.cn/a/787673.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python实现吃豆人游戏详解(内附完整代码)

一、吃豆人游戏背景 吃豆人是一款由Namco公司在1980年推出的经典街机游戏。游戏的主角是一个黄色的小圆点&#xff0c;它必须在迷宫中吃掉所有的点数&#xff0c;同时避免被四处游荡的幽灵捉到。如果玩家能够吃掉所有的点数&#xff0c;并且成功避开幽灵&#xff0c;就可以进入…

机场公厕厕位指引屏,布线简单,安装便捷

在人潮涌动的机场&#xff0c;公厕不仅是旅客的必需设施&#xff0c;更是衡量机场服务质量的重要指标。然而&#xff0c;传统机场公厕往往存在信息不透明、清洁维护滞后、高峰期拥挤等问题&#xff0c;严重影响了旅客的使用体验。近年来&#xff0c;随着智慧机场理念的兴起&…

设计无缝体验:交互设计流程全解析

完整的产品交互设计流程是什么&#xff1f;完整的产品交互设计流程包括研究用户需求、指定信息架构、制作产品原型、进行用户测试和实时发布产品。交互设计就是从人与产品之间的关系入手&#xff0c;通过产品设计来满足大众的日常需求。随着网络技术的流行&#xff0c;产品交互…

ChatGPT-4o大语言模型优化、本地私有化部署、从0-1搭建、智能体构建技术

在过去几年中&#xff0c;人工智能领域的发展迅猛&#xff0c;尤其是大语言模型的应用&#xff0c;为各行各业带来了前所未有的创新与突破。从ChatGPT-3.5的推出到GPT Store的上线&#xff0c;再到最新的多模态交互ChatGPT-4o&#xff0c;OpenAI不断引领科技潮流&#xff0c;推…

Spring源码二十:Bean实例化流程三

上一篇Spring源码十九&#xff1a;Bean实例化流程二中&#xff0c;我们主要讨论了单例Bean创建对象的主要方法getSingleton了解到了他的核心流程无非是&#xff1a;通过一个简单工厂的getObject方法来实例化bean&#xff0c;当然spring在实例化前后提供了扩展如&#xff1a;bef…

猎人维修大师免狗版

技术文档摘要 标题&#xff1a; 多功能维修工具集合概述 摘要&#xff1a; 本文档提供了一组多功能维修工具的概述&#xff0c;这些工具旨在为专业技术人员提供便利&#xff0c;以执行设备维修和软件解锁等任务。文档列出了各个工具的主要功能和应用场景。 关键词&#xff1…

面试经典 106. 从中序与后序遍历序列构造二叉树

最近小胖开始找工作了&#xff0c;又来刷苦逼的算法了 555 废话不多说&#xff0c;看这一题&#xff0c;上链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/description/?envTypestudy-plan-v2&envIdtop-inte…

Github Actions 构建Vue3 + Vite项目

本篇文章以自己创建的项目为例&#xff0c;用Github Actions构建。 Github地址&#xff1a;https://github.com/ling08140814/myCarousel 访问地址&#xff1a;https://ling08140814.github.io/myCarousel/ 具体步骤&#xff1a; 1、创建一个Vue3的项目&#xff0c;并完成代…

【动态规划Ⅴ】二维数组的动态规划——0/1矩阵、最大正方形

二维数组的动态规划——0/1矩阵、最大正方形 最大正方形1277. 统计全为 1 的正方形子矩阵221. 最大正方形 01矩阵542. 01 矩阵 最大正方形 下面两个题目是非常相似的&#xff0c;只是一个统计正方形数目&#xff0c;一个统计最大正方形的面积。 1277. 统计全为 1 的正方形子矩…

使用ssh服务器管理远程主机

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、配置网卡服务 1、配置网卡参数 2、创建网络会话 3、绑定两块网卡 二、远程控制服务 1、配置sshd服务 2、在Windows连接 3、安全密钥…

AI绘画:艺术与科技的交融,创新浪潮与无限可能

在科技日新月异的当下&#xff0c;AI 绘画作为人工智能领域的一颗璀璨新星&#xff0c;正以惊人的速度在国内崭露头角&#xff0c;引发了艺术与技术交融的全新变革。随着人工智能技术的飞速发展&#xff0c;AI绘画已成为艺术与科技交融的新宠。2024年&#xff0c;AI绘画行业在国…

【Python】已解决:SyntaxError: positional argument follows keyword argument

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;SyntaxError: positional argument follows keyword argument 一、分析问题背景 在Python编程中&#xff0c;当我们在调用函数时混合使用位置参数&#xff08;p…

【RAG KG】GraphRAG开源:查询聚焦摘要的图RAG方法

前言 传统的 RAG 方法在处理针对整个文本语料库的全局性问题时存在不足&#xff0c;例如查询&#xff1a;“数据中的前 5 个主题是什么&#xff1f;” 对于此类问题&#xff0c;是因为这类问题本质上是查询聚焦的摘要&#xff08;Query-Focused Summarization, QFS&#xff09…

tessy 单元测试:小白入门指导手册

目录 1,创建单元测试工程目录 2,导入单元测试源文件 一:创建测试文件夹(最好和代码目录一一对应,方便查找) 二:选择测试环境 三:添加源文件 四:分析源文件 3,编写单元测试用例 一:设置函数参数的传输方向 二:添加单元测试用例 三:编辑单元测试用例数据 …

网站更新改版了

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a;Leo杂谈 ✨特色专栏&#xff1a;MySQL学…

UI设计入门到精通:规范整理与应用技巧

很多刚入行的UI设计师在遇到一些不熟悉的词时会充满问号&#xff0c;往往会纠结用什么尺寸最合适。设计师在设计UI的时候不一定要严格遵守设计规范&#xff0c;但是要了解规范&#xff0c;整合&#xff0c;灵活处理。为了解决新手的“十万个为什么”&#xff0c;本文将带你了解…

无法连接Linux远程服务器的Mysql,解决办法

问题描述 如果是关闭虚拟机之后&#xff0c;二次打开无法连接Mysql&#xff0c;则可尝试一下方法进行解决 解决方法 关闭虚拟机的防火墙 1&#xff1a;查看防火墙状态 systemctl status firewalld 一下显示说明防火墙是启动的状态 2&#xff1a;关闭防火墙 systemctl st…

Python大数据分析——决策树和随机森林

Python大数据分析——决策树和随机森林 决策树决策树节点字段的选择信息熵条件熵信息增益信息增益率 基尼指数条件基尼指数基尼指数增益 决策树函数 随机森林函数 决策树 图中的决策树呈现自顶向下的生长过程&#xff0c;深色的椭圆表示树的根节点&#xff1b;浅色的椭圆表示树…

招投标信息采集系统:让您的企业始终站在行业前沿

一、为何招投标信息如此关键&#xff1f; 在经济全球化的大背景下&#xff0c;招投标活动日益频繁&#xff0c;成为企业获取项目、拓展市场的主流方式之一。招投标信息采集&#xff0c;作为企业战略决策的前置环节&#xff0c;其重要性不言而喻。它不仅关乎企业能否第一时间发…

探索 Qt 的 `QSqlDatabase`:数据库访问的桥梁

&#x1f60e; 作者介绍&#xff1a;欢迎来到我的主页&#x1f448;&#xff0c;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff08;领取大厂面经等资料&#xff09;&#xff0c;欢迎加我的…