Introduction
- Background: Android app Optimizer, what to do?
- Performance analysis tools for Android app optimization
- Android App Optimizer's rationale for boosting your app's startup speed
- Android app optimizer boosts your app launch Speed instance challenge
- How the Android app optimization layout is placed
- Android App Optimizer's ANR explanation
- Android app optimization eliminates lag
- Optimized memory optimization for Android apps
- Android app optimized for long-lasting power
- How the Android app optimizes for efficient network requests
App Optimization series has been in the near-term, before sharing a number of tools, theory, also combined with the case of the start optimization, layout analysis and so on.
The original plan is to use this article as a connecting point in this series, to make a small summary of the previous few, chat about the app fluency and fast response topic.
Thick a Wisp, found content or a lot of, for a moment to break into a few to slowly write it, do not blame ~
Let's talk about ANR today.
1, did you meet the ANR?
You may have encountered this situation during app use:
Anr
Congratulations, this is the legendary ANR.
1.1 What is ANR
The ANR full name application not responding, which is "application unresponsive." When the operation is not processed by the system for a period of time, the system level will pop up the ANR dialog box.
1.2 Why does it produce ANR?
In Android, the app's responsiveness is monitored by Activity Manager and Window Manager System services. The ANR dialog box usually pops up in the following two scenarios:
- Unable to respond to user input events (such as keyboard input, touch screen, etc.) within 5s.
- The broadcastreceiver cannot end within 10s.
The primary reason for both of these situations is that there are too many time-consuming operations in the main thread (UI thread), such as file reads and writes, database reads and writes, network queries, and so on.
1.3 How to avoid ANR
Know the cause of the ANR, then want to avoid the ANR, it is very simple, a rule:
Do not perform heavy operations on the main thread (UI thread).
This actually involves two questions:
- Which places are running on the main thread?
- Not the main thread, where do you do it?
Answer later.
2, ANR Analysis 2.1 Get ANR generated trace file
When ANR is generated, the system generates a Traces.txt file that is placed under/data/anr/. You can export it locally by using the ADB command:
$adb pull data/anr/traces.txt .
2.2 Analysis of ANR caused by traces.txt2.2.1 common obstruction
The tracs.txt files obtained are generally as follows:
The following is a Githubapp code example, forcing the sleep thread to produce a ANR.
-----PID2976 at2016-09-0823:02:-----CMD Line:com.anly.githubappLatest ANR Occurrence process (package name) ...DALVIKTHREADS(): "Main" prio=5 tid=1 Sleeping | group="Main" scount=1 dscount=0 obj=0x73467fa8 self=0x7fbf66c95000 | Systid=2976 nice=0 cgrp=Default sched=0/0 handle=0x7fbf6a8953e0 | State=s schedstat= (000) utm=stm=Panax Notoginseng core=1 hz=100 | stack=0x7ffff4ffd000-0x7ffff4fff000 stacksize=8MB | Held mutexes= at java.lang.thread.sleep! (Native method)-Sleeping on <0x35fc9e33> (a java.lang.Object) at Java.lang.Thread.sleep (Thread.java:1031)-Locked <0x35fc9e33> (a java.lang.Object) at Java.lang.Thread.sleep (Thread.java:985)Sleep is too long in the main thread, blocking causes no response. At COM.TENCENT.BUGLY.CRASHREPORT.CRASH.C.L (bugly:258)-Locked <@addr =0x12dadc70> (a com.tencent.bugly.crashreport.crash.c) at Com.tencent.bugly.crashreport.CrashReport.testANRCrash (bugly:166)The function call that generated the ANR-locked <@addr =0x12d1e840> (a java.lang.class<com.tencent.bugly.crashreport.crashreport>) at COM.ANLY.GITHUBAPP.COMMON.WRAPPER.CRASHHELPER.TESTANR (Crashhelper.java:At Com.anly.githubapp.ui.Module.main.MineFragment.onClick (Minefragment.java:90HThe start of the ANR at Com.anly.githubapp.ui.module.main.minefragment_viewbinding$2.doClick (Minefragment_viewbinding.java:At Butterknife.internal.DebouncingOnClickListener.onClick (Debouncingonclicklistener.java:@ Android.view.View.performClick (view.java:4780) at Android.view.view$performclick.run (View.java: 19866) at Android.os.Handler.handleCallback (Handler.java:739) at Android.os.Handler.dispatchMessage ( Handler.java:android.os.Looper.loop (Looper.java:135) at Android.app.ActivityThread.main ( Activitythread.java:5254) at java.lang.reflect.method.invoke! (Native method) at Java.lang.reflect.Method.invoke (Method.java:372) at com.android.internal.os.zygoteinit$ Methodandargscaller.run (Zygoteinit.java:903) at Com.android.internal.os.ZygoteInit.main (Zygoteinit.java: 698)
Get the trace information, everything.
The addition of the Chinese note in the trace information has basically explained how the trace file should be analyzed:
- Most of the files are the latest generated ANR trace information.
- The previous two lines indicate the process PID, time, and process name (package name) that the ANR occurred.
- Look for our code point, then push forward and look at the method call stack, which goes back to the root cause of the problem.
The above ANR trace is relatively simple, and you may not be doing too much time-consuming operations in the main thread, but it is still ANR. This is probably the following two scenarios:
2.2.2 CPU Full load
The trace information you see at this time may contain information such as:
Process:com.anly.githubapp ... CPU usage from3330ms to814ms ago:6% 178/system_server: 3.5% user + 1.4% kernel/faults: "Minor" Major 4.6%
2976/com.anly.githubapp:
0.7% user + 3.7% kernel/faults: Minor, Major 0.9% 252/com.an Droid.systemui: 0.9% user + 0% kernel ... 100%total: 5.9% user + 4.1% kernel + 89% iowait
The last sentence shows:
- When it is CPU consuming 100%, full load.
- The largest number is occupied by iowait, which is the I/O operation.
At this point, the analysis method call stack, generally will find that the method has frequent file read-write or database read and write operations in the main thread to do.
2.2.3 Memory reasons
In fact, memory causes may cause ANR, for example, if the app can use very little memory due to memory leaks, we click the button to launch a large picture as the background activity, may produce ANR, then trace information may be this:
The following trace information is from the network and is used to make an example Cmdline:android.process.acoreDALVIK THREADS:"Main" prio=5 tid=3 vmwait|group="Main" scount=1 dscount=0 S=n obj=0x40026240self=0xbda8| Systid=1815 nice=0 sched=0/0 cgrp=unknownhandle=- 1344001376atdalvik.system.vmruntime.trackexternalallocation (Nativemethod) Atandroid.graphics.Bitmap.nativeCreate (Native Method) Atandroid.graphics.Bitmap.createBitmap (Bitmap.java:468) Atandroid.view.View.buildDrawingCache (View.java:6324) Atandroid.view.View.getDrawingCache (View.java:6178) ... Meminfo in pid 1360 [Android.process.acore] **native Dalvik Other totalsize: 17036 23111 N/a 40147allocated: 16484 20675 N/a 37159free: 296 2436 N/a 2732
You can see that free memory is running out.
Of course this situation may be more likely to produce oom anomalies ...
Treatment of 2.2 ANR
For three different situations, the general treatment is as follows
The main thread is blocking the
Separate sub-threads are opened to handle time-consuming blocking transactions.
CPU full load, I/O blocking
I/O blocking is generally a file read or write or database operation is performed on the main thread, or it can be executed asynchronously by opening a child thread.
Not enough memory to use
Increase VM memory, use the Largeheap property, and troubleshoot memory leaks (this is in memory optimization).
3, go a little deeper.
No one wants to solve the problem after it has gone wrong.
The difference between a master and a novice is that a master knows how to avoid problems in the first place. So what levels of work do we need to do to avoid the problem of ANR?
3.1 Where is the execution of the main thread
- All life cycle callbacks for an activity are performed on the main thread.
- Service defaults are performed on the main thread.
- The Broadcastreceiver OnReceive callback is performed on the main thread.
- Without the handlemessage of the Looper handler that uses the child thread, the post (Runnable) is executed on the main thread.
- In addition to the Doinbackground in Asynctask's callback, the others are executed in the main thread.
- The View post (Runnable) is executed on the main thread.
3.2 What are the ways to use child threads
We almost always say that the way to avoid ANR is to perform time-consuming blocking operations on child threads. So what are some of the ways that we can do this in android?
3.2.1 Start Thread mode
This is actually the way that Java implements multithreading. There are two implementations that inherit the thread or implement the Runnable interface:
Inherit thread
class PrimeThread extends Thread { long minPrime; PrimeThread(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . }}PrimeThread p = new PrimeThread(143);p.start();
Implementing the Runnable Interface
class PrimeRun implements Runnable { long minPrime; PrimeRun(long minPrime) { this.minPrime = minPrime; } public void run() { // compute primes larger than minPrime . . . }}PrimeRun p = new PrimeRun(143);new Thread(p).start();
3.2.2 Using Asynctask
This is an Android-specific way, Asynctask, as the name implies, is the meaning of asynchronous tasks.
PrivateClassDownloadfilestaskExtendsasynctask<UrlInteger,long> {Do the long-runningExecuting on a child threadProtected LongDoinbackground(URL ... URLs) {int count = Urls.length;Long totalsize =0;for (int i =0; I < count; i++) {totalsize + = Downloader.downloadfile (Urls[i]); Publishprogress ((int) ((I/(FLOAT) count) *100));Escape early if Cancel () is calledif (iscancelled ())Break }return totalsize; }Called each time publishprogress ()//execute on the main thread protected void onprogressupdate(Integer ... progress) {setprogresspercent (progress[ 0]); } //This is called Time Doinbackground () is finished //performed on the main thread protected void onpostexecute(Lo ng result) {shownotification ("downloaded" + result + "bytes");}} //Start mode new Downloadfilestask (). Execute (URL1, URL2, url3);
3.2.3 Handlerthread
A way to combine handler and thread in Android. There is a cloud in front, by default handler's handlemessage is executed on the main thread, but if I give this handler the looper of the child thread, Handlemessage will execute it in that child thread. Handlerthread is exactly one such combination:
Start a child thread named New_thread handlerthread thread =New Handlerthread ("New_thread"); Thread.Start ();Take New_thread assignment to ServicehandlerPrivate Servicehandler Mservicehandler;mservicelooper = Thread.getlooper (); Mservicehandler =new Servicehandler (Mservicelooper); Private Final class Servicehandler extends Handler { public Servicehandler( Looper Looper) { super (Looper);} @Override public void handlemessage(Message msg) { //At this time Handlemessage is running in New_ Thread is in this sub-thread. }}
3.2.4 Intentservice
The service is running on the main thread, however Intentservice is running on the child thread.
In fact Intentservice is the realization of a Handlerthread + Servicehandler mode.
The above Handlerthread use code example also comes from the intentservice source.
3.2.5 Loader
Android 3.0 introduces a data loader that can be used in activity/fragment. Supports asynchronous loading of data and monitors the data source to pass new results when data changes. Commonly used are cursorloader, which are used to load database data.
Prepare the loader. Either re-connect with an existing one,Or start a new one.Use Loadermanager to initialize Loadergetloadermanager (). Initloader (0,Nullthis);If the loader specified by ID already exists, the last created loader is reused.If the ID specified loader does not exist, then Initloader () will trigger the Loadermanager.loadercallbacks method//oncreateloader (). In this method, you can implement code to instantiate and return the new loaderCreate a LoaderPublic loader<cursor>Oncreateloader(int ID, Bundle args) {This is called if a new Loader needs to be created. ThisSample only have one Loader, so we don't care about the ID.First, pick the base URI to use depending on whether we isCurrently filtering. Uri BaseUri;if (mcurfilter! =NULL) {BaseUri = Uri.withappendedpath (Contacts.content_filter_uri, Uri.encode (Mcurfilter));}else {BaseUri = Contacts.content_uri;}Now create and return a CursorloaderCreating a Cursor for the data being displayed. String select ="((" + Contacts.display_name +"Notnull) and ("+ Contacts.has_phone_number + " =1) and ("+ Contacts.display_name + "! = "))"; return New Cursorloader (Getactivity (), BaseUri, Contacts_summary_projection, select, null, Contacts.display_name + "COLLATE localized ASC");} //Load complete public void onloadfinished(loader<cursor> Loader, Cursor data) { //Swap the new Cursor in. (The framework would take care of closing the //old cursor once we return.) madapter.swapcursor (data);}
Please refer to the website loader for details.
3.2.6 Special attention
When using thread and Handlerthread, it is recommended that you set the thread to a lower priority for better results:
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
Because if you do not have any priority settings, the thread default and UI thread you create have the same priority, you know. The same priority thread, CPU scheduling may still block out your UI Thread, resulting in ANR.
Conclusion
In the case of ANR, the individual thinks it is a precaution, recognize the blocking point in the code, and use the thread. At the same time form good programming habits, to have the concept of mainthread and worker thread ... (In fact, people's working condition is the same ~ haha)
Android App Optimizer's ANR explanation