網站首頁 編程語言 正文
1.啟動分為兩種方式
- 1) 冷啟動:當直接從桌面上直接啟動,同時后臺沒有該進程的緩存,這個時候系統就需要重新創建一個新的進程并且分配各種資源。
-
2) 熱啟動:該
app
后臺有該進程的緩存,這時候啟動的進程就屬于熱啟動。 - 熱啟動不需要重新分配進程,也不會
Application
了,直接走的就是app
的入口Activity
,這樣速度就很快
2.如何測量一個應用的啟動時間
使用命令行來啟動app,同時進行時間測量。單位:毫秒
?adb shell am start - W [PackageName] /[PackageName.MainActivity]
例: adb shell am start -W com.haocai.app/.activity.GuideActivity
熱啟動耗時:
打印的結果為:
-
ThisTime
該activity
啟動耗時 -
TotalTime
應用自身啟動耗時=ThisTime+
應用application
等資源啟動時間 -
WaitTime
系統啟動應用耗時=TotalTime
+系統資源啟動時間
3.應用啟動的流程
Application
從構造方法開始 ---> attachBaseContext()
---> onCreate()
構造方法 --->
ActivityonCreate()
---> 設置顯示界面布局,設置主題、背景等等屬性 ---> onStart()
---> onResume()
---> 顯示里面的View(測量、布局、繪制,顯示到界面上)
從構造方法我們知道,啟動耗時的主要花費在各個啟動流程中
4.減少應用的啟動時間的耗時
根據應用的啟動流程,我們從而得到以下減少應用啟動耗時操作的建議:
- 不要在
Application
的構造方法、attachBaseContext()
、onCreate()
里面進行初始化耗時操作。 - MainActivity,由于用戶只關心最后顯示的這一幀,對我們的布局的層次要求減 自定義控件的測量、布局、繪制的時間。 同時 不要在
onCreate
、onStart
、onResume
當中的做耗時操作。 - 對于
SharedPreference
的初始化
因為它初始化的時候是需要將數據全部讀取出來放到內存當中。
- 優化1:可以盡可能減少sp文件數量(IO需要時間)
- 優化2:像這樣的初始化最好放到線程里面
- 優化3:大量的數據緩存到數據庫中
app啟動的耗時主要在:Application
初始化 + MainActivity
的界面加載繪制時間。
由于MainActvity
的業務和布局復雜度非常高,甚至該界面必須要有一些初始化的數據才能顯示。
那么這個時候MainActivity
就可能半天都出不來,這就給用戶感覺App太卡了。
常規方法:
1.我們要做的就是給用戶趕緊利落的體驗。點擊app就立馬彈出我們的界面。
于是乎想到使用SplashActivity
--非常簡單的一個歡迎頁面上面都不干就只顯示一個圖片。
2.但是SplashActivity
啟動之后,還是需要跳到MainActivity
。MainActivity
還是需要從頭開始加載布局和數據。
想到SplashActivity里面可以去做一些MainActivity
的數據的預加載。然后需要通過意圖傳到MainActivity
。
更好的優化:
耗時的問題:Application
+Activity
的啟動及資源加載時間;預加載的數據花的時間。
如果我們能讓這兩個時間重疊在一個時間段內并發地做這兩個事情就省時間了。
比如:將SplashActivity
和MainActivity
合為一個。
一進來還是顯示MainActivity
,SplashActivity
可以變成一個SplashFragment
,然后放一個FrameLayout
作為根布局直接顯示SplashFragment
界面。SplashFragment
里面非常之簡單,就是現實一個圖片,啟動非常快。
當SplashFragment
顯示完畢后再將它remove
。同時在splash
的2S的友好時間內進行網絡數據緩存。
這個時候我們才看到MainActivity
,就不必再去等待網絡數據返回了。
新問題:SplashView
和ContentView
加載放到一起來做了 ,這可能會影響應用的啟動時間?
解決:可以使用ViewStub延遲加載MainActivity
當中的View來達到減輕這個影響。viewStub
的設計就是為了防止MainActivity的啟動加載資源太耗時了。延遲進行加載,不影響啟動,用戶友好。
但是viewStub加載也需要時間。等到主界面出來以后。viewStub.inflate(xxxx);
5.如何設計延遲加載DelayLoad
第一時間想到的就是在onCreate
里面調用Handler.postDelayed()
方法;
問題一:這個延時時間如何控制
不同的機器啟動速度不一樣,這個時間如何控制?
假設,先需要splash
做一個2s動畫,然后在MainActivity
中主界面加載完成之后,關閉splash
頁面
如果這樣寫:
mHandler.postDelayed(new Runnable() { @Override public void run() { mProgressBar.setVisibility(View.GONE); iv.setVisibility(View.VISIBLE); } }, 2500);
是無法在準確監聽頁面加載完的
問題:什么時候應用已經啟動并加載完成,界面已經顯示出來了。
采用onResume
執行完了之后才顯示完畢?不行。
建議采用getDecorView()
獲取上級view
然后添加視圖
綜合上訴方案,以下是關鍵代碼:
public class MainActivity extends AppCompatActivity { private Handler mHandler = new Handler(); private SplashFragment splashFragment; private ViewStub viewStub; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); splashFragment = new SplashFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.frame, splashFragment); transaction.commit(); /** *這么寫不好判斷視圖有沒有加載完 */ // mHandler.postDelayed(new Runnable() { // @Override // public void run() { // mProgressBar.setVisibility(View.GONE); // iv.setVisibility(View.VISIBLE); // } // }, 2500); viewStub = (ViewStub) findViewById(R.id.content_viewstub); //1.判斷當窗體加載完畢的時候,立馬再加載真正的布局進來 getWindow().getDecorView().post(new Runnable() { @Override public void run() { // 開啟延遲加載 mHandler.post(new Runnable() { @Override public void run() { //將viewstub加載進來 viewStub.inflate(); } }); } }); //2.判斷當窗體加載完畢的時候執行,延遲一段時間做動畫。 getWindow().getDecorView().post(new Runnable() { @Override public void run() { // 開啟延遲加載,也可以不用延遲可以立馬執行(我這里延遲是為了實現fragment里面的動畫效果的耗時) mHandler.postDelayed(new DelayRunnable(MainActivity.this, splashFragment), 2000); } }); //3.同時進行異步加載數據 //...... } static class DelayRunnable implements Runnable { private WeakReference<Context> contextWeakReference; private WeakReference<SplashFragment> splashFragmentWeakReference; public DelayRunnable(Context context, SplashFragment f) { contextWeakReference = new WeakReference<Context>(context); splashFragmentWeakReference = new WeakReference<SplashFragment>(f); } @Override public void run() { //移除Fragment if (contextWeakReference != null) { SplashFragment splashFragment = splashFragmentWeakReference.get(); if (splashFragment == null) { return; } FragmentActivity activity = (FragmentActivity) contextWeakReference.get(); FragmentTransaction transaction = activity.getSupportFragmentManager().beginTransaction(); transaction.remove(splashFragment); transaction.commit(); } } } }
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <ViewStub android:id="@+id/content_viewstub" android:layout="@layout/activity_main_viewstub" android:layout_width="match_parent" android:layout_height="match_parent"/> <FrameLayout android:id="@+id/frame" android:layout_width="match_parent" android:layout_height="match_parent" > </FrameLayout> </RelativeLayout>
ps:測試數據是在老款三星手機下所得耗時數據。
不過相較于SplashActivity+MainActivity
啟動速度優化還是挺明顯的。大家可以在自己手機上試試。
原文鏈接:https://juejin.cn/post/7036981414893453319
相關推薦
- 2022-05-29 Docker鏡像與容器的導入導出操作實踐_docker
- 2022-07-09 利用go語言實現查找二叉樹中的最大寬度_Golang
- 2022-04-12 C++中菱形繼承的解釋與處理詳解_C 語言
- 2022-04-24 python文件與路徑管理方法_python
- 2023-04-24 Android布局控件View?ViewRootImpl?WindowManagerService關
- 2022-10-28 C++異步操作future和aysnc與function和bind_C 語言
- 2021-12-08 教你如何在windows?10家庭版上安裝docker_docker
- 2022-09-22 Pod 生命周期、重啟策略、健康檢查、服務可用性檢查
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支