word怎么做網(wǎng)站鏈接seo交流中心
文章目錄
- Android 性能優(yōu)化之卡頓優(yōu)化
- 卡頓檢測
- TraceView
- 配置
- 缺點(diǎn)
- StricktMode
- 配置
- 違規(guī)代碼
- BlockCanary
- 配置
- 問題代碼
- 缺點(diǎn)
- ANR
- ANR原因
- ANRWatchDog監(jiān)測
- 解決方案
Android 性能優(yōu)化之卡頓優(yōu)化
卡頓檢測
- TraceView
- StricktModel
- BlockCanary
TraceView
配置
Debug.startMethodTracing("myTrace");
Debug.stopMethodTracing();
生成的 trace 文件保存在:/storage/self/primary/Android/data/<包名>/files/myTrace.trace
缺點(diǎn)
- 運(yùn)行時開銷大,整體變慢。
- 容易帶偏優(yōu)化方向。
StricktMode
StricktMode 嚴(yán)苛模式,是 Android 提供的一種運(yùn)行時檢測機(jī)制。
策略:
- 線程策略:
- 自定義耗時調(diào)用:detectCustomSlowCalls
- 磁盤讀取操作:detectDiskReads
- 網(wǎng)絡(luò)操作:detectNetwork
- 虛擬機(jī)策略:
- Activity泄露:detectActivityLeaks()
- Sqlite對象泄露:detectLeakedSqlLiteObjects
- 檢測實(shí)例數(shù)量:setClassInstanceLimit()
在 LogCat 中過濾 “StrictMode” 即可查看日志信息。
配置
public class BaseApp extends Application {@Overridepublic void onCreate() {super.onCreate();initStrictMode();}private void initStrictMode() {if (BuildConfig.DEBUG) {StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectCustomSlowCalls() //API等級11,使用StrictMode.noteSlowCode.detectDiskReads().detectDiskWrites().detectNetwork()// or .detectAll() for all detectable problems.penaltyLog() //在Logcat 中打印違規(guī)異常信息.build());StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectActivityLeaks().detectLeakedSqlLiteObjects()
// .setClassInstanceLimit(Person.class, 1).detectLeakedClosableObjects() //API等級11.penaltyLog().build());}}
}
違規(guī)代碼
主線操作IO問題:
File externalStorage = getFilesDir();
File destFile = new File(externalStorage, "hello.txt");
try {OutputStream output = new FileOutputStream(destFile, true);output.write("I am testing io".getBytes());output.flush();output.close();
} catch (IOException e) {e.printStackTrace();
}
日志:
可以看到違規(guī)的原因和位置。
Activity內(nèi)存泄露問題:
BaseApp.addActivity(this);
日志:
2024-07-15 17:50:48.075 19900-19900/com.example.anr D/StrictMode: StrictMode policy violation: android.os.strictmode.InstanceCountViolation: class com.example.anr.StuckActivity; instances=12; limit=2at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)
多次進(jìn)出后輸出日志,存在12個實(shí)例。
BlockCanary
BlockCanary 是一個用于 Android 應(yīng)用開發(fā)者的性能分析工具,它可以幫助開發(fā)者發(fā)現(xiàn)和解決應(yīng)用中的卡頓問題。BlockCanary 通過在應(yīng)用中植入檢測邏輯,監(jiān)控應(yīng)用運(yùn)行時的線程狀態(tài),并在檢測到卡頓發(fā)生時記錄相關(guān)信息。它的主要目的是幫助開發(fā)者追蹤和分析應(yīng)用中可能導(dǎo)致卡頓的代碼段或操作。
配置
添加依賴庫:
implementation 'com.github.markzhai:blockcanary-android:1.5.0'
配置:
public class BaseApplication extends Application {@Overridepublic void onCreate() {BlockCanary.install(this, new AppBlockCanaryContext()).start();}
}
問題代碼
依次執(zhí)行問題代碼:
private void testSleep() {Log.e("TAG", "sleep前");try {Thread.sleep(2000L);} catch (InterruptedException e) {throw new RuntimeException(e);}Log.e("TAG", "sleep后");
}
private void testMath() {Log.e("TAG", "math前");long start = System.currentTimeMillis();double result = 0;for (int i = 0; i < 10000000; i++) {result += Math.acos(Math.cos(i));result -= Math.asin(Math.sin(i));result += Math.acos(Math.cos(i));result -= Math.asin(Math.sin(i));}Log.e("TAG", "math" + result);Log.e("TAG", "耗時 " + (System.currentTimeMillis() - start));
}
BlockCanary 依次生成2個信息:
點(diǎn)擊第一個進(jìn)去可以看到,阻塞時間和阻塞代碼:
點(diǎn)擊第二個進(jìn)去同樣也能看到相關(guān)信息:
缺點(diǎn)
- BlockCanary 需要在應(yīng)用中植入檢測邏輯,這會帶來一定的性能開銷。
- 卡頓堆??赡懿粶?zhǔn)確。
ANR
ANR(Application Not Responding)是指應(yīng)用程序未響應(yīng),Android 系統(tǒng)對于一些事件需要在一定時間范圍內(nèi)完成,如果超過預(yù)定時間未能得到有效響應(yīng)或者響應(yīng)時間過長,都會造成 ANR。
ANR原因
- 數(shù)據(jù)導(dǎo)致的 ANR:頻繁 GC 導(dǎo)致線程暫停,處理事件時間被拉長。
- 線程阻塞或死鎖導(dǎo)致的 ANR。
- Binder 導(dǎo)致的 ANR:Binder 通信數(shù)據(jù)量過大。
ANRWatchDog監(jiān)測
ANRWatchDog是一個用于監(jiān)測Android應(yīng)用程序中的ANR(應(yīng)用程序無響應(yīng))的開源庫。
添加依賴庫:
implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
配置:
public class BaseApp extends Application {@Overridepublic void onCreate() {super.onCreate(); new ANRWatchDog().start(); // 默認(rèn)5000毫秒}
}
問題代碼一:
public void onClick1(View view) {try {Thread.sleep(20000L);} catch (InterruptedException e) {throw new RuntimeException(e);}
}
ANRWatchDog警告:
問題代碼二:
public void onClick2(View view) {SharedPreferences sp = getSharedPreferences("app", Context.MODE_PRIVATE);for (int i = 0; i < 100000; i++) {SharedPreferences.Editor edit = sp.edit();for (int j = 0; j < 100000; j++) {edit.putString("name", "aaaaa").putInt("age", 18).putBoolean("sex", true).commit();}}
}
ANRWatchDog警告:
解決方案
- 將所有耗時操作如訪問網(wǎng)絡(luò)、socket 通信、查詢大量 SQL 語句、復(fù)雜邏輯計算等都放在子線程中,然后通過 handler.sendMessage、runOnUIThread 等方式更新 UI。無論如何都要確保用戶界面的流暢度,如果耗時操作需要讓用戶等待,可以在界面上顯示進(jìn)度條
- 將 IO 操作放在異步線程。在一些同步的操作主線程有可能被鎖,需要等待其他線程釋放響應(yīng)鎖才能繼續(xù)執(zhí)行,這樣會有一定的 ANR 風(fēng)險,對于這種情況有時也可以用異步線程來執(zhí)行相應(yīng)的邏輯,另外,要避免死鎖的發(fā)生
- 使用 Thread 或 HandlerThread 時,調(diào)用 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)設(shè)置優(yōu)先級,否則仍然會降低程序響應(yīng),因?yàn)槟J(rèn) Thread 優(yōu)先級和主線程相同
- 使用 Handler 處理工作線程結(jié)果,而不是使用 Thread.wait() 或 Thread.sleep() 來阻塞主線程
- Activity 的 onCreate() 和 onResume() 回調(diào)中避免耗時代碼
- BroadcastReceiver 中 onReceive() 代碼也要盡量減少耗時,建議使用 IntentService 處理
- 各個組件的生命周期函數(shù)都不應(yīng)該有太耗時的操作,即使對于后臺 Service 或 ContentProvider 來講,雖然應(yīng)用在后臺運(yùn)行時生命周期函數(shù)不會有用戶輸入引起無響應(yīng)的 ANR,但其執(zhí)行時間過長也會引起 Service 或 ContentProvider 的 ANR