Android卡頓優(yōu)化 | 卡頓及其優(yōu)化工具概述及StrictMode實(shí)踐案例

項(xiàng)目GitHub

本文要點(diǎn)

  • 一般使用的卡頓優(yōu)化工具
  • 卡頓問(wèn)題概述
  • 卡頓問(wèn)題分析難點(diǎn)
  • 關(guān)于CPU Profiler
  • 關(guān)于Systrace
  • 關(guān)于StrictMode
  • 磁盤(pán)讀寫(xiě)違例檢測(cè)實(shí)戰(zhàn)
  • 實(shí)例限制檢測(cè)實(shí)戰(zhàn)

一般使用的卡頓優(yōu)化工具

  • CPU Profiler
  • Systrace
  • StrictMode
    (strict adj.精確的; 絕對(duì)的; 嚴(yán)格的,嚴(yán)謹(jǐn)?shù)模?[植]筆直的
    mode n.方式; 狀況; 時(shí)尚,風(fēng)尚; 調(diào)式 模式;)

卡頓問(wèn)題概述

  • 很多性能問(wèn)題(如內(nèi)存占用高躬络、耗費(fèi)流量等)都相對(duì)不容易被發(fā)現(xiàn),
    但是卡頓問(wèn)題卻是很容易被直觀感受到的搭儒;
  • 卡頓問(wèn)題較難排查穷当、定位;

卡頓問(wèn)題分析難點(diǎn)

  • 可能的產(chǎn)生原因 繁雜:代碼淹禾、內(nèi)存馁菜、繪制、IO稀拐、【在主線程做UI處理火邓、IO操作耗時(shí)操作】等;
  • 線上卡頓問(wèn)題,在線下難以復(fù)現(xiàn)铲咨,
    卡頓問(wèn)題跟用戶屆時(shí)的現(xiàn)場(chǎng)環(huán)境有很大的關(guān)系躲胳;
  • 比如,
    屆時(shí)用戶終端的磁盤(pán)IO空間不足纤勒,影響了APP的IO寫(xiě)入性能坯苹,
    導(dǎo)致APP卡頓,這樣的場(chǎng)景有時(shí)候是很難復(fù)現(xiàn)的摇天;
    【最好在問(wèn)題發(fā)生時(shí)候粹湃,就記錄下來(lái)用戶屆時(shí)的場(chǎng)景】

關(guān)于CPU Profiler

  • 圖形的形式展示程序的執(zhí)行時(shí)間、調(diào)用棧泉坐、執(zhí)行次數(shù)等为鳄;

  • 信息全面,包含了所有線程腕让、所有方法的調(diào)用時(shí)間孤钦;

  • 運(yùn)行時(shí)開(kāi)銷比較嚴(yán)重,導(dǎo)致APP運(yùn)行時(shí)所有函數(shù)都會(huì)不等比地變慢纯丸,可能會(huì)帶偏優(yōu)化方向偏形;

  • 使用方式

    • Debug.startMethodTracing();【在需要監(jiān)控的代碼塊前添加(注意它有四個(gè)重載方法)】
    • Debug.stopMethodTracing();【在需要監(jiān)控的代碼塊后添加】
    • 生成的調(diào)試文件在sd卡:Android/data/packagename/files
    • 上次在內(nèi)存優(yōu)化的實(shí)戰(zhàn)中,
      其實(shí)已經(jīng)使用過(guò)觉鼻,提到過(guò)CPU Profiler了俊扭,
      這里可以看一下App內(nèi)存優(yōu)化 之 內(nèi)存抖動(dòng)解決實(shí)戰(zhàn)!W钩隆H蟆!3╂ⅰ咒钟!

關(guān)于Systrace

關(guān)于StrictMode

  • 嚴(yán)苛模式隙疚,Android提供的一種運(yùn)行時(shí)檢測(cè)機(jī)制;
    如果在開(kāi)發(fā)階段對(duì)成千上萬(wàn)行的代碼進(jìn)行code review磕道,
    可能效率是比較低下的供屉;
    使用StrictMode之后,
    系統(tǒng)會(huì)自動(dòng)檢測(cè)出來(lái)主線程當(dāng)中違例的一些情況,
    同時(shí)按照代碼的配置給出相應(yīng)的反應(yīng)伶丐。

  • 方便悼做,強(qiáng)大,容易被忽視

  • 主要檢測(cè):線程檢測(cè)策略哗魂、虛擬機(jī)檢測(cè)策略

    • 線程檢測(cè)策略【StrictMode.setThreadPolicy()】:
      如肛走,
      自定義的耗時(shí)調(diào)用檢測(cè),如detectCustomSlowCalls()录别;
      磁盤(pán)讀取操作檢測(cè)朽色,detectDiskReads()
      網(wǎng)絡(luò)操作檢測(cè),detectNetwork()
      【detect vt.查明组题,發(fā)現(xiàn)葫男; 洞察; 偵察崔列,偵查腾誉; 】
    • 虛擬機(jī)策略【StrictMode.setVmPolicy()】:
      Activity泄漏檢測(cè),detectActivityLeaks()
      SqlLite對(duì)象泄漏檢測(cè)峻呕,detectLeakedSqlLiteObjects()
      限制實(shí)例數(shù)量檢測(cè)利职,setClassInstanceLimit(要限制的類實(shí)例,限制的數(shù)量)
  • 具體使用:
    可以在Activity或者ApplicationonCreate()中調(diào)用StrictMode的方法:

