您好,登錄后才能下訂單哦!
什么是 StrictMode(嚴苛模式)
strictmode是android在 API9后引入的檢測影響app運行流暢性的一種機制,例如我們都知道的主線程中不允許有網絡操作這條規則就是嚴苛模式規則的一種.
strictmode.java 這個類中設定了許多detect標志位例如 DETECT_NETWORK ,還有許多 penalty標志位例如 PENALTY_NETWORK , DETECT標志位決定strictmode是否要對這項內容進行檢測,PENALTY標志位決定了在這項內容發生時是否要拋出異常(相當于一種懲罰機制,PENALTY的意思就是懲罰).
StrictMode 類的作用之一就是對這些標志位進行管理,通過 setThreadPolicy() 方法可以設定 Policy 變量中的mask值.
之后會將 POLICY 變量傳入 BlockGuard 中,BlockGuard 運行在 Dalvik虛擬機中,對所有的異常操作進行統一的管理.
Android官方文檔中對于strict mode 給出的解釋
strictmode 是一種開發工具,引入它可以使你發現在開發過程中產生的問題,并修復它們.
在 application main thread中常有UI相關的操作和動畫發生,strictmode可以在主線程中檢測硬盤和網絡相關的操作.將硬盤讀寫操作和網絡相關操作挪出主線程可以使你的app更加流暢和具有響應性.同時為了使app更加響應性,你可以屏蔽ANR發生時彈出的dialog.
需要注意的是,盡管android設備的硬盤類型大多為 flash memory,建立在這種存儲介質上的文件系統的并發性仍然是非常有限的(速度上肯定是RAM比較快).
大部分情況下,硬盤的讀寫操作都是非常快的,但在某些情況下,后臺進程中會運行耗費很大的I/O操作,在這種情況下,app的響應速度會下降很多.
一.setThreadPolicy()流程
StrictMode類的文檔中給出的strictmode啟動方式
* public void onCreate() { * if (DEVELOPER_MODE) { * StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}() * .detectDiskReads() * .detectDiskWrites() * .detectNetwork() // or .detectAll() for all detectable problems * .penaltyLog() * .build()); * StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}() * .detectLeakedSqlLiteObjects() * .detectLeakedClosableObjects() * .penaltyLog() * .penaltyDeath() * .build()); * } * super.onCreate();
1.
在執行了 setThreadPolicy()函數后會調用 setThreadPolicyMask()方法.
public static void setThreadPolicy(final ThreadPolicy policy) { setThreadPolicyMask(policy.mask); }
2.
在 setThreadPolicyMask()方法中,除了在java層的threadLocal中設置外,還需要在Native層也進行一個設置.
private static void setThreadPolicyMask(final int policyMask) { // In addition to the Java-level thread-local in Dalvik's // BlockGuard, we also need to keep a native thread-local in // Binder in order to propagate the value across Binder calls, // even across native-only processes. The two are kept in // sync via the callback to onStrictModePolicyChange, below. setBlockGuardPolicy(policyMask); // And set the Android native version... Binder.setThreadStrictModePolicy(policyMask); }
3.
首先分析java層的 setBlockGuardPolicy()方法.
如果policyMask==0,會返回一個默認policy,默認policy不進行任何設置和檢測,policy對象存儲在threadLocal變量中(每個線程保存一個policy的對象),首次運行該方法會生成一個默認policy(mMask=0)保存在threadLocal中,這里的policy對象是AndroidBlockGuardPolicy類型.
// Sets the policy in Dalvik/libcore (BlockGuard) private static void setBlockGuardPolicy(final int policyMask) { if (policyMask == 0) { BlockGuard.setThreadPolicy(BlockGuard.LAX_POLICY); return; } final BlockGuard.Policy policy = BlockGuard.getThreadPolicy(); final AndroidBlockGuardPolicy androidPolicy; if (policy instanceof AndroidBlockGuardPolicy) { androidPolicy = (AndroidBlockGuardPolicy) policy; } else { androidPolicy = threadAndroidPolicy.get(); BlockGuard.setThreadPolicy(androidPolicy); } androidPolicy.setPolicyMask(policyMask); }
4.
再看Native層的代碼:
設置了policy
386void IPCThreadState::setStrictModePolicy(int32_t policy) 387{ 388 mStrictModePolicy = policy; 389}
二.StrictMode如何檢測問題.
1.
CloseGuard檢測游標是否正常關閉:
當使用ContentResolver來查詢數據庫的時候,會返回一個CursorWrapperInner類型的Cursor對象.
mCursor = mResolver.query(mUri, null, null, null, null);
CloseGuard對CursorWrapperInner是否正常關閉的檢測的邏輯在finalize()函數中,finalize()會在gc執行垃圾回收的時候被調用(垃圾回收使用了GcRoot算法)
如果沒有執行CursorWrapperInner的close()函數,僅將CursorWrapperInner對象置為null,當主動觸發gc的時候( Systemgc()),finalize()函數被調用 ,"Cursor finalized without prior close()"這段log被打印.但如果沒有將CursorWrapperInner對象置為null,這時主動觸發gc并不會引起 finalize()函數的執行,因為CursorWrapperInner對象被強引用,垃圾回收器在回收時不會考慮回收強引用對象,即使最后內存不足而崩潰.
經過測試程序的測試,發現"Cursor finalized without prior close()"這段log在 CursorWrapperInner對象置空并執行 System.gc()后是會打印出來的.
但是 CloseGuard中的 warnIfOpen()函數始終沒有執行
在 CursorWrapperInner的構造函數中,mCloseGuard執行 open()函數,在 open函數中allocationSite被賦值,而 ENABLED 變量是默認為true的,唯一改變它的setEnabled()方法在源碼中也并沒有被調用,所以應該是會在REPORTER中打印SystemLog的,但最后SystemLog并沒有打印,具體原因分析不出來.
@Override protected void finalize() throws Throwable { try { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); } if (!mProviderReleased && mContentProvider != null) { // Even though we are using CloseGuard, log this anyway so that // application developers always see the message in the log. Log.w(TAG, "Cursor finalized without prior close()"); ContentResolver.this.releaseProvider(mContentProvider); } } finally { super.finalize(); } } } public void warnIfOpen() { if (allocationSite == null || !ENABLED) { return; } String message = ("A resource was acquired at attached stack trace but never released. " + "See java.io.Closeable for information on avoiding resource leaks."); REPORTER.report(message, allocationSite); } @Override public void report (String message, Throwable allocationSite) { System.logW(message, allocationSite); } CursorWrapperInner(Cursor cursor, IContentProvider icp) { super(cursor); mContentProvider = icp; mCloseGuard.open("close"); }
2.
onSqliteObjectsLeaked()也是用來檢測數據庫游標有沒有正常關閉,但這個函數檢測的是通過SqliteDataBase. query()得到的SqliteCursor游標對象.
檢測位置也是在 finalize()函數中.
/** * Release the native resources, if they haven't been released yet. */ @Override protected void finalize() { try { // if the cursor hasn't been closed yet, close it first if (mWindow != null) { if (mStackTrace != null) { String sql = mQuery.getSql(); int len = sql.length(); StrictMode.onSqliteObjectLeaked( "Finalizing a Cursor that has not been deactivated or closed. " + "database = " + mQuery.getDatabase().getLabel() + ", table = " + mEditTable + ", query = " + sql.substring(0, (len > 1000) ? 1000 : len), mStackTrace); } close(); } } finally { super.finalize(); } }
流程如下圖
三.StrictMode中使用到的橋接模式
橋接模式:所謂橋接模式就是將邏輯的抽象與實現分開的一種模式
總結
以上所述是小編給大家介紹的Android StrictMode運行流程,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。