最近2018中文字幕在日韩欧美国产成人片_国产日韩精品一区二区在线_在线观看成年美女黄网色视频_国产精品一区三区五区_国产精彩刺激乱对白_看黄色黄大色黄片免费_人人超碰自拍cao_国产高清av在线_亚洲精品电影av_日韩美女尤物视频网站

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Android性能調(diào)優(yōu)利器StrictMode的示例分析

這篇文章主要為大家展示了“Android性能調(diào)優(yōu)利器StrictMode的示例分析”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“Android性能調(diào)優(yōu)利器StrictMode的示例分析”這篇文章吧。

創(chuàng)新互聯(lián)專注于企業(yè)成都全網(wǎng)營銷推廣、網(wǎng)站重做改版、庫倫網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5場景定制商城系統(tǒng)網(wǎng)站開發(fā)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為庫倫等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

什么是StrictMode

StrictMode意思為嚴(yán)格模式,是用來檢測程序中違例情況的開發(fā)者工具。最常用的場景就是檢測主線程中本地磁盤和網(wǎng)絡(luò)讀寫等耗時(shí)的操作。

嚴(yán)在哪里

既然叫做嚴(yán)格模式,那么又嚴(yán)格在哪些地方呢?

在Android中,主線程,也就是UI線程,除了負(fù)責(zé)處理UI相關(guān)的操作外,還可以執(zhí)行文件讀取或者數(shù)據(jù)庫讀寫操作(從Android 4.0 開始,網(wǎng)絡(luò)操作禁止在主線程中執(zhí)行,否則會拋出NetworkOnMainThreadException)。使用嚴(yán)格模式,系統(tǒng)檢測出主線程違例的情況會做出相應(yīng)的反應(yīng),如日志打印,彈出對話框亦或者崩潰等。換言之,嚴(yán)格模式會將應(yīng)用的違例細(xì)節(jié)暴露給開發(fā)者方便優(yōu)化與改善。

具體能檢測什么

嚴(yán)格模式主要檢測兩大問題,一個(gè)是線程策略,即TreadPolicy,另一個(gè)是VM策略,即VmPolicy。

ThreadPolicy

線程策略檢測的內(nèi)容有

  • 自定義的耗時(shí)調(diào)用 使用detectCustomSlowCalls()開啟

  • 磁盤讀取操作 使用detectDiskReads()開啟

  • 磁盤寫入操作 使用detectDiskWrites()開啟

  • 網(wǎng)絡(luò)操作 使用detectNetwork()開啟

VmPolicy

虛擬機(jī)策略檢測的內(nèi)容有

Activity泄露 使用detectActivityLeaks()開啟
未關(guān)閉的Closable對象泄露 使用detectLeakedClosableObjects()開啟
泄露的Sqlite對象 使用detectLeakedSqlLiteObjects()開啟
檢測實(shí)例數(shù)量 使用setClassInstanceLimit()開啟

工作原理

其實(shí)StrictMode實(shí)現(xiàn)原理也比較簡單,以IO操作為例,主要是通過在open,read,write,close時(shí)進(jìn)行監(jiān)控。libcore.io.BlockGuardOs文件就是監(jiān)控的地方。以open為例,如下進(jìn)行監(jiān)控。

@Override
public FileDescriptor open(String path, int flags, int mode) throws ErrnoException {
 BlockGuard.getThreadPolicy().onReadFromDisk();
 if ((mode & O_ACCMODE) != O_RDONLY) {
 BlockGuard.getThreadPolicy().onWriteToDisk();
 }
 return os.open(path, flags, mode);
}

其中onReadFromDisk()方法的實(shí)現(xiàn),代碼位于StrictMode.java中。

public void onReadFromDisk() {
 if ((mPolicyMask & DETECT_DISK_READ) == 0) {
 return;
 }
 if (tooManyViolationsThisLoop()) {
 return;
 }
 BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
 e.fillInStackTrace();
 startHandlingViolationException(e);
}

如何使用

關(guān)于StrictMode如何使用,最重要的就是如何啟用嚴(yán)格模式。

放在哪里

