小酌雞湯
富貴必從勤苦得猿挚,男兒須讀五車書硝清。
本文來源《Android 性能優(yōu)化 全家桶》
StrictMode能檢測什么呢弄企?
?StrictMode主要檢測兩大問題:線程策略(TreadPolicy)和VM策略(VmPolicy)寒跳。
StrictMode的工作原理硕淑?
?StrictMode最常用于在應(yīng)用程序的主線程上捕獲意外的磁盤或網(wǎng)絡(luò)訪問胚委,在該線程上接收UI操作并進(jìn)行動(dòng)畫處理挟鸠。使磁盤和網(wǎng)絡(luò)操作脫離主線程可以使應(yīng)用程序更加流暢,響應(yīng)更快亩冬。通過使應(yīng)用程序的主線程保持響應(yīng)狀態(tài)艘希,還可以防止向用戶顯示ANR對話框。
請注意硅急,即使Android設(shè)備的磁盤通常位于閃存中覆享,但許多設(shè)備在該內(nèi)存之上運(yùn)行文件系統(tǒng)的并發(fā)性非常有限。通常情況下营袜,幾乎所有磁盤訪問都是快速的撒顿,但是在某些情況下,某些進(jìn)程在后臺(tái)發(fā)生某些I / O時(shí)荚板,訪問速度可能會(huì)大大降低凤壁。如果可能的話吩屹,最好假設(shè)這種情況并不快。
ThreadPolicy線程策略
- 檢測所有可能的問題拧抖,使用detectAll()開啟煤搜;
- 調(diào)用速度緩慢的檢測,使用detectCustomSlowCalls()開啟唧席;
- 磁盤讀取操作擦盾,使用detectDiskReads()開啟;
- 磁盤寫入操作淌哟,使用detectDiskWrites()開啟厌衙;
- 網(wǎng)絡(luò)操作,使用detectNetwork()開啟;
- 檢測已定義資源類型和getter調(diào)用之間的不匹配的功能绞绒,使用detectResourceMismatches()開啟婶希;
- 檢測未緩沖的輸入/輸出操作,使用detectUnbufferedIo()開啟蓬衡。
VmPolicy虛擬機(jī)策略
- 檢測所有可能的問題喻杈,使用detectAll()開啟;
- 檢測Activity泄漏狰晚,使用detectActivityLeaks()開啟筒饰;
- 權(quán)限檢測,detectContentUriWithoutPermission()開啟壁晒;
- 未關(guān)閉的Closable對象泄漏瓷们,使用detectLeakedClosableObjects()開啟;
- 泄漏的Sqlite對象秒咐,使用detectLeakedSqlLiteObjects()開啟谬晕;
- 檢測實(shí)例數(shù)量,使用setClassInstanceLimit()開啟携取。
- 等等……
StrictMode的使用原則和技巧
?以名稱開頭的方法detect
指定了我們應(yīng)該尋找的問題攒钳。以名稱開頭的方法penalty
指定了檢測到問題時(shí)應(yīng)采取的措施。
?可以根據(jù)需要調(diào)用任意多個(gè)detect和penalty方法雷滋。順序微不足道:所有措施都適用于所有檢測到的問題不撑。
StrictMode如何使用?
?在Application
晤斩,Activity
或其他應(yīng)用程序組件Application.onCreate()
方法執(zhí)行前焕檬,添加StrictMode檢測。
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new ThreadPolicy.Builde()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new VmPolicy.Builde()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
如果觀測結(jié)果呢澳泵?
- AS IDE中的logat中篩選StrictMode信息
- adb logcat 進(jìn)行篩選StrictMode信息
現(xiàn)在实愚,就一起實(shí)操體驗(yàn) StrictMode 吧~
(1)StrictMode實(shí)操環(huán)境(可選項(xiàng),用自己的環(huán)境和代碼也一樣)
- SamplePop代碼下載
- SamplePop環(huán)境如下:
?Android Studio 4.0
?Gradle version 6.1.1
?Android API version 30
(2)舉個(gè)栗子:主線程中的文件寫入的檢查
(2.1)代碼啟用全部的ThreadPolicy和VmPolicy違例檢測
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
//代碼啟用全部的ThreadPolicy和VmPolicy違例檢測
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//執(zhí)行模擬測試
writeToFileInMainThread();
}
/**
* 主線程寫文件
*/
public void writeToFileInMainThread() {
File destFile = new File(Environment.getExternalStoragePublicDirectory
(Environment.DIRECTORY_DOWNLOADS).getPath(), "StrictModeTest.txt");
try {
destFile.createNewFile();
destFile.setWritable(true);
OutputStream output = new FileOutputStream(destFile, true);
output.write("IO operation".getBytes());
output.flush();
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
(2.2)運(yùn)行應(yīng)用,觀察logcat的輸出:
(2.3)解決StrictMode檢查錯(cuò)誤
/**
* 子線程寫文件
*/
public void writeToFileInSubThread() {
new Thread(new Runnable() {
@Override
public void run() {
writeToFileInMainThread();
}
}).start();
}
(3)舉個(gè)栗子:內(nèi)存泄漏的檢查
(3.1)讓LeakActivity產(chǎn)生內(nèi)存泄漏
public class LeakActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_leak);
ActivityManager.getInstance().mActivities.add(this);
}
}
(3.2)ActivityManager中關(guān)于mActivities的部分實(shí)現(xiàn)
public class ActivityManager {
private static ActivityManager mInstance = new ActivityManager();
public ArrayList<Activity> mActivities = new ArrayList<>();
private ActivityManager(){
}
public static ActivityManager getInstance() {
return mInstance;
}
}
(3.3)引發(fā)內(nèi)存泄漏
?不斷從MainActivity打開LeakActivity爆侣,再返回萍程,再打開,如此反復(fù)操作兔仰,引發(fā)內(nèi)存泄漏茫负。
public void onLeakActivityStart(View view) {
Log.d(TAG, "onLeakActivityStart: ");
startActivity(new Intent(this, LeakActivity.class));
}
(3.4)運(yùn)行應(yīng)用,觀察logcat的輸出:
(4)舉個(gè)栗子:自定義檢測類的實(shí)例泄漏
(4.1)開啟實(shí)例檢測乎赴,當(dāng)LeakActivity類出現(xiàn)多于一個(gè)實(shí)例時(shí)忍法,就報(bào)告內(nèi)存泄漏
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().setClassInstanceLimit(LeakActivity.class, 1).penaltyLog().build());
(4.2)運(yùn)行應(yīng)用,觀察logcat的輸出:
(5)舉個(gè)栗子:耗時(shí)調(diào)用(noteSlowCall)
(5.1)耗時(shí)調(diào)用檢測榕吼,適用于自定義的任務(wù)執(zhí)行類中饿序,比如:
public class FastRunTask {
private static final int MAX_RUN_VALID_DURATION = 300;
public void execute(Runnable task) {
long startTime = SystemClock.uptimeMillis();
task.run();
long useTime = SystemClock.uptimeMillis() - startTime;
if (useTime > MAX_RUN_VALID_DURATION) {
StrictMode.noteSlowCall("FastRunTask note slow call use time : [" + useTime + "]");
}
}
}
(5.2)執(zhí)行耗時(shí)任務(wù):
public void onFastRunTask(View view) {
Log.d(TAG, "onFastRunTask: ");
FastRunTask fastRunTask = new FastRunTask();
fastRunTask.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
(5.3)運(yùn)行應(yīng)用,觀察logcat的輸出:
(6)StrictMode小結(jié)
- 主要作用:查找可能會(huì)長時(shí)間運(yùn)行的操作羹蚣,例如您可能會(huì)無意中在主線程中執(zhí)行的網(wǎng)絡(luò)或數(shù)據(jù)庫操作原探。
-
注意項(xiàng):
?StrictMode無法監(jiān)控JNI中的磁盤IO和網(wǎng)絡(luò)請求
?應(yīng)用中并非需要解決全部的違例情況,比如有些IO操作必須在主線程中進(jìn)行顽素。
?通常情況下StrictMode給出的耗時(shí)相對實(shí)際情況偏高咽弦,并不是真正的耗時(shí)數(shù)據(jù)。 -
如何修復(fù)問題:如果你發(fā)現(xiàn)你的感覺有問題的違規(guī)行為胁出,有各種各樣的工具來幫助解決這些問題:線程型型,
Handler
,AsyncTask
全蝶,IntentService
等闹蒜。
注意:StrictMode不是安全機(jī)制,不能保證找到所有磁盤或網(wǎng)絡(luò)訪問抑淫。盡管在執(zhí)行
Binder
調(diào)用時(shí)確實(shí)跨進(jìn)程邊界傳播了狀態(tài)绷落,但它最終仍是盡力而為的機(jī)制。未來的Android版本可能會(huì)執(zhí)行更多(或更少)操作丈冬,因此您永遠(yuǎn)不要在發(fā)布的應(yīng)用程序中啟用StrictMode嘱函。
一起來啟用 StrictModel 查看自己的項(xiàng)目吧~
小編的擴(kuò)展鏈接
參考鏈接
狀似明月泛云河甘畅,體如輕風(fēng)動(dòng)流波
?
舉手之勞埂蕊,贊有余香!???比心??
?