1

After running a code inspection through android studio, it highlight that the MainHandler should be static. I move the class to static but now it complain that "Non-Static method remainingSecondsChanged(int) cannot be referenced from a static context"

public class CountDownView extends FrameLayout {

    private static void remainingSecondsChanged(int newVal) {
        mRemainingSecs = newVal;
        if (mListener != null) {
            mListener.onRemainingSecondsChanged(mRemainingSecs);
        }

        if (newVal == 0) {
            // Countdown has finished.
            setVisibility(View.INVISIBLE);
            if (mListener != null) {
                mRemainingSecondsView.setText(null);
                mRemainingSecondsView.setBackgroundResource(R.drawable.bracket_view_finder);
                mListener.onCountDownFinished();
            }
        } else {
            Locale locale = getResources().getConfiguration().locale;
            String localizedValue = String.format(locale, "%d", newVal);
            mRemainingSecondsView.setText(localizedValue);

            // Schedule the next remainingSecondsChanged() call in 1 second
            mHandler.sendEmptyMessageDelayed(SET_TIMER_TEXT, 1000);
        }
    }

    public void startCountDown(int sec) {
        if (sec < 0) {
            return;
        }
        if (sec == 0) {
            cancelCountDown();
        }
        mRemainingSecondsView.setBackgroundResource(R.drawable.bracket_count_down);
        setVisibility(View.VISIBLE);
        remainingSecondsChanged(sec);
    }

    private static class MainHandler extends Handler {

        @Override
        public void handleMessage(Message message) {
            if (message.what == SET_TIMER_TEXT) {
                remainingSecondsChanged(mRemainingSecs - 1);
            }
        }
    }

    private static final MainHandler mHandler = new MainHandler();

}

Any idea how to fix it ?

Seb
  • 2,929
  • 4
  • 30
  • 73
  • You can make `remainingSecondsChanged` static – BNK Aug 06 '15 at 08:17
  • @ChungPham I have tried but after the setVisibility, Locale locale = getResources() are complaining about same issues – Seb Aug 06 '15 at 08:19

4 Answers4

2

This StackOverflow post here Explains why the inner classes should be static and it is the pretty much same reason why the code analyzer complaints about it,Suppose If you want the members of the containing class to be accessible from your inner class you can make it non static

Community
  • 1
  • 1
nvinayshetty
  • 3,187
  • 1
  • 21
  • 32
2

First... Why's Studio showing that message?

Background

Each Handler is associated with a Thread, and all Handler objects on the same Thread share a common Looper object, where they post and read their messages. Thing is... when these objects are non-static well... non-static inner classes hold an implicit reference to their outer class. So the Handler will hold a reference to your Activity, and if this Handler has a delayed message, your Activity will be unable to be garbage collected until this message is processed.

You can read more about it here.

Solution

As for your problem. The first thing you already did, which is make your Handler a static inner class. Now, create a WeakReference to your outer class (Could be an Activity or I believe in this case, your CountDownView).

Now try changing your Handler to something like this (Instead of Activity you could reference your CountDownView):

private static class MainHandler extends Handler {

    private final WeakReference<YourActivity> mActivity;

    public MainHandler(YourActivity activity) {
        mActivity = new WeakReference<YourActivity>(activity);
    }

    @Override
    public void handleMessage(Message message) {
        YourActivity activity = mActivity.get();
        if (activity != null) {
            if (message.what == SET_TIMER_TEXT) {
                activity.remainingSecondsChanged(mRemainingSecs - 1);
            }
        }            
    }
}

And instantiate it like this:

// this is a reference to your Activity, or your CountDownView, wherever your method is.
private final MainHandler mHandler = new MainHandler(this);
Mauker
  • 11,237
  • 7
  • 58
  • 76
0

I am not android programmer but maybe instead of creating inner class which extends Handler than you can create private field like this:

private Handler handler = new Handler() {
   public void handleMessage(Message msg) {
      //call your non static method here
   }
}
wawek
  • 1,577
  • 1
  • 13
  • 23
0

Change the constructor of the MainHandler to receive a callback interface

public MainHandler(Callback cb){
  this.mCallBack = cb;
}

Then at handleMessage call the callback interface to perform the method

 public void handleMessage(Message message) {
            if (message.what == SET_TIMER_TEXT) {
                mCallBack.someMethod();1);
            }
        }

At fragment declare interface

public interface Callback
{
 void someMethod();
}

Make your fragment implement it.

private final MainHandler mHandler = new MainHandler(this);

Then at the implementation call

        remainingSecondsChanged(mRemainingSecs - 1);

This is not the best way to do it but its the fastest with your current design.

EE66
  • 4,601
  • 1
  • 17
  • 20