Handlers and memory leaks in Android

前端 未结 6 2114
攒了一身酷
攒了一身酷 2020-11-29 18:14

Please have a look at the code below:

public class MyGridFragment extends Fragment{

     Handler myhandler = new Handler() {
    @Override
    public void h         


        
相关标签:
6条回答
  • 2020-11-29 18:34

    Per the ADT 20 Changes, it looks like you should make it static.

    New Lint Checks:

    Check to make sure that Fragment classes are instantiatable. If you accidentally make a fragment innerclass non-static, or forget to have a default constructor, you can hit runtime errors when the system attempts to reinstantiate your fragment after a configuration change.

    Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.

    0 讨论(0)
  • 2020-11-29 18:37

    If you read docs about AccountManager or PendingIntent, you will see that some methods take Handler as one of arguments.

    For example:

    • onFinished - The object to call back on when the send has completed, or null for no callback.
    • handler - Handler identifying the thread on which the callback should happen. If null, the callback will happen from the thread pool of the process.

    Imagine the situation. Some Activity calls PendingIntent.send(...) and put the non-static inner subclass of Handler. And then activity is destroyed. But inner class lives.

    Inner class still holds a link to destroyed activity, it cannot be garbage-collected.

    If you're not planning to send your handler to such methods, you have nothing to worry about.

    0 讨论(0)
  • 2020-11-29 18:42

    I run into the same issue and I find that it is one of this topics with many questions and few answeres. My solution is simple and I hope it can help someone:

    /* BEFORE */
    private Handler mHandler= new Handler() {
            @Override public void handleMessage(Message msg) {
            this.doSomething();
        };
    };
    

    We can create a static Handler subclass that simply runs a Runnable. The actual handler instance will know what to do through the runnable that will have access to instance variables.

    /* AFTER */
    static class RunnableHandler extends Handler {
        private Runnable mRunnable;
        public RunnableHandler(Runnable runnable) { 
            mRunnable = runnable;
        }
        @Override public void handleMessage(Message msg) {
            mRunnable.run();
        };
    }
    private RunnableHandler mHandler = new RunnableHandler(new Runnable() {
        @Override public void run() {
            this.doSomething();
        } });
    

    The warning is gone while the funcionality is the same.

    0 讨论(0)
  • 2020-11-29 18:53

    Here's a somewhat useful little class I made that you can use. Sadly it's still quite verbose because you can't have anonymous static inner classes.

    import java.lang.ref.WeakReference;
    import android.os.Handler;
    import android.os.Message;
    
    /** A handler which keeps a weak reference to a fragment. According to
     * Android's lint, references to Handlers can be kept around for a long
     * time - longer than Fragments for example. So we should use handlers
     * that don't have strong references to the things they are handling for.
     * 
     * You can use this class to more or less forget about that requirement.
     * Unfortunately you can have anonymous static inner classes, so it is a
     * little more verbose.
     * 
     * Example use:
     * 
     *  private static class MsgHandler extends WeakReferenceHandler<MyFragment>
     *  {
     *      public MsgHandler(MyFragment fragment) { super(fragment); }
     * 
     *      @Override
     *      public void handleMessage(MyFragment fragment, Message msg)
     *      {
     *          fragment.doStuff(msg.arg1);
     *      }
     *  }
     * 
     *  // ...
     *  MsgHandler handler = new MsgHandler(this);
     */
    public abstract class WeakReferenceHandler<T> extends Handler
    {
        private WeakReference<T> mReference;
    
        public WeakReferenceHandler(T reference)
        {
            mReference = new WeakReference<T>(reference);
        }
    
        @Override
        public void handleMessage(Message msg)
        {
            if (mReference.get() == null)
                return;
            handleMessage(mReference.get(), msg);
        }
    
        protected abstract void handleMessage(T reference, Message msg);
    }
    
    0 讨论(0)
  • 2020-11-29 18:57

    I recently updated something similar in my own code. I just made the anonymous Handler class a protected inner class and the Lint warning went away. See if something like the below code will work for you:

    public class MyGridFragment extends Fragment{
    
        static class MyInnerHandler extends Handler{
            WeakReference<MyGridFragment> mFrag;
    
            MyInnerHandler(MyGridFragment aFragment) {
                mFrag = new WeakReference<MyGridFragment>(aFragment);
            }
    
            @Override
            public void handleMessage(Message message) {
                MyGridFragment theFrag = mFrag.get();
                switch (message.what) {
                case 2:
                    ArrayList<HashMap<String,String>> theurls = (ArrayList<HashMap<String,String>>) message.obj;
                    theFrag.urls.addAll(theurls);
                    theFrag.theimageAdapter.notifyDataSetChanged();
                    theFrag.dismissBusyDialog();
                    break;
                }//end switch
            }
        }
        MyInnerHandler myHandler = new MyInnerHandler(this);
    }
    

    You may have to change where I put "theFrag." as I could only guess as to what those referenced.

    0 讨论(0)
  • 2020-11-29 18:57

    A simple solution for this case might be:

    Handler handler=new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message message) {
            //do your stuff here
            return false;
        } });
    
    0 讨论(0)
提交回复
热议问题