private boolean DEV_MODE = true;

    private void initStrictMode() {
        if (DEV_MODE) {
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectCustomSlowCalls() //API等級(jí)11瘦癌,使用StrictMode.noteSlowCode
                    .detectDiskReads()
                    .detectDiskWrites()
                    .detectNetwork()// or .detectAll() for all detectable problems
                    .penaltyLog() //在Logcat 中打印違規(guī)異常信息
                    .build());

            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects()
                    .setClassInstanceLimit(NewsItem.class, 1)
                    .detectLeakedClosableObjects() //API等級(jí)11
                    .penaltyLog()
                    .build());
        }
    }
  • 【調(diào)試技巧】
    設(shè)置一個(gè)DEV_MODE標(biāo)志位:
    只有在線下開(kāi)發(fā)的環(huán)境時(shí)將之設(shè)置為true猪贪,才會(huì)使進(jìn)程打開(kāi)StrictMode

  • 【檢測(cè)策略的調(diào)用】
    detect開(kāi)頭的方法讯私,
    都是StrictMode提供的檢測(cè)策略热押,
    調(diào)用過(guò)了,則StrictMode便會(huì)進(jìn)行相應(yīng)的檢測(cè)和反應(yīng)斤寇;

  • 【響應(yīng)方式配置】
    penaltyLog()【penalty n.懲罰桶癣,刑罰,害處】是出現(xiàn)違規(guī)后用log打印出來(lái)娘锁,即指定StrictMode的響應(yīng)方式牙寞,
    StrictMode除了打印log的方式,
    還有其他響應(yīng)方式莫秆,
    penaltyDeath()可以讓APP直接崩潰掉间雀,
    penaltyDialog()可以彈出一個(gè)Dialog等!D魇骸H切!7觳怠A狻9椴浴E缁А滤钱!

  • 實(shí)戰(zhàn)一下:
    磁盤(pán)讀寫(xiě)違例檢測(cè)(log的響應(yīng)方式):

/**
 * 模擬內(nèi)存泄露的Activity
 */
public class MemoryLeakActivity extends AppCompatActivity implements CallBack{

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memoryleak);

        ImageView imageView = findViewById(R.id.iv_memoryleak);
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.splash);
        imageView.setImageBitmap(bitmap);

        CallBackManager.addCallBack(this);

        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads()
                .detectDiskWrites()
                .penaltyLog()
                .build());

        findViewById(R.id.iv_memoryleak).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                writeToExternalStorage();
            }
        });
    }

    /**
     * 文件系統(tǒng)的操作
     */
    public void writeToExternalStorage() {
        try {
            File externalStorage = Environment.getExternalStorageDirectory();

            File mbFile = new File(externalStorage, "xxx.txt");
            if (mbFile.exists()){
                mbFile.createNewFile();
            }

            OutputStream output = new FileOutputStream(mbFile, true);
            output.write("www.wooyun.org".getBytes());
            output.flush();
            output.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        CallBackManager.removeCallBack(this);
    }

    @Override
    public void dpOperate() {
        // do sth
    }
}

Dialog的響應(yīng)方式:

以上IO違例的原因就是在主線程做了IO操作了
這顯然是不行的或南,需要開(kāi)一個(gè)子線程給它整驳规!

  • 實(shí)例限制檢測(cè):
public class TestApp extends Application {

    static MemoryLeakActivity i = new MemoryLeakActivity();
    static MemoryLeakActivity j = new MemoryLeakActivity();

    @Override
    public void onCreate() {
        super.onCreate();

        //實(shí)例限制檢測(cè) 測(cè)試
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .setClassInstanceLimit(MemoryLeakActivity.class, 1)
                .detectLeakedClosableObjects() //API等級(jí)11
                .penaltyLog()
                .build());
    }
}










最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肴敛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吗购,更是在濱河造成了極大的恐慌医男,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捻勉,死亡現(xiàn)場(chǎng)離奇詭異镀梭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)踱启,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門报账,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人埠偿,你說(shuō)我怎么就攤上這事透罢。” “怎么了冠蒋?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵羽圃,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我抖剿,道長(zhǎng)朽寞,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任斩郎,我火速辦了婚禮脑融,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘缩宜。我一直安慰自己肘迎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布脓恕。 她就那樣靜靜地躺著膜宋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪炼幔。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天史简,我揣著相機(jī)與錄音乃秀,去河邊找鬼肛著。 笑死,一個(gè)胖子當(dāng)著我的面吹牛跺讯,可吹牛的內(nèi)容都是我干的枢贿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼刀脏,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼局荚!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起愈污,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耀态,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后暂雹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體首装,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年杭跪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仙逻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡涧尿,死狀恐怖系奉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情姑廉,我是刑警寧澤喜最,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站庄蹋,受9級(jí)特大地震影響瞬内,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜限书,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一虫蝶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧倦西,春花似錦能真、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至卤档,卻和暖如春蝙泼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背劝枣。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工汤踏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留织鲸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓溪胶,卻偏偏與公主長(zhǎng)得像搂擦,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哗脖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354