An overview of the
StrictMode is an essential performance check tool for Android development. StrictMode can help detect code blocks that do not make sense.
Classification of strategy
StrictMode is divided into ThreadPolicy and VmPolicy.
ThreadPolicy
Threading strategy mainly includes the following aspects
- DetectNetwork: Detection of mainline network usage (critical)
- DetectCustomSlowCalls: Detect custom slower-running functions
- PenaltyLog: outputs logs
- PenaltyDialog: Pop-up dialog box to monitor the situation
- DetectDiskReads: detectDiskReads on THE UI thread (critical)
- DetectDiskWrites: detectDiskWrites in the UI thread (critical)
- DetectResourceMismatches: Detecting resource mismatches (API >22)
- DetectAll: All supported items such as detectAll (if you are too lazy to list them all, you can do this)
- PermitDiskReads: allows the UI thread to read operations on disk
VmPolicy (VmPolicy)
Vm policies include the following aspects
- Detectacvityleaks: Detecting Activity memory leaks (important) (API >10)
- DetectCleartextNetwork: plaintext network (API >22)
- DetectFileUriExposure: detection of file:// or content:// (API >17)
- DetectLeakedClosableObjects: testing resources not properly closed (important) (API > 10)
- DetectLeakedRegistrationObjects: BroadcastReceiver and ServiceConnection whether be released (important) (API > 15)
- DetectLeakedSqlLiteObjects: database resource is not closed properly. (important) (API > 8)
- SetClassInstanceLimit: Set the maximum number of instances of a class that are in memory at the same time to help check for memory leaks (important)
- PenaltyLog: outputs logs
- PenaltyDeath: App crashes once detected
code
Private void enabledStrictMode () {/ / open Thread strategy mode StrictMode. SetThreadPolicy (new StrictMode. ThreadPolicy. Builder (.) detectNetwork () / / monitoring the main thread to use network IO detectCustomSlowCalls () / / monitoring custom slow function. DetectDiskReads () DetectDiskWrites (); penaltyLog(); penaltyDialog(); build(); / / open the VM strategy pattern StrictMode. SetVmPolicy (new StrictMode. VmPolicy. Builder () detectLeakedSqlLiteObjects sqlite leak () / / monitoring DetectLeakedClosableObjects () / / monitoring not closing IO object. SetClassInstanceLimit (MainActivity class, 1) / / set a class instance in memory at the same time limit, Detectacvityleaks (). PenaltyLog ()// Write to the log. PenaltyDeath ()// the case is terminated. Build ()); }Copy the code
Case 1
public class MainActivity extends Activity { private Handler mHandler = new Handler(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (BuildConfig.DEBUG) { enabledStrictMode(); } mhandler.postdelayed (new Runnable() {@override public void run() {log.d ("MainActivity", "I'm coming "); }}, 10 * 1000); TextView tv = new TextView(this); Tv.settext (" Nice "); } private void enabledStrictMode () {/ / open Thread strategy mode StrictMode. SetThreadPolicy (new StrictMode. ThreadPolicy. Builder (.) detectNetwork () / / monitoring the main thread to use network IO detectCustomSlowCalls () / / monitoring custom slow function. DetectDiskReads () DetectDiskWrites (); penaltyLog(); penaltyDialog(); build(); / / open the VM strategy pattern StrictMode. SetVmPolicy (new StrictMode. VmPolicy. Builder () detectLeakedSqlLiteObjects sqlite leak () / / monitoring DetectLeakedClosableObjects () / / monitoring not closing IO object. SetClassInstanceLimit (MainActivity class, 1) / / set a class instance in memory at the same time limit, Detectacvityleaks (). PenaltyLog ()// Write to the log. PenaltyDeath ()// the case is terminated. Build ()); }}Copy the code
As shown in the code, I create a Handler (non-static) in the MainActivity (singleTask and app startup Activity) and execute a task delayed by 10 seconds. Now I keep starting and exiting MainActivity, and I find something like this
As you can see, MainActivity creates multiple instances (this diagram uses MAT’s OQL, as explained in more detail in a later section), and we expect only one instance of MainActivity. List one of the object instance reference paths, as shown in the figure below.
As you can see from the above figure, it is the Handler that holds the MainActivity instance, causing the MainActivity to fail to be released.
transform
public class MainActivity extends Activity { private static class InnerHandler extends Handler { private final WeakReference<MainActivity> mWeakreference; InnerHandler(MainActivity activity) { mWeakreference = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); final MainActivity activity = mWeakreference.get(); if (activity == null) { return; } log.d ("MainActivity"," MSG "); } } private Handler mHandler = new InnerHandler(this); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (BuildConfig.DEBUG) { enabledStrictMode(); } mhandler.postdelayed (new Runnable() {@override public void run() {log.d ("MainActivity", "I'm coming "); }}, 10 * 1000); TextView tv = new TextView(this); Tv.settext (" I'm coming "); setContentView(tv); } @Override protected void onDestroy() { mHandler.removeCallbacksAndMessages(null); super.onDestroy(); } private void enabledStrictMode () {/ / open Thread strategy mode StrictMode. SetThreadPolicy (new StrictMode. ThreadPolicy. Builder (.) detectNetwork () / / monitoring the main thread to use network IO detectCustomSlowCalls () / / monitoring custom slow function. DetectDiskReads () DetectDiskWrites (); penaltyLog(); penaltyDialog(); build(); / / open the VM strategy pattern StrictMode. SetVmPolicy (new StrictMode. VmPolicy. Builder () detectLeakedSqlLiteObjects sqlite leak () / / monitoring DetectLeakedClosableObjects () / / monitoring not closing IO object. SetClassInstanceLimit (MainActivity class, 1) / / set a class instance in memory at the same time limit, Detectacvityleaks ().penaltylog ()// Write log.build ()); }}Copy the code
Will for a static inner class Handler implementation, and to hold the current Activity, by means of a weak reference at onDestory call removeCallbacksAndMessages (null) method, the complete null, said it would all messages in the Handler to empty out. After running the code, see the following figure through MAT analysis
As can be seen from the figure, there is currently only one MainActivity, as expected by the code design.
note
During our analysis of this case, android instances=2; StrictMode message with limit=1 because the system is collecting the MainActivity instance during the process of starting and exiting the MainActivity. This object is being referenced by FinalizerReference. We are starting another MainActivity, so we report two instances.
Case 2
public class MainActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (BuildConfig.DEBUG) { enabledStrictMode(); } TextView tv = new TextView(this); Tv.settext (" I'm coming "); setContentView(tv); newThread(); takeTime(); } private void newThread() { for (int i = 0; i < 50; i++) { new Thread(new Runnable() { @Override public void run() { takeTime(); } }).start(); } } private void takeTime() { try { File file = new File(getCacheDir(), "test"); if (file.exists()) { file.delete(); } file.createNewFile(); FileOutputStream fileOutputStream = new FileOutputStream(file); Final String content = "Hello, I'm coming "; StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 100; i++) { buffer.append(content); } fileOutputStream.write(buffer.toString().getBytes()); fileOutputStream.flush(); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onDestroy() { super.onDestroy(); } private void enabledStrictMode () {/ / open Thread strategy mode StrictMode. SetThreadPolicy (new StrictMode. ThreadPolicy. Builder (.) detectNetwork () / / monitoring the main thread to use network IO detectCustomSlowCalls () / / monitoring custom slow function. DetectDiskReads () DetectDiskWrites (); penaltyLog(); penaltyDialog(); build(); / / open the VM strategy pattern StrictMode. SetVmPolicy (new StrictMode. VmPolicy. Builder () detectLeakedSqlLiteObjects sqlite leak () / / monitoring DetectLeakedClosableObjects () / / monitoring not closing IO object. SetClassInstanceLimit (MainActivity class, 1) / / set a class instance in memory at the same time limit, Detectacvityleaks ().penaltylog ()// Write log.build ()); }}Copy the code
Run the above code, a warning dialog box pops up
Click OK, check StrictMode log see attached picture
According to the log information, the program spent 75ms on createNewFile, openFile and writeFile, which is a time-consuming operation for the program. Continue with our journal
The file stream is not closed, and we can quickly locate the problem point by logging:
fileOutputStream.write(buffer.toString().getBytes());
fileOutputStream.flush();
Copy the code
After the file stream is flushed, the close method is not executed. As a result, the file resource is held by the object and cannot be released, resulting in a waste of memory and resources.
conclusion
StrictMode in addition to the above cases, StrictMode can also detect IO, network, database and other related operations, and these operations are exactly the most common factors affecting App performance in the process of Android development (time-consuming, CPU time, occupy a large amount of memory). Therefore, it is a good habit to pay attention to StrictMode changes in the development process. On the one hand, it can check the quality of the code of the project team members, and on the other hand, it can help me form some good thinking ways of writing code in the process of Android development. In StrictMode, we should always pay attention to the log conversion (such as method execution time), especially those red logs, because these methods cause huge problems.