Android Learning Series (37)-Context of App debugging Memory leakage (II)

Source: Internet
Author: User

Next, go to Android Learning Series (36)-Context of App debugging Memory leakage (part I) to continue the analysis.

5. AsyncTask object

I went to the Grand interview for a test N years ago. At that time, the interviewer strongly recommended me to use AsyncTask and other built-in systems to do things. Of course, it is understandable.

However, AsyncTask requires additional attention. The leakage principle is similar to that of Handler and Thread. its lifecycle is not necessarily the same as that of Activity.

Solution:Terminate the background task in AsyncTask when the activity exits.

However, the question is how to terminate it?

AsyncTask provides the corresponding API: public final boolean cancel (boolean mayInterruptIfRunning ).

It provides the following explanation:

// Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. // If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.

Cancel may not succeed. If it is running, it may interrupt background tasks. How does it feel so unreliable?

Yes, it is unreliable.

So how can we be reliable? Let's take a look at the official example:

Private class DownloadFilesTask extends AsyncTask <URL, Integer, Long> {protected Long doInBackground (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 called // pay attention to the following line. if cancel is detected, exit if (isCancelled () break;} return totalSize;} protected void onProgressUpdate (Integer... progress) {setProgressPercent (progress [0]);} protected void onPostExecute (Long result) {showDialog ("Downloaded" + result + "bytes ");}}

The official example is very good. It listens to the cancel status at any time in the background loop to prevent timely exit.

To remind everyone, google deliberately put down a large part of English in AsyncTask's description:

// AsyncTask is designed to be a helper class around Thread and Handler and does not constitute a generic threading framework. AsyncTasks should ideally be used for short operations (a few seconds at the most.) If you need to keep threads running for long periods of time, it is highly recommended you use the various APIs provided by the java.util.concurrent pacakge such as Executor, ThreadPoolExecutor and FutureTask.

Poor me, the Chinese mainland has a vast territory and a vast land and resources. Nothing is missing, that is, the lack of sensitivity to English reading.

Learn English well and avoid mistakes!

 

6. BroadcastReceiver object

... Has leaked IntentReceiver... Are you missing a call to unregisterReceiver ()?

The unregister () method is not called for various reasons.

The solution is simple.Make sure to call the unregister () method.

By the way, I encountered an opposite situation in my work. The Referer object was not successfully called by registerReceiver (), so an error was prompted during unregister:

// Java. lang. IllegalArgumentException: aggreger not registered...

There are two solutions:

Solution 1: After registerReceiver (), set a FLAG to determine whether it is unregister () based on the FLAG (). Almost all the articles found on the Internet are written in this way. I have encountered such a bug and I have been doing this all the time. But it is undeniable that such code looks really ugly.

Solution 2: I accidentally heard a great reminder that I saw a more common method in the Android source code:

// Just sample, which can be written into the tool class. // at first glance, I can see this code, which is too rough. But when I look back, what I want is so simple and crude, do not make some simple things so complicated. Private void unregisterReceiverSafe (BroadcastReceiver receiver ER) {try {getContext (). unregisterReceiver (receiver ER);} catch (IllegalArgumentException e) {// ignore }}

  

7. TimerTask object

When the TimerTask object is used with the schedule () method of the Timer, it is very easy to cause memory leakage.

Private void startTimer () {if (mTimer = null) {mTimer = new Timer ();} if (mTimerTask = null) {mTimerTask = new TimerTask () {@ Override public void run () {// todo};} if (mTimer! = Null & mTimerTask! = Null) mTimer. schedule (mTimerTask, 1000,100 0 );}

The leak is,You forgot to delete the Timer and TimerTask instances. The timing of cancel is the same as that described in cursor. cancel can be used when appropriate.

private void cancelTimer(){          if (mTimer != null) {              mTimer.cancel();              mTimer = null;          }          if (mTimerTask != null) {              mTimerTask.cancel();              mTimerTask = null;          }    } 

 

8. Observer object.

The leakage of Observer objects is also a common, easy-to-discover, and easy-to-solve type of leakage.

First look at a piece of normal code:

// It is actually very simple, but ContentObserver is a system example, it is necessary to give a note to everyone, do not take it lightly private final ContentObserver mSettingsObserver = new ContentObserver (new Handler ()) {@ Override public void onChange (boolean selfChange, Uri uri) {// todo}; @ Override public void onStart () {super. onStart (); // register the observer getContentResolver (). registerContentObserver (Settings. global. getUriFor (xxx), false, mSettingsObserver) ;}@ Override public void onStop () {super. onStop (); // unregister it when stoping getContentResolver (). unregisterContentObserver (mSettingsObserver );}

After reading the example, let's look at the case:

    private final class SettingsObserver implements Observer {        public void update(Observable o, Object arg) {            // todo ...        }       }     mContentQueryMap = new ContentQueryMap(mCursor, Settings.System.XXX, true, null);     mContentQueryMap.addObserver(new SettingsObserver());

Who is so lazy? How can this problem be solved by passing the SettingObserver into an anonymous object?

Therefore, some lazy cannot be stolen, and some syntactic Sugar cannot be eaten.

The solution is,Delete the Observer when it is not required or exited.

private Observer mSettingsObserver;@Overridepublic void onResume() {    super.onResume();    if (mSettingsObserver == null) {        mSettingsObserver = new SettingsObserver();    }       mContentQueryMap.addObserver(mSettingsObserver);}@Overridepublic void onStop() {    super.onStop();    if (mSettingsObserver != null) {        mContentQueryMap.deleteObserver(mSettingsObserver);    }       mContentQueryMap.close();}

Note that different registration methods and anti-registration methods are different.

// For reference only, do not rigid/* addCallback <==> removeCallbackregisterReceiver <==> unregisterReceiveraddObserver <==> response <==> unregisterContentObserver ......*/

 

9. Dialog object

Android. view. WindowManager $ BadTokenException: Unable to add window -- token android. OS. BinderProxy @ 438afa60 is not valid; is your activity running?

Generally, the MESSAGE of Handler is in the queue, and the Activity has exited. Then, Handler starts to process the Dialog related tasks.

The key point is how to determine whether the Activity is exited. Someone says, set a FLAG in onDestroy. I'm sorry to tell you that this mistake is likely to happen again.

Solution:

Handler handler = new Handler () {public void handleMessage (Message msg) {switch (msg. what) {case MESSAGE_1: // isFinishing = true, it is not processed. end if (! IsFinishing () {// do not exit // removeDialog () // showDialog ()} break; default: break;} super. handleMessage (msg );}};

Release early!

 

10. Other Objects

Mainly Listener objects ,"Put yourself in. Remember to release yourself in time.".

 

11. Summary

Combined with Context and Cursor, We have enumerated a large number of leaked instances, most of which have similar root causes.

After analyzing these examples, we should be able to understand 90% of the Memory leakage at the APP layer.

As for how to discover and locate memory leaks, this is another interesting topic. Now I can only say that there are methods and tools.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.