9

Given this code:

public class MainActivity extends FragmentActivity implements ActionBar.TabListener {

public static final int MESSAGE_NOT_CONNECTED = 1;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

// -------------------------------------------------
public final void setStatus(int Rid) {
    final ActionBar actionBar = getActionBar();
    actionBar.setSubtitle(Rid);
}

// -------------------------------------------------
static Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
        case MESSAGE_NOT_CONNECTED:
            setStatus(R.string.title_not_connected);
            break;
        }
    }
}
}

I am getting the compile error: Cannot make a static reference to the non-static method setStatus(int) ...

Which makes sense, because getActionBar() in setStatus() is a non-static method.

I made the Handler class static because of the warning: This Handler class should be static or leaks might occur.

The question: how do I properly access the setStatus() method from within the static handler?

EDIT: new handler code is the answer.

static class hHandler extends Handler {
    private final WeakReference<MainActivity> mTarget;
    hHandler(MainActivity target) {
        mTarget = new WeakReference<MainActivity>(target);
    }

    @Override
    public void handleMessage(Message msg) {
        MainActivity target = mTarget.get();
        If(target == null) {
             return;
        }
        switch (msg.what) {
        case MESSAGE_NOT_CONNECTED:
            target.setStatus(R.string.title_not_connected);
            break;
        }
    }
}
NickL
  • 4,258
  • 2
  • 21
  • 38
vedavis
  • 958
  • 1
  • 13
  • 22
  • 1
    http://stackoverflow.com/q/11407943/844882 – Alex Lockwood Aug 06 '12 at 12:32
  • The link that @Alex Lockwood provided, lead to another link from Romain Guy that helped me understand WeakReferences: static vs non-static inner classes [link](https://groups.google.com/forum/?fromgroups#!msg/android-developers/1aPZXZG6kWk/lIYDavGYn5UJ). I can answer my own question, but I can't post it yet. – vedavis Aug 06 '12 at 14:18
  • I answered the question (since you apparently can't post it yet...) :P – Alex Lockwood Aug 06 '12 at 16:38

3 Answers3

10

Try using a WeakReference, as described in this article.

Alex Lockwood
  • 83,063
  • 39
  • 206
  • 250
  • That is the answer. I edited the original post with the changes. Thanks for posting, Alex. – vedavis Aug 06 '12 at 17:11
  • @Alex Lockwood That article is nice, but it doesn't explain how to get a context from the static Handler. I was using a Toast from inside handleMessage using Toast.makeText(getApplicationContext(), dataString, Toast.LENGTH_SHORT).show(); Now that the Handler is static, getApplicationContext() doesn't make sense. My Handler is inside a Service if that matters. – David Doria Oct 02 '13 at 12:33
  • @DavidDoria Give the `Handler` a constructor which takes a `Context` as an argument and then holds a weak reference to that `Context`. – Alex Lockwood Oct 02 '13 at 13:40
1

Since you are now using a WeakReference, mTarget.get() might return null. In your edited code, you are not checking if target is null before executing target.setStatus(R.string.title_not_connected). So this may throw a NullPointerException if the weakreference object has been GC'ed.

NickL
  • 4,258
  • 2
  • 21
  • 38
0

In my activity's onDestroy method I call:

this.myHandler.removeCallbacksAndMessages(null);

This does not get rid of the "This Handler class should be static or leaks might occur" warning, but I believe it destroys the message hence stopping the leak. My handler class is an inner non-static class of my activity. My activity has an instance of MyHandler myHandler.

When I do this, the handler's handleMessage method isn't called, which I assume means that the message containing the handler, which contained a reference to the activity was destroyed. Am open for comments as I haven't tested it with any leak testing tools. Here is where I copied the idea: http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html answerer: CyrilJanuary 15, 2013 at 7:50 AM

flobacca
  • 936
  • 2
  • 17
  • 42