嚴(yán)格模式的開啟可以放在Application或者Activity以及其他組件的onCreate方法。為了更好地分析應(yīng)用中的問題,建議放在Application的onCreate方法中。

簡單啟用

以下的代碼啟用全部的ThreadPolicy和VmPolicy違例檢測

if (IS_DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
 StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
 StrictMode.setVmPolicy(new VmPolicy.Builder().detectAll().penaltyLog().build());
}

嚴(yán)格模式需要在debug模式開啟,不要在release版本中啟用。

同時(shí),嚴(yán)格模式自API 9 開始引入,某些API方法也從 API 11 引入。使用時(shí)應(yīng)該注意 API 級別。

如有需要,也可以開啟部分的嚴(yán)格模式。

查看結(jié)果

嚴(yán)格模式有很多種報(bào)告違例的形式,但是想要分析具體違例情況,還是需要查看日志,終端下過濾StrictMode就能得到違例的具體stacktrace信息。

adb logcat | grep StrictMode

解決違例

  • 如果是主線程中出現(xiàn)文件讀寫違例,建議使用工作線程(必要時(shí)結(jié)合Handler)完成。

  • 如果是對SharedPreferences寫入操作,在API 9 以上 建議優(yōu)先調(diào)用apply而非commit。

  • 如果是存在未關(guān)閉的Closable對象,根據(jù)對應(yīng)的stacktrace進(jìn)行關(guān)閉。

  • 如果是SQLite對象泄露,根據(jù)對應(yīng)的stacktrace進(jìn)行釋放。

舉個(gè)例子

以主線程中的文件寫入為例,引起違例警告的代碼

public void writeToExternalStorage() {
 File externalStorage = Environment.getExternalStorageDirectory();
 File destFile = new File(externalStorage, "dest.txt");
 try {
 OutputStream output = new FileOutputStream(destFile, true);
 output.write("droidyue.com".getBytes());
 output.flush();
 output.close();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }
}

引起的警告為

D/StrictMode( 9730): StrictMode policy violation; ~duration=20 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=31 violation=2
D/StrictMode( 9730): at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1176)
D/StrictMode( 9730): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:106)
D/StrictMode( 9730): at libcore.io.IoBridge.open(IoBridge.java:390)
D/StrictMode( 9730): at java.io.FileOutputStream.(FileOutputStream.java:88)
D/StrictMode( 9730): at com.example.strictmodedemo.MainActivity.writeToExternalStorage(MainActivity.java:56)
D/StrictMode( 9730): at com.example.strictmodedemo.MainActivity.onCreate(MainActivity.java:30)
D/StrictMode( 9730): at android.app.Activity.performCreate(Activity.java:4543)

因?yàn)樯鲜鰧儆谥骶€程中的IO違例,解決方法就是講寫入操作放入工作線程。

public void writeToExternalStorage() {
 new Thread() {
 @Override
 public void run() {
 super.run();
 File externalStorage = Environment.getExternalStorageDirectory();
 File destFile = new File(externalStorage, "dest.txt");
 try {
 OutputStream output = new FileOutputStream(destFile, true);
 output.write("droidyue.com".getBytes());
 output.flush();
 output.close();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }.start();
}

然而這并非完善,因?yàn)镺utputStream.write方法可能拋出IOException,導(dǎo)致存在OutputStream對象未關(guān)閉的情況,仍然需要改進(jìn)避免出現(xiàn)Closable對象未關(guān)閉的違例。改進(jìn)如下

public void writeToExternalStorage() {
 new Thread() {
 @Override
 public void run() {
 super.run();
 File externalStorage = Environment.getExternalStorageDirectory();
 File destFile = new File(externalStorage, "dest.txt");
 OutputStream output = null;
 try {
 output = new FileOutputStream(destFile, true);
 output.write("droidyue.com".getBytes());
 output.flush();
 output.close();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 if (null != output) {
  try {
  output.close();
  } catch (IOException e) {
  e.printStackTrace();
  }
 }
 }
 }
 }.start();
}

檢測內(nèi)存泄露

通常情況下,檢測內(nèi)存泄露,我們需要使用MAT對heap dump 文件進(jìn)行分析,這種操作不困難,但也不容易。使用嚴(yán)格模式,只需要過濾日志就能發(fā)現(xiàn)內(nèi)存泄露。

這里以Activity為例說明,首先我們需要開啟對檢測Activity泄露的違例檢測。使用上面的detectAll或者detectActivityLeaks()均可。其次寫一段能夠產(chǎn)生Activity泄露的代碼。

public class LeakyActivity extends Activity{
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 MyApplication.sLeakyActivities.add(this);
 }
}

