(十三)Android 性能優(yōu)化 StrictMode

小酌雞湯

富貴必從勤苦得猿挚,男兒須讀五車書硝清。

本文來源《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的輸出:
StrictMode 主線程寫文件
(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的輸出:
StrictMode 內(nèi)存泄漏
(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的輸出:
StrictMode 實(shí)例檢測
(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的輸出:
StrictMode 耗時(shí)調(diào)用
(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ī)行為胁出,有各種各樣的工具來幫助解決這些問題:線程型型,HandlerAsyncTask全蝶,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)流波

?

舉手之勞埂蕊,贊有余香!???比心??

?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疏唾,一起剝皮案震驚了整個(gè)濱河市蓄氧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌槐脏,老刑警劉巖喉童,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異顿天,居然都是意外死亡堂氯,警方通過查閱死者的電腦和手機(jī)蔑担,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咽白,“玉大人啤握,你說我怎么就攤上這事【Э颍” “怎么了排抬?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵妓肢,是天一觀的道長搬泥。 經(jīng)常有香客問我,道長索赏,這世上最難降的妖魔是什么侵贵? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任届搁,我火速辦了婚禮,結(jié)果婚禮上窍育,老公的妹妹穿的比我還像新娘咖祭。我一直安慰自己,他們只是感情好蔫骂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布么翰。 她就那樣靜靜地躺著,像睡著了一般辽旋。 火紅的嫁衣襯著肌膚如雪浩嫌。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天补胚,我揣著相機(jī)與錄音码耐,去河邊找鬼。 笑死溶其,一個(gè)胖子當(dāng)著我的面吹牛骚腥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瓶逃,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼束铭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了厢绝?” 一聲冷哼從身側(cè)響起契沫,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昔汉,沒想到半個(gè)月后懈万,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年会通,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了口予。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涕侈,死狀恐怖苹威,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情驾凶,我是刑警寧澤牙甫,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站调违,受9級特大地震影響窟哺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜技肩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一且轨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虚婿,春花似錦旋奢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至剧浸,卻和暖如春锹引,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背唆香。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工嫌变, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躬它。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓腾啥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親冯吓。 傳聞我的和親對象是個(gè)殘疾皇子倘待,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354