一、冷熱啟動(dòng)概念:
1、冷啟動(dòng):冷啟動(dòng)因?yàn)橄到y(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給它,所以會(huì)先創(chuàng)建和初始化Application類(lèi),再創(chuàng)建和初始化MainActivity類(lèi)(包括一系列的測(cè)量、布局、繪制),最后顯示在界面上。
2、熱啟動(dòng):熱啟動(dòng)因?yàn)闀?huì)從已有的進(jìn)程中來(lái)啟動(dòng),所以熱啟動(dòng)就不會(huì)走Application這步了,而是直接走M(jìn)ainActivity(包括一系列的測(cè)量、布局、繪制),所以熱啟動(dòng)的過(guò)程只需要?jiǎng)?chuàng)建和初始化一個(gè)MainActivity就行了,而不必創(chuàng)建和初始化Application,因?yàn)橐粋€(gè)應(yīng)用從新進(jìn)程的創(chuàng)建到進(jìn)程的銷(xiāo)毀,Application只會(huì)初始化一次。
二、冷啟動(dòng)流程:
應(yīng)用的第一次啟動(dòng)才算完成,這時(shí)候我們看到的界面也就是所說(shuō)的第一幀。所以,總結(jié)一下,應(yīng)用的啟動(dòng)流程如下:
Application的創(chuàng)建和初始化——>attachBaseContext()——>onCreate()——>Activity的構(gòu)造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>contentView的measure/layout/draw顯示在界面上。
三、工具和分析方法:
1、測(cè)量activity的啟動(dòng)時(shí)間-------Activity的reportFullyDrawn()方法
2、adb shell screenrecord --bugreport /sdcard/launch.mp4 錄制屏幕
優(yōu)化方法:
1、不要讓Application參與業(yè)務(wù)的操作
2、不要在APPlication進(jìn)行耗時(shí)操作,比如有些開(kāi)發(fā)者會(huì)在自己的APP里一系列文件夾或文件(比如我自己),這些I/O操作應(yīng)該放到"確實(shí)該使用的時(shí)候再去創(chuàng)建"亦或者是數(shù)據(jù)庫(kù)的一些操作。
3、不要以靜態(tài)變量的方式在Application中保存數(shù)據(jù)等。
java代碼優(yōu)化
1、緩存:需要頻繁訪問(wèn),或者訪問(wèn)一次開(kāi)銷(xiāo)比較大的:
需要重復(fù)用到的,可以緩存下來(lái),比如res.getstring()這種
其他緩存:圖片緩存、線程池、消息緩存handler.obtainMessage()、
2、數(shù)據(jù)結(jié)構(gòu)的選擇:
Android也提供了一些性能更優(yōu)的數(shù)據(jù)類(lèi)型,如SparseArray、SparseBooleanArray、SparseIntArray、Pair。
Sparse系列的數(shù)據(jù)結(jié)構(gòu)是為key為int情況的特殊處理,采用二分查找及簡(jiǎn)單的數(shù)組存儲(chǔ),加上不需要泛型轉(zhuǎn)換的開(kāi)銷(xiāo),相對(duì)Map來(lái)說(shuō)性能更優(yōu)。
3、算法的選擇:
盡量不用o(n*2)的算法;有必要的時(shí)間以空間換時(shí)間
4、異步:
耗時(shí)操作放到異步線程里面去執(zhí)行
5、提前或延遲操作,錯(cuò)開(kāi)時(shí)間段提高TPS
(1) 延遲操作:不在Activity、Service、BroadcastReceiver的生命周期等對(duì)響應(yīng)時(shí)間敏感函數(shù)中執(zhí)行耗時(shí)操作,可適當(dāng)delay。Android中可以采取handler.postDelayed,handler.postAtTime,handler.sendMessageDelayed,View.postDelayed,AlarmManager定時(shí)等。
布局優(yōu)化:
工具:hierarchy viewer、lint
策略:減少布局的復(fù)雜性,布局深度
方法:
1、include
2、merge
3、viewstub默認(rèn)不會(huì)顯示,需要的時(shí)候再inflate; gone
4、listview的優(yōu)化:復(fù)用convertview, viewHolder來(lái)減少findviewById, 局部更新
5、用SurfaceView或TextureView代替普通View:
他們可以通過(guò)將繪圖操作移動(dòng)到另一個(gè)單獨(dú)線程上提高性能;因?yàn)镾urfaceView在常規(guī)視圖系統(tǒng)之外,所以無(wú)法像常規(guī)試圖一樣移動(dòng)、縮放或旋轉(zhuǎn)一個(gè)SurfaceView。TextureView是Android4.0引入的,除了與SurfaceView一樣在單獨(dú)線程繪制外,還可以像常規(guī)視圖一樣被改變。
6、盡量為所有分辨率創(chuàng)建資源,減少不必要的硬件縮放,這會(huì)降低UI的繪制速度
數(shù)據(jù)庫(kù)優(yōu)化
1、索引:
CREATE INDEX mycolumn_index ON mytable (myclumn)
好處:索引可以大大查詢(xún)的速度;包括對(duì)表查詢(xún)、連表查詢(xún)、分組查詢(xún)、排序查詢(xún)
壞處:增刪改需要維護(hù)索引,影響性能;而且索引需要占用一定的物理空間
適用場(chǎng)景:更新頻率較低,查詢(xún)頻率較高,經(jīng)常有范圍查詢(xún)(>, <, =, >=, <=)或order by、group by發(fā)生時(shí)的字段建議使用索引;經(jīng)常同時(shí)存取多列,且每列都含有重復(fù)值可考慮建立復(fù)合索引
2、事務(wù):
Sqlite默認(rèn)會(huì)為每個(gè)插入、更新操作創(chuàng)建一個(gè)事務(wù),并且在每次插入、更新后立即提交(創(chuàng)建事務(wù)->執(zhí)行語(yǔ)句->提交);優(yōu)化的方式是,批量操作時(shí),創(chuàng)建事務(wù)->執(zhí)行n條語(yǔ)句->提交
public void insertWithOneTransaction() {
SQLiteDatabase db = sqliteOpenHelper.getWritableDatabase();
// Begins a transaction
db.beginTransaction();
try {
// your sqls
for (int i = 0; i < 100; i++) {
db.insert(yourTableName, null, value);
}
// marks the current transaction as successful
db.setTransactionSuccessful();
} catch (Exception e) {
// process it
e.printStackTrace();
} finally {
// end a transaction
db.endTransaction();
}
}
3、數(shù)據(jù)庫(kù)查詢(xún)操作放到異步線程里面去做
4、語(yǔ)句的拼接使用StringBuilder代替String
這個(gè)就不多說(shuō)了,簡(jiǎn)單的string相加會(huì)導(dǎo)致創(chuàng)建多個(gè)臨時(shí)對(duì)象消耗性能。StringBuilder的空間預(yù)分配性能好得多。如果你對(duì)字符串的長(zhǎng)度有大致了解,如100字符左右,可以直接new StringBuilder(128)指定初始大小,減少空間不夠時(shí)的再次分配。
5、查詢(xún)時(shí)返回更少的結(jié)果集及更少的字段。
查詢(xún)時(shí)只取需要的字段和結(jié)果集,更多的結(jié)果集會(huì)消耗更多的時(shí)間及內(nèi)存,更多的字段會(huì)導(dǎo)致更多的內(nèi)存消耗。
6、少用cursor.getColumnIndex,用static變量記住某一列的index
根據(jù)性能調(diào)優(yōu)過(guò)程中的觀察cursor.getColumnIndex的時(shí)間消耗跟cursor.getInt相差無(wú)幾??梢栽诮ū淼臅r(shí)候用static變量記住某列的index,直接調(diào)用相應(yīng)index而不是每次查詢(xún)。
其他:
視覺(jué)體驗(yàn)上的“快”:
為啟動(dòng)的Activity自定義一個(gè)Theme,Theme里的windowBackground設(shè)置成我們想要讓用戶(hù)看到的畫(huà)面;
為啟動(dòng)的Activity自定義一個(gè)Theme
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/window_background_statusbar_toolbar_tab</item>
</style>
將新的Theme應(yīng)用到設(shè)置到AndroidManifest.xml中
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme.Launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
由于給MainActivity設(shè)置了一個(gè)新的Theme,這樣做會(huì)覆蓋原來(lái)的Theme,所以在MainActivity中需要設(shè)置回原來(lái)的Theme