MyApplication中關(guān)于sLeakyActivities的部分實(shí)現(xiàn)

public class MyApplication extends Application {
 public static final boolean IS_DEBUG = true;
 public static ArrayList sLeakyActivities = new ArrayList();
}

當(dāng)我們反復(fù)進(jìn)入LeakyActivity再退出,過濾StrictMode就會得到這樣的日志

E/StrictMode( 2622): class com.example.strictmodedemo.LeakyActivity; instances=2; limit=1
E/StrictMode( 2622): android.os.StrictMode$InstanceCountViolation: class com.example.strictmodedemo.LeakyActivity; instances=2; limit=1
E/StrictMode( 2622): at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)

分析日志,LeakyActivity本應(yīng)該是只存在一份實(shí)例,但現(xiàn)在出現(xiàn)了2個(gè),說明LeakyActivity發(fā)生了內(nèi)存泄露。

嚴(yán)格模式除了可以檢測Activity的內(nèi)存泄露之外,還能自定義檢測類的實(shí)例泄露。從API 11 開始,系統(tǒng)提供的這個(gè)方法可以實(shí)現(xiàn)我們的需求。

public StrictMode.VmPolicy.Builder setClassInstanceLimit (Class klass, int instanceLimit)

舉個(gè)栗子,比如一個(gè)瀏覽器中只允許存在一個(gè)SearchBox實(shí)例,我們就可以這樣設(shè)置已檢測SearchBox實(shí)例的泄露

StrictMode.setVmPolicy(new VmPolicy.Builder().setClassInstanceLimit(SearchBox.class, 1).penaltyLog().build());

noteSlowCall

StrictMode從 API 11開始允許開發(fā)者自定義一些耗時(shí)調(diào)用違例,這種自定義適用于自定義的任務(wù)執(zhí)行類中,比如我們有一個(gè)進(jìn)行任務(wù)處理的類,為TaskExecutor。

public class TaskExecutor {
 public void execute(Runnable task) {
 task.run();
 }
}

先需要跟蹤每個(gè)任務(wù)的耗時(shí)情況,如果大于500毫秒需要提示給開發(fā)者,noteSlowCall就可以實(shí)現(xiàn)這個(gè)功能,如下修改代碼

public class TaskExecutor {
 private static long SLOW_CALL_THRESHOLD = 500;
 public void executeTask(Runnable task) {
 long startTime = SystemClock.uptimeMillis();
 task.run();
 long cost = SystemClock.uptimeMillis() - startTime;
 if (cost > SLOW_CALL_THRESHOLD) {
 StrictMode.noteSlowCall("slowCall cost=" + cost);
 }
 }
}

執(zhí)行一個(gè)耗時(shí)2000毫秒的任務(wù)

