<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Android 編程下的 TraceView 簡介及其案例實(shí)戰(zhàn)

      TraceView 是 Android 平臺配備一個(gè)很好的性能分析的工具。它可以通過圖形化的方式讓我們了解我們要跟蹤的程序的性能,并且能具體到 method。詳細(xì)內(nèi)容參考:Profiling with Traceview and dmtracedump

      TraceView 簡介

      TraceView 是 Android 平臺特有的數(shù)據(jù)采集和分析工具,它主要用于分析 Android 中應(yīng)用程序的 hotspot。TraceView 本身只是一個(gè)數(shù)據(jù)分析工具,而數(shù)據(jù)的采集則需要使用 Android SDK 中的 Debug 類或者利用 DDMS 工具。二者的用法如下:

      • 開發(fā)者在一些關(guān)鍵代碼段開始前調(diào)用 Android SDK 中 Debug 類的 startMethodTracing 函數(shù),并在關(guān)鍵代碼段結(jié)束前調(diào)用 stopMethodTracing 函數(shù)。這兩個(gè)函數(shù)運(yùn)行過程中將采集運(yùn)行時(shí)間內(nèi)該應(yīng)用所有線程(注意,只能是 Java 線程)的函數(shù)執(zhí)行情況,并將采集數(shù)據(jù)保存到 /mnt/sdcard/ 下的一個(gè)文件中。開發(fā)者然后需要利用 SDK 中的 TraceView 工具來分析這些數(shù)據(jù)。
      • 借助 Android SDK 中的 DDMS 工具。DDMS 可采集系統(tǒng)中某個(gè)正在運(yùn)行的進(jìn)程的函數(shù)調(diào)用信息。對開發(fā)者而言,此方法適用于沒有目標(biāo)應(yīng)用源代碼的情況。

      DDMS 中 TraceView 使用示意圖如下,調(diào)試人員可以通過選擇 Devices 中的應(yīng)用后點(diǎn)擊 按鈕 Start Method Profiling(開啟方法分析)和點(diǎn)擊  Stop Method Profiling停止方法分析

      開啟方法分析后對應(yīng)用的目標(biāo)頁面進(jìn)行測試操作,測試完畢后停止方法分析,界面會(huì)跳轉(zhuǎn)到 DDMS 的 trace 分析界面,如下圖所示:

      TraceView 界面比較復(fù)雜,其 UI 劃分為上下兩個(gè)面板,即 Timeline Panel(時(shí)間線面板)和 Profile Panel(分析面板)。上圖中的上半部分為 Timeline Panel(時(shí)間線面板)Timeline Panel 又可細(xì)分為左右兩個(gè) Pane

      • 左邊 Pane 顯示的是測試數(shù)據(jù)中所采集的線程信息。由圖可知,本次測試數(shù)據(jù)采集了 main 線程,傳感器線程和其它系統(tǒng)輔助線程的信息。
      • 右邊 Pane 所示為時(shí)間線,時(shí)間線上是每個(gè)線程測試時(shí)間段內(nèi)所涉及的函數(shù)調(diào)用信息。這些信息包括函數(shù)名、函數(shù)執(zhí)行時(shí)間等。由圖可知,Thread-1412 線程對應(yīng)行的的內(nèi)容非常豐富,而其他線程在這段時(shí)間內(nèi)干得工作則要少得多。
      • 另外,開發(fā)者可以在時(shí)間線 Pane 中移動(dòng)時(shí)間線縱軸。縱軸上邊將顯示當(dāng)前時(shí)間點(diǎn)中某線程正在執(zhí)行的函數(shù)信息。

      上圖中的下半部分為 Profile Panel(分析面板),Profile Panel 是 TraceView 的核心界面,其內(nèi)涵非常豐富。它主要展示了某個(gè)線程(先在 Timeline Panel 中選擇線程)中各個(gè)函數(shù)調(diào)用的情況,包括 CPU 使用時(shí)間、調(diào)用次數(shù)等信息。而這些信息正是查找 hotspot 的關(guān)鍵依據(jù)。所以,對開發(fā)者而言,一定要了解 Profile Panel 中各列的含義。下表列出了 Profile Panel 中比較重要的列名及其描述。

       

       

       

       

       

       

       

       

       

      TraceView 實(shí)戰(zhàn)

      了解完 TraceView 的 UI 后,現(xiàn)在介紹如何利用 TraceView 來查找 hotspot。一般而言,hotspot 包括兩種類型的函數(shù):

      • 一類是調(diào)用次數(shù)不多,但每次調(diào)用卻需要花費(fèi)很長時(shí)間的函數(shù)。
      • 一類是那些自身占用時(shí)間不長,但調(diào)用卻非常頻繁的函數(shù)。

      測試背景:APP 在測試機(jī)運(yùn)行一段時(shí)間后出現(xiàn)手機(jī)發(fā)燙、卡頓、高 CPU 占有率的現(xiàn)象。將應(yīng)用切入后臺進(jìn)行 CPU 數(shù)據(jù)的監(jiān)測,結(jié)果顯示,即使應(yīng)用不進(jìn)行任何操作,應(yīng)用的 CPU 占有率都會(huì)持續(xù)的增長。

      按照 TraceView 簡介中的方法進(jìn)行測試,TraceView 結(jié)果 UI 顯示后進(jìn)行數(shù)據(jù)分析,在 Profile Panel 中,選擇按 Cpu Time/Call 進(jìn)行降序排序(從上之下排列,每項(xiàng)的耗費(fèi)時(shí)間由高到低)得到如圖所示結(jié)果:

      圖中 ImageLoaderTools$2.run() 是應(yīng)用程序中的函數(shù),它耗時(shí)為 1111.124。然后點(diǎn)擊 ImageLoaderTools$2.run() 項(xiàng),得到更為詳盡的調(diào)用關(guān)系圖:

      上圖中 Parents 為 ImageLoaderTools$2.run() 方法的調(diào)用者:Parents (the methods calling this method)Children ImageLoaderTools$2.run() 調(diào)用的子函數(shù)或方法:Children (the methods called by this method)。本例中 ImageLoaderTools$2.run() 方法的調(diào)用者為 Framework 部分,而  ImageLoaderTools$2.run() 方法調(diào)用的自方法中我們卻發(fā)現(xiàn)有三個(gè)方法的 Incl Cpu Time % 占用均達(dá)到了 14% 以上,更離譜的是 Calls+RecurCalls/Total 顯示這三個(gè)方法均被調(diào)用了 35000 次以上,從包名可以識別出這些方法為測試者自身所實(shí)現(xiàn),由此可以判斷 ImageLoaderTools$2.run() 極有可能是手機(jī)發(fā)燙、卡頓、高 CPU 占用率的原因所在。

      代碼驗(yàn)證

      大致可以判斷是 ImageLoaderTools$2.run() 方法出現(xiàn)了問題,下面找到這個(gè)方法進(jìn)行代碼上的驗(yàn)證:

        1 package com.sunzn.app.utils;
        2 
        3 import java.io.File;
        4 import java.io.IOException;
        5 import java.io.InputStream;
        6 import java.lang.ref.SoftReference;
        7 import java.util.ArrayList;
        8 import java.util.HashMap;
        9 
       10 import android.content.Context;
       11 import android.graphics.Bitmap;
       12 import android.os.Environment;
       13 import android.os.Handler;
       14 import android.os.Message;
       15 
       16 public class ImageLoaderTools {
       17 
       18     private HttpTools httptool;
       19 
       20     private Context mContext;
       21 
       22     private boolean isLoop = true;
       23 
       24     private HashMap<String, SoftReference<Bitmap>> mHashMap_caches;
       25 
       26     private ArrayList<ImageLoadTask> maArrayList_taskQueue;
       27 
       28     private Handler mHandler = new Handler() {
       29         public void handleMessage(android.os.Message msg) {
       30             ImageLoadTask loadTask = (ImageLoadTask) msg.obj;
       31             loadTask.callback.imageloaded(loadTask.path, loadTask.bitmap);
       32         };
       33     };
       34 
       35     private Thread mThread = new Thread() {
       36 
       37         public void run() {
       38 
       39             while (isLoop) {
       40 
       41                 while (maArrayList_taskQueue.size() > 0) {
       42 
       43                     try {
       44                         ImageLoadTask task = maArrayList_taskQueue.remove(0);
       45 
       46                         if (Constant.LOADPICTYPE == 1) {
       47                             byte[] bytes = httptool.getByte(task.path, null, HttpTools.METHOD_GET);
       48                             task.bitmap = BitMapTools.getBitmap(bytes, 40, 40);
       49                         } else if (Constant.LOADPICTYPE == 2) {
       50                             InputStream in = httptool.getStream(task.path, null, HttpTools.METHOD_GET);
       51                             task.bitmap = BitMapTools.getBitmap(in, 1);
       52                         }
       53 
       54                         if (task.bitmap != null) {
       55                             mHashMap_caches.put(task.path, new SoftReference<Bitmap>(task.bitmap));
       56                             File dir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
       57                             if (!dir.exists()) {
       58                                 dir.mkdirs();
       59                             }
       60                             String[] path = task.path.split("/");
       61                             String filename = path[path.length - 1];
       62                             File file = new File(dir, filename);
       63                             BitMapTools.saveBitmap(file.getAbsolutePath(), task.bitmap);
       64                             Message msg = Message.obtain();
       65                             msg.obj = task;
       66                             mHandler.sendMessage(msg);
       67                         }
       68                     } catch (IOException e) {
       69                         e.printStackTrace();
       70                     } catch (Exception e) {
       71                         e.printStackTrace();
       72                     }
       73 
       74                     synchronized (this) {
       75                         try {
       76                             wait();
       77                         } catch (InterruptedException e) {
       78                             e.printStackTrace();
       79                         }
       80                     }
       81 
       82                 }
       83 
       84             }
       85 
       86         };
       87 
       88     };
       89 
       90     public ImageLoaderTools(Context context) {
       91         this.mContext = context;
       92         httptool = new HttpTools(context);
       93         mHashMap_caches = new HashMap<String, SoftReference<Bitmap>>();
       94         maArrayList_taskQueue = new ArrayList<ImageLoaderTools.ImageLoadTask>();
       95         mThread.start();
       96     }
       97 
       98     private class ImageLoadTask {
       99         String path;
      100         Bitmap bitmap;
      101         Callback callback;
      102     }
      103 
      104     public interface Callback {
      105         void imageloaded(String path, Bitmap bitmap);
      106     }
      107 
      108     public void quit() {
      109         isLoop = false;
      110     }
      111 
      112     public Bitmap imageLoad(String path, Callback callback) {
      113         Bitmap bitmap = null;
      114         String[] path1 = path.split("/");
      115         String filename = path1[path1.length - 1];
      116 
      117         if (mHashMap_caches.containsKey(path)) {
      118             bitmap = mHashMap_caches.get(path).get();
      119             if (bitmap == null) {
      120                 mHashMap_caches.remove(path);
      121             } else {
      122                 return bitmap;
      123             }
      124         }
      125 
      126         File dir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
      127 
      128         File file = new File(dir, filename);
      129 
      130         bitmap = BitMapTools.getBitMap(file.getAbsolutePath());
      131         if (bitmap != null) {
      132             return bitmap;
      133         }
      134 
      135         ImageLoadTask task = new ImageLoadTask();
      136         task.path = path;
      137         task.callback = callback;
      138         maArrayList_taskQueue.add(task);
      139 
      140         synchronized (mThread) {
      141             mThread.notify();
      142         }
      143 
      144         return null;
      145     }
      146 
      147 }

      以上代碼即是 ImageLoaderTools 圖片工具類的全部代碼,先不著急去研究這個(gè)類的代碼實(shí)現(xiàn)過程,先來看看這個(gè)類是怎么被調(diào)用的:

       1 ImageLoaderTools imageLoaderTools = imageLoaderTools = new ImageLoaderTools(this);
       2 
       3 Bitmap bitmap = imageLoaderTools.imageLoad(picpath, new Callback() {
       4 
       5     @Override
       6     public void imageloaded(String picPath, Bitmap bitmap) {
       7         if (bitmap == null) {
       8             imageView.setImageResource(R.drawable.default);
       9         } else {
      10             imageView.setImageBitmap(bitmap);
      11         }
      12     }
      13 });
      14 
      15 if (bitmap == null) {
      16     imageView.setImageResource(R.drawable.fengmianmoren);
      17 } else {
      18     imageView.setImageBitmap(bitmap);
      19 }

      ImageLoaderTools 被調(diào)用的過程非常簡單:1.ImageLoaderTools 實(shí)例化;2.執(zhí)行 imageLoad() 方法加載圖片。

      在 ImageLoaderTools 類的構(gòu)造函數(shù)(90行-96行)進(jìn)行實(shí)例化過程中完成了網(wǎng)絡(luò)工具 HttpTools 初始化、新建一個(gè)圖片緩存 Map、新建一個(gè)下載隊(duì)列、開啟下載線程的操作。這時(shí)候請注意開啟線程的操作,開啟線程后執(zhí)行 run() 方法35行-88行,這時(shí) isLoop 的值是默認(rèn)的 true,maArrayList_taskQueue.size() 是為 0 的,在任務(wù)隊(duì)列 maArrayList_taskQueue 中還沒有加入下載任務(wù)之前這個(gè)循環(huán)會(huì)一直循環(huán)下去。在執(zhí)行 imageLoad() 方法加載圖片時(shí)會(huì)首先去緩存 mHashMap_caches 中查找該圖片是否已經(jīng)被下載過,如果已經(jīng)下載過則直接返回與之對應(yīng)的 bitmap 資源,如果沒有查找到則會(huì)往 maArrayList_taskQueue 中添加下載任務(wù)并喚醒對應(yīng)的下載線程,之前開啟的線程在發(fā)現(xiàn) maArrayList_taskQueue.size() > 0 后就進(jìn)入下載邏輯,下載完任務(wù)完成后將對應(yīng)的圖片資源加入緩存 mHashMap_caches 并更新 UI,下載線程執(zhí)行 wait() 方法被掛起。一個(gè)圖片下載的業(yè)務(wù)邏輯這樣理解起來很順暢,似乎沒有什么問題。開始我也這樣認(rèn)為,但后來在仔細(xì)的分析代碼的過程中發(fā)現(xiàn)如果同樣一張圖片資源重新被加載就會(huì)出現(xiàn)死循環(huán)。還記得緩存 mHashMap_caches 么?如果一張圖片之前被下載過,那么緩存中就會(huì)有這張圖片的引用存在。重新去加載這張圖片的時(shí)候如果重復(fù)的去初始化 ImageLoaderTools,線程會(huì)被開啟,而使用 imageLoad() 方法加載圖片時(shí)發(fā)現(xiàn)緩存中存在這個(gè)圖片資源,則會(huì)將其直接返回,注意這里使用的是 return bitmap; 那就意味著 imageLoad() 方法里添加下載任務(wù)到下載隊(duì)列的代碼不會(huì)被執(zhí)行到,這時(shí)候 run() 方法中的 isLoop = true 并且 maArrayList_taskQueue.size() = 0,這樣內(nèi)層 while 里的邏輯也就是掛起線程的關(guān)鍵代碼 wait() 永遠(yuǎn)不會(huì)被執(zhí)行到,而外層 while 的判斷條件一直為 true,就這樣程序出現(xiàn)了死循環(huán)。死循環(huán)才是手機(jī)發(fā)燙、卡頓、高 CPU 占用率的真正原因所在。

      解決方案

      準(zhǔn)確的定位到代碼問題所在后,提出解決方案就很簡單了,這里提供的解決方案是將 wait() 方法從內(nèi)層 while 循環(huán)提到外層 while 循環(huán)中,這樣重復(fù)加載同一張圖片時(shí),死循環(huán)一出現(xiàn)線程就被掛起,這樣就可以避免死循環(huán)的出現(xiàn)。代碼如下:

       1 private Thread mThread = new Thread() {
       2 
       3     public void run() {
       4 
       5         while (isLoop) {
       6 
       7             while (maArrayList_taskQueue.size() > 0) {
       8 
       9                 try {
      10                     ImageLoadTask task = maArrayList_taskQueue.remove(0);
      11 
      12                     if (Constant.LOADPICTYPE == 1) {
      13                         byte[] bytes = httptool.getByte(task.path, null, HttpTools.METHOD_GET);
      14                         task.bitmap = BitMapTools.getBitmap(bytes, 40, 40);
      15                     } else if (Constant.LOADPICTYPE == 2) {
      16                         InputStream in = httptool.getStream(task.path, null, HttpTools.METHOD_GET);
      17                         task.bitmap = BitMapTools.getBitmap(in, 1);
      18                     }
      19 
      20                     if (task.bitmap != null) {
      21                         mHashMap_caches.put(task.path, new SoftReference<Bitmap>(task.bitmap));
      22                         File dir = mContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
      23                         if (!dir.exists()) {
      24                             dir.mkdirs();
      25                         }
      26                         String[] path = task.path.split("/");
      27                         String filename = path[path.length - 1];
      28                         File file = new File(dir, filename);
      29                         BitMapTools.saveBitmap(file.getAbsolutePath(), task.bitmap);
      30                         Message msg = Message.obtain();
      31                         msg.obj = task;
      32                         mHandler.sendMessage(msg);
      33                     }
      34                 } catch (IOException e) {
      35                     e.printStackTrace();
      36                 } catch (Exception e) {
      37                     e.printStackTrace();
      38                 }
      39 
      40             }
      41             
      42             synchronized (this) {
      43                 try {
      44                     wait();
      45                 } catch (InterruptedException e) {
      46                     e.printStackTrace();
      47                 }
      48             }
      49 
      50         }
      51 
      52     };
      53 
      54 };

      最后再附上代碼修改后代碼運(yùn)行的性能圖,和之前的多次被重復(fù)執(zhí)行,效率有了質(zhì)的提升,手機(jī)發(fā)燙、卡頓、高 CPU 占用率的現(xiàn)象也消失了。

      posted @ 2013-07-22 22:06  sunzn  閱讀(54269)  評論(6)    收藏  舉報(bào)
      主站蜘蛛池模板: 99在线小视频| 被黑人巨大一区二区三区| 高清偷拍一区二区三区| 日本深夜福利在线观看| 国语精品自产拍在线观看网站| 欧美人妻久久精品| 少妇无套内谢免费视频| 成人国产欧美大片一区| 国产精品 亚洲一区二区三区| 国产suv精品一区二区四| 亚洲色丰满少妇高潮18p| 国产视频一区二区在线看| 免费午夜无码片在线观看影院| 中文字幕日韩一区二区不卡| 国产三级精品片| 九色综合久99久久精品| 俺来也俺去啦最新在线| 精品一区二区中文字幕| 国产玖玖视频| 青青青青久久精品国产| 四虎在线播放亚洲成人| 日韩V欧美V中文在线| 成人动漫综合网| 亚洲视频免费一区二区三区 | 精品综合久久久久久97| 少妇极品熟妇人妻无码| 国产免费午夜福利在线观看| 吉隆县| 少妇av一区二区三区无码| 91精品国产一二三产区| 越南女子杂交内射bbwxz| 国产极品粉嫩尤物一线天| 亚洲一区二区精品另类| 国产v亚洲v天堂a无码99| 好男人日本社区www| 乌克兰丰满女人a级毛片右手影院| 狠狠色狠狠色综合| 熟女视频一区二区三区嫩草| 久热天堂在线视频精品伊人| 亚洲成年av天堂动漫网站| 久热这里只有精品视频六|