文章目錄
- Android 性能優化之啟動優化
- 啟動狀態
- 冷啟動
- 溫啟動
- 熱啟動
- 耗時檢測
- 檢測手段
- TraceView
- 使用方式
- 缺點
- Systrace
- 環境配置
- 使用方式
- TraceView和Systrace比較
- AOP統計耗時
- 環境配置
- 使用
- 優化
- 白屏優化
- 異步加載優化
- 環境配置
- 使用
- 延遲加載優化
- AppStartup
- 源碼下載
Android 性能優化之啟動優化
啟動狀態
冷啟動
冷啟動是應用程序啟動的默認方式。當用戶首次啟動應用程序時,或者系統徹底殺死了應用程序進程后再次啟動應用程序時,會經歷冷啟動。在冷啟動過程中,系統需要創建一個新的進程,并初始化所有必要的資源。這包括加載應用程序的代碼、數據,以及初始化應用程序的環境。冷啟動的時間相對較長,因為系統需要執行一系列初始化操作。用戶能感受到明顯的等待時間,這段時間從點擊應用圖標到看到應用程序主界面出現。
在冷啟動開始時,系統有以下三項任務:
- 加載并啟動應用。
- 在啟動后立即顯示應用的空白啟動窗口。
- 創建應用進程。
系統一創建應用進程,應用進程就負責后續階段:
- 創建應用對象。
- 啟動主線程。
- 創建主 activity。
- 膨脹視圖。
- 創建屏幕布局。
- 執行初步繪制。
溫啟動
溫啟動是指應用程序已經在后臺運行,但由于系統資源緊張等原因被系統終止。當用戶再次啟動應用程序時,系統會重新加載應用程序。與冷啟動相比,溫啟動不需要重新創建進程,因此啟動時間較短。
熱啟動
熱啟動是指應用程序處于前臺運行狀態,用戶通過返回鍵或應用程序內部的邏輯退到后臺,然后又重新顯示到前臺。在這種情況下,應用程序的進程仍然在運行,所以不需要進行任何初始化操作。熱啟動是最快的啟動方式,因為系統只需要恢復應用程序的前臺狀態。
耗時檢測
檢測手段
- TraceView
- Systrace
- AOP統計耗時
TraceView
TraceView 是 Android SDK 中提供的性能分析工具,它可以幫助開發者分析應用程序的方法調用和線程活動。TraceView 專注于應用程序的內部行為,提供了方法執行時間、調用次數、CPU 使用率等詳細信息。它通常用于分析應用程序的特定部分或特定場景。
使用方式
public class BaseApp extends Application { @Overridepublic 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 {@Overridepublic 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@Overridepublic 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@Overridepublic void onCreate() {super.onCreate(); initRefresh(); initTitleBar(); initToast(); initActivites(); }@CostTimeprivate void initActivites() {ActivityManager.getInstance().init(instance);}@CostTimeprivate void initToast() {ToastUtils.init(instance, new ToastStyle());ToastUtils.setDebugMode(AppConfig.isDebug());ToastUtils.setInterceptor(new ToastLogInterceptor());}@CostTimeprivate void initTitleBar() {TitleBar.setDefaultStyle(new TitleBarStyle());}@CostTimeprivate void initRefresh() {SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() {@Overridepublic RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) {layout.setPrimaryColorsId(R.color.black, android.R.color.white);//全局設置主題顏色return new ClassicsHeader(context);}});SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() {@Overridepublic 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:
<activityandroid: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@Overridepublic 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() {@Overridepublic 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 {@Overridepublic void run() {try {Thread.sleep(1000L);Log.e("TAG", "預加載數據");} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
public class ClearTask implements Task {@Overridepublic 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