TaskExecutor executor = new TaskExecutor();
executor.executeTask(new Runnable() {
 @Override
 public void run() {
 try {
 Thread.sleep(2000);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
});

得到的違例日志,注意其中~duration=20 ms并非耗時(shí)任務(wù)的執(zhí)行時(shí)間,而我們的自定義信息msg=slowCall cost=2000才包含了真正的耗時(shí)。

D/StrictMode(23890): StrictMode policy violation; ~duration=20 ms: android.os.StrictMode$StrictModeCustomViolation: policy=31 violation=8 msg=slowCall cost=2000
D/StrictMode(23890): at android.os.StrictMode$AndroidBlockGuardPolicy.onCustomSlowCall(StrictMode.java:1163)
D/StrictMode(23890): at android.os.StrictMode.noteSlowCall(StrictMode.java:1974)
D/StrictMode(23890): at com.example.strictmodedemo.TaskExecutor.executeTask(TaskExecutor.java:17)
D/StrictMode(23890): at com.example.strictmodedemo.MainActivity.onCreate(MainActivity.java:36)
D/StrictMode(23890): at android.app.Activity.performCreate(Activity.java:4543)
D/StrictMode(23890): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1071)
D/StrictMode(23890): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2158)
D/StrictMode(23890): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2237)
D/StrictMode(23890): at android.app.ActivityThread.access$600(ActivityThread.java:139)
D/StrictMode(23890): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1262)
D/StrictMode(23890): at android.os.Handler.dispatchMessage(Handler.java:99)
D/StrictMode(23890): at android.os.Looper.loop(Looper.java:156)
D/StrictMode(23890): at android.app.ActivityThread.main(ActivityThread.java:5005)
D/StrictMode(23890): at java.lang.reflect.Method.invokeNative(Native Method)
D/StrictMode(23890): at java.lang.reflect.Method.invoke(Method.java:511)
D/StrictMode(23890): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
D/StrictMode(23890): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
D/StrictMode(23890): at dalvik.system.NativeStart.main(Native Method)

其他技巧

除了通過日志查看之外,我們也可以在開發(fā)者選項(xiàng)中開啟嚴(yán)格模式,開啟之后,如果主線程中有執(zhí)行時(shí)間長的操作,屏幕則會閃爍,這是一個(gè)更加直接的方法。

Android性能調(diào)優(yōu)利器StrictMode的示例分析

問題來了

日志的時(shí)間靠譜么

在下面的過濾日志中,我們看到下面的一個(gè)IO操作要消耗31毫秒,這是真的么

D/StrictMode( 2921): StrictMode policy violation; ~duration=31 ms: android.os.StrictMode$StrictModeDiskReadViolation: policy=31 violation=2
D/StrictMode( 2921): at android.os.StrictMode$AndroidBlockGuardPolicy.onReadFromDisk(StrictMode.java:1176)
D/StrictMode( 2921): at libcore.io.BlockGuardOs.read(BlockGuardOs.java:148)
D/StrictMode( 2921): at libcore.io.IoBridge.read(IoBridge.java:422)
D/StrictMode( 2921): at java.io.FileInputStream.read(FileInputStream.java:179)
D/StrictMode( 2921): at java.io.InputStreamReader.read(InputStreamReader.java:244)
D/StrictMode( 2921): at java.io.BufferedReader.fillBuf(BufferedReader.java:130)
D/StrictMode( 2921): at java.io.BufferedReader.readLine(BufferedReader.java:354)
D/StrictMode( 2921): at com.example.strictmodedemo.MainActivity.testReadContentOfFile(MainActivity.java:65)
D/StrictMode( 2921): at com.example.strictmodedemo.MainActivity.onCreate(MainActivity.java:28)
D/StrictMode( 2921): at android.app.Activity.performCreate(Activity.java:4543)

從上面的stacktrace可以看出testReadContentOfFile方法中包含了文件讀取IO操作,至于是否為31毫秒,我們可以利用秒表的原理計(jì)算一下,即在方法調(diào)用的地方如下記錄

long startTime = System.currentTimeMillis();
testReadContentOfFile();
long cost = System.currentTimeMillis() - startTime;
Log.d(LOGTAG, "cost = " + cost);

得到的日志中上述操作耗時(shí)9毫秒,非31毫秒。

D/MainActivity(20996): cost = 9

注:通常情況下StrictMode給出的耗時(shí)相對實(shí)際情況偏高,并不是真正的耗時(shí)數(shù)據(jù)。

注意

  • 在線上環(huán)境即Release版本不建議開啟嚴(yán)格模式。

  • 嚴(yán)格模式無法監(jiān)控JNI中的磁盤IO和網(wǎng)絡(luò)請求。

  • 應(yīng)用中并非需要解決全部的違例情況,比如有些IO操作必須在主線程中進(jìn)行。

以上是“Android性能調(diào)優(yōu)利器StrictMode的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


網(wǎng)頁標(biāo)題:Android性能調(diào)優(yōu)利器StrictMode的示例分析
文章源于:http://fisionsoft.com.cn/article/ipsjph.html