Android優(yōu)化提升應(yīng)用啟動速度及Splash頁面的設(shè)計(jì)
1.啟動分為兩種方式
- 1) 冷啟動:當(dāng)直接從桌面上直接啟動,同時(shí)后臺沒有該進(jìn)程的緩存,這個(gè)時(shí)候系統(tǒng)就需要重新創(chuàng)建一個(gè)新的進(jìn)程并且分配各種資源。
- 2) 熱啟動:該
app后臺有該進(jìn)程的緩存,這時(shí)候啟動的進(jìn)程就屬于熱啟動。 - 熱啟動不需要重新分配進(jìn)程,也不會
Application了,直接走的就是app的入口Activity,這樣速度就很快
2.如何測量一個(gè)應(yīng)用的啟動時(shí)間
使用命令行來啟動app,同時(shí)進(jìn)行時(shí)間測量。單位:毫秒
?adb shell am start - W [PackageName] /[PackageName.MainActivity]
例: adb shell am start -W com.haocai.app/.activity.GuideActivity


熱啟動耗時(shí):
打印的結(jié)果為:
ThisTime該activity啟動耗時(shí)TotalTime應(yīng)用自身啟動耗時(shí)=ThisTime+應(yīng)用application等資源啟動時(shí)間WaitTime系統(tǒng)啟動應(yīng)用耗時(shí)=TotalTime+系統(tǒng)資源啟動時(shí)間
3.應(yīng)用啟動的流程
Application從構(gòu)造方法開始 ---> attachBaseContext() ---> onCreate()構(gòu)造方法 --->
ActivityonCreate() ---> 設(shè)置顯示界面布局,設(shè)置主題、背景等等屬性 ---> onStart()--->
onResume() ---> 顯示里面的View(測量、布局、繪制,顯示到界面上)
從構(gòu)造方法我們知道,啟動耗時(shí)的主要花費(fèi)在各個(gè)啟動流程中
4.減少應(yīng)用的啟動時(shí)間的耗時(shí)
根據(jù)應(yīng)用的啟動流程,我們從而得到以下減少應(yīng)用啟動耗時(shí)操作的建議:
- 不要在
Application的構(gòu)造方法、attachBaseContext()、onCreate()里面進(jìn)行初始化耗時(shí)操作。 - MainActivity,由于用戶只關(guān)心最后顯示的這一幀,對我們的布局的層次要求減 自定義控件的測量、布局、繪制的時(shí)間。 同時(shí) 不要在
onCreate、onStart、onResume當(dāng)中的做耗時(shí)操作。 - 對于
SharedPreference的初始化
因?yàn)樗跏蓟臅r(shí)候是需要將數(shù)據(jù)全部讀取出來放到內(nèi)存當(dāng)中。
- 優(yōu)化1:可以盡可能減少sp文件數(shù)量(IO需要時(shí)間)
- 優(yōu)化2:像這樣的初始化最好放到線程里面
- 優(yōu)化3:大量的數(shù)據(jù)緩存到數(shù)據(jù)庫中
app啟動的耗時(shí)主要在:Application初始化 + MainActivity的界面加載繪制時(shí)間。
由于MainActvity的業(yè)務(wù)和布局復(fù)雜度非常高,甚至該界面必須要有一些初始化的數(shù)據(jù)才能顯示。
那么這個(gè)時(shí)候MainActivity就可能半天都出不來,這就給用戶感覺App太卡了。
常規(guī)方法:
1.我們要做的就是給用戶趕緊利落的體驗(yàn)。點(diǎn)擊app就立馬彈出我們的界面。
于是乎想到使用SplashActivity--非常簡單的一個(gè)歡迎頁面上面都不干就只顯示一個(gè)圖片。
2.但是SplashActivity啟動之后,還是需要跳到MainActivity。MainActivity還是需要從頭開始加載布局和數(shù)據(jù)。
想到SplashActivity里面可以去做一些MainActivity的數(shù)據(jù)的預(yù)加載。然后需要通過意圖傳到MainActivity。
更好的優(yōu)化:
耗時(shí)的問題:Application+Activity的啟動及資源加載時(shí)間;預(yù)加載的數(shù)據(jù)花的時(shí)間。
如果我們能讓這兩個(gè)時(shí)間重疊在一個(gè)時(shí)間段內(nèi)并發(fā)地做這兩個(gè)事情就省時(shí)間了。
比如:將SplashActivity和MainActivity合為一個(gè)。
一進(jìn)來還是顯示MainActivity,SplashActivity可以變成一個(gè)SplashFragment,然后放一個(gè)FrameLayout作為根布局直接顯示SplashFragment界面。
SplashFragment里面非常之簡單,就是現(xiàn)實(shí)一個(gè)圖片,啟動非??臁?/p>
當(dāng)SplashFragment顯示完畢后再將它remove。同時(shí)在splash的2S的友好時(shí)間內(nèi)進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)緩存。
這個(gè)時(shí)候我們才看到MainActivity,就不必再去等待網(wǎng)絡(luò)數(shù)據(jù)返回了。
新問題:SplashView和ContentView加載放到一起來做了 ,這可能會影響應(yīng)用的啟動時(shí)間?
解決:可以使用ViewStub延遲加載MainActivity當(dāng)中的View來達(dá)到減輕這個(gè)影響。
viewStub的設(shè)計(jì)就是為了防止MainActivity的啟動加載資源太耗時(shí)了。延遲進(jìn)行加載,不影響啟動,用戶友好。
但是viewStub加載也需要時(shí)間。等到主界面出來以后。
viewStub.inflate(xxxx);
5.如何設(shè)計(jì)延遲加載DelayLoad
第一時(shí)間想到的就是在onCreate里面調(diào)用Handler.postDelayed()方法;
問題一:這個(gè)延時(shí)時(shí)間如何控制
不同的機(jī)器啟動速度不一樣,這個(gè)時(shí)間如何控制?
假設(shè),先需要splash做一個(gè)2s動畫,然后在MainActivity中主界面加載完成之后,關(guān)閉splash頁面
如果這樣寫:
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mProgressBar.setVisibility(View.GONE);
iv.setVisibility(View.VISIBLE);
}
}, 2500);
是無法在準(zhǔn)確監(jiān)聽頁面加載完的
問題:什么時(shí)候應(yīng)用已經(jīng)啟動并加載完成,界面已經(jīng)顯示出來了。
采用onResume執(zhí)行完了之后才顯示完畢?不行。
建議采用getDecorView() 獲取上級view 然后添加視圖
綜合上訴方案,以下是關(guān)鍵代碼:
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.判斷當(dāng)窗體加載完畢的時(shí)候,立馬再加載真正的布局進(jìn)來
getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
// 開啟延遲加載
mHandler.post(new Runnable() {
@Override
public void run() {
//將viewstub加載進(jìn)來
viewStub.inflate();
}
});
}
});
//2.判斷當(dāng)窗體加載完畢的時(shí)候執(zhí)行,延遲一段時(shí)間做動畫。
getWindow().getDecorView().post(new Runnable() {
@Override
public void run() {
// 開啟延遲加載,也可以不用延遲可以立馬執(zhí)行(我這里延遲是為了實(shí)現(xiàn)fragment里面的動畫效果的耗時(shí))
mHandler.postDelayed(new DelayRunnable(MainActivity.this, splashFragment), 2000);
}
});
//3.同時(shí)進(jìn)行異步加載數(shù)據(jù)
//......
}
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:測試數(shù)據(jù)是在老款三星手機(jī)下所得耗時(shí)數(shù)據(jù)。
不過相較于SplashActivity+MainActivity啟動速度優(yōu)化還是挺明顯的。大家可以在自己手機(jī)上試試。
到此這篇關(guān)于Android提升應(yīng)用啟動速度及Splash頁面的設(shè)計(jì)的文章就介紹到這了,更多相關(guān)Android性能優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
android調(diào)用WebService實(shí)例分析
這篇文章主要介紹了android調(diào)用WebService的方法,以實(shí)例形式較為詳細(xì)的分析了WebService的調(diào)用原理與具體使用方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10
Android EditText長按菜單中分享功能的隱藏方法
Android EditText控件是經(jīng)常使用的控件,下面這篇文章主要給大家介紹了關(guān)于Android中EditText長按菜單中分享功能的隱藏方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
Android?RecyclerChart其它圖表繪制示例詳解
這篇文章主要為大家介紹了Android?RecyclerChart其它圖表繪制示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
解決android關(guān)于打開虛擬機(jī)時(shí)右側(cè)工具欄不顯示的問題
下面小編就為大家分享一篇解決android關(guān)于打開虛擬機(jī)時(shí)右側(cè)工具欄不顯示的問題,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
andriod開發(fā)之Activity的渲染機(jī)制
本文給大家分享的是在andriod開發(fā)中經(jīng)常需要用到的Activity的渲染機(jī)制的詳細(xì)說明,主要是通過實(shí)例給大家講解Activity是如何畫到屏幕上的,希望大家能夠喜歡2018-03-03
Android安裝apk文件并適配Android 7.0詳解
這篇文章主要介紹了Android安裝apk文件并適配Android 7.0詳解的相關(guān)資料,需要的朋友可以參考下2017-05-05

