0

Inside of the handler after I first enter the app from a clean state, the Handler handles the MSG_PULLED action however, the reference to main is null. The weak reference is not null. How can this possibly be happening?

Inspired by this post: This Handler class should be static or leaks might occur: IncomingHandler

static class MainHandler extends Handler {
    private final WeakReference<MainActivity> wMain; 
    static int angle=0;
    public MainHandler(MainActivity main) {
        super();
        this.wMain = new WeakReference<MainActivity>(main);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        MainActivity main = wMain.get();
        int what = msg.what;
        if(what == MSG_PULLED) {
            main.startAnim();
        } 
    }
}

And how I initiate the handler:

static MainHandler mainHandler;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mainHandler = new MainHandler(this);
        mainHandler.sendEmptyMessageDelayed(MSG_PULLED,500);
    }
Community
  • 1
  • 1
hunterp
  • 15,716
  • 18
  • 63
  • 115
  • 1
    Whatever a `WeakReference` references can be garbage collected when no other entity keeps a strong reference to that instance. That's probably what happened. – zapl Sep 29 '12 at 20:03
  • Zapl, sounds interesting, but I am not fully grasping the implication of your insight. Can you put this in the context of the flow of my activity? – hunterp Sep 29 '12 at 20:04

1 Answers1

1

The Activity instances in your app are regularly destroyed and new ones are created for example when rotating the display.

Now what should happen in that case is that the old instance is garbage collected and only the new one exists. If you keep the old one around you have created a leak.

Since Handler are not garbage collectable until they have no more messages (?) they can live longer than the Activity in witch they were created, which usually leads to leaking the old Activity (until the Handler can be collected) since Handler usually have a strong reference to their Activity.

The WeakReference way in your code get's rid of that problem by keeping just a weak link to the Activity that does not prevent garbage collection.

The problem is that you use the get() method the wrong way: get() will only return the original object while it exists. When it's gone you get null. Here: the Activity will exists while it is still the active one (determined by the system).

The null is also not a big problem: when you get null your Activity instance is no longer alive (maybe a new one was created, maybe it's completely gone) so you can't do anything useful with it anymore. Animation would not show even if you had still a reference.

Basically do it like below and your problem is solved

@Override
public void handleMessage(Message msg) {
    super.handleMessage(msg);
    MainActivity main = wMain.get();

    // message arrived after activity death
    if (main == null) return;

    int what = msg.what;
    if(what == MSG_PULLED) {
        main.startAnim();
    } 
}

The WeakReference itself (wMain) is not null because it is itself strongly references as a member variable. Just the content inside it can / will be null at some point.

zapl
  • 63,179
  • 10
  • 123
  • 154
  • Sounds good. I actually eliminated weak reference. Can you make a case of why its a popular meme at the moment? I forget why I even added it in the first place – hunterp Sep 29 '12 at 20:30
  • "Inspired by this post: This Handler class should be static or leaks might occur: IncomingHandler". You should not create leaks and Eclipse/Lint started warning about non-static handlers recently so I guess that's why you added it and should keep it. Not sure about the popular meme part – zapl Sep 29 '12 at 20:35
  • Yes, but now I made it a plain old reference and eclipse is not warning. – hunterp Sep 29 '12 at 21:35
  • 1
    Eclipse won't detect that but the problem it is warning about is still there. – zapl Sep 29 '12 at 21:51
  • Thing is, i'm not seeing it in my Error reporting from Android. – hunterp Oct 01 '12 at 06:16
  • 1
    Because it is not an error that leads to guaranteed app crashes. It's about consuming more memory than required which *can* lead to `OutOfMemoryException` – zapl Oct 01 '12 at 11:47