問題
一般沒有特殊處理,android啓動的時候,會出現白屏或者黑屏的狀態,體驗很差。究其原因,白屏是app在冷啓動的時候,初始化,系統自動用默認的背景色來填充屏幕。這個默認的背景色和你定義的app主題有關。比如如果你的主題繼承自Theme.AppCompat.Light.NoActionBar
,那麼啓動的時候就是白色。
本章就來解決app啓動慢的問題。
解決
我所瞭解到的,一般解決這個問題的方法有兩種:
-
將這個背景色改爲透明色。雖然看上去沒有白屏的狀況,但用戶點擊app後,原先白屏的那段時間變成了桌面背景,讓人感覺啓動慢是手機系統的鍋,跟app沒啥。有點甩鍋的意思。
具體做法是在
style
中添加主題<style name="AppTheme.SplashTheme" parent="Theme.AppCompat.Light.NoActionBar"> <item name="android:windowFullscreen">true</item> <item name="android:windowIsTranslucent">true</item> </style>
注意這裏
windowIsTranslucent
屬性就是設置背景色透明的關鍵代碼。然後在AndroidManifest
中將啓動的那個activity
的theme
設置爲這個主題
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
```
-
第一種方法說白了只是給用戶一個假象,“是你手機系統的問題,不是我app的問題”。既然能把背景改成透明的,那爲什麼不能直接改成我的splash頁的背景圖片呢,這樣白屏的那段時間,先用這個背景圖片,當splash頁加載好的時候,無縫銜接,但用戶看到的就是,”不錯這個很快,點了沒有任何停頓,立馬啓動。“。
具體方法,只要將剛纔的那個
AppTheme.SplashTheme
的屬性改一改。
```
這裏的`windowBackground`就是設置背景圖片的關鍵代碼,那段冷啓動的時間,屏幕就被設置成這張圖片。接下來使用一樣,在`AndroidManifest`註冊使用即可。強力推薦。
再優化
搞定了白屏問題,我們再來看看一般app使用splash頁啓動的方法,可能最一般的做法就是將啓動頁做成一個Activity,啓動完跳轉到MainActivity。
SplashActivity
-> MainActivity
但是這樣是不是有些浪費,SplashActivity
運行期間,app應當可以做一些初始化,加載數據的工作,減輕MainActivity
的負擔。所以SplashActivity
就不需要了,splash可以使用全屏的dialog
代替,用完直接銷燬。如此,app啓動更快了。加載完splash, MainActivity
的數據頁加載好了。
這裏提供一個封裝好的實現:SplashDialog
public class SplashScreen {
private Dialog splashDialog;
private Activity activity;
public SplashScreen(Activity activity) {
this.activity = activity;
}
/**
* 顯示splash圖片
*
* @param millis 停留時間 毫秒
*
*/
public void show(final int millis) {
Runnable runnable = new Runnable() {
public void run() {
DisplayMetrics metrics = new DisplayMetrics();
final ImageView root = new ImageView(activity);
root.setMinimumHeight(metrics.heightPixels);
root.setMinimumWidth(metrics.widthPixels);
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, 0.0F));
root.setScaleType(ImageView.ScaleType.FIT_XY);
//glide加載圖片
GlideApp.with(activity)
.load(URL_SPLASH_IMAGE)
.placeholder(R.drawable.splash)
.error(R.drawable.splash)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(root);
splashDialog = new Dialog(activity, android.R.style.Theme_NoTitleBar_Fullscreen);
Window window = splashDialog.getWindow();
window.setWindowAnimations(R.style.dialog_anim_fade_out);
splashDialog.setContentView(root);
splashDialog.setCancelable(false);
splashDialog.show();
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
removeSplash();
}
}, millis);
}
};
activity.runOnUiThread(runnable);
}
private void removeSplash() {
if (splashDialog != null && splashDialog.isShowing()) {
splashDialog.dismiss();
splashDialog = null;
}
}
}
這裏我使用了glide來加載圖片,你也可以更改爲自己的加載工具。
在 MainActivity
使用,oncreate
之後直接調用,new SplashDialog(this).show(3000);
啓動頁變得只需要一行代碼,而且更快,更方便。ps:別忘了給MainActivity
加上之前的主題。
踩坑
上面提到了第二種方法,設置背景圖片。這裏遇到了一個坑,如果有類似問題可以參考。
我的 MainActivity
設置了浸入式的狀態欄,但是沒有設置透明底部導航欄。導致設置背景圖片windowBackground
的高度是加上了底部導航欄,也就是說導航欄擋住了一部分的背景圖片,但是SplashDialog
加載的圖片是忽略底部導航欄的,這樣這兩張圖就會有個錯位,啓動的時候,會出現圖片的位置移動了一下。
解決方法是,在前面的AppTheme.SplashTheme
中,繼承自@android:style/Theme.Light.NoTitleBar.Fullscreen
,即老版本的theme,不要繼承自Theme.AppCompat.Light.NoActionBar
。原因猜想是,老版本不支持佔用導航欄的空間,自然也就不會有被導航欄擋住的情況。