非静态方法问题
Non static method issue
通过 android studio 运行 代码检查后,强调 MainHandler 应该是静态的。我将 class 移动到 static 但现在它抱怨说
"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();
}
知道如何解决吗?
我不是 android 程序员,但也许与其创建扩展 Handler 的内部 class,不如像这样创建私有字段:
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
//call your non static method here
}
}
这个 Whosebug post here 解释了为什么内部 classes 应该是静态的,这与代码分析器抱怨它的原因几乎相同,假设如果你想要包含 class 的成员可以从你的内部访问 class 你可以让它成为非静态的
修改MainHandler的构造函数接收回调接口
public MainHandler(Callback cb){
this.mCallBack = cb;
}
然后在handleMessage调用回调接口执行方法
public void handleMessage(Message message) {
if (message.what == SET_TIMER_TEXT) {
mCallBack.someMethod();1);
}
}
在片段声明接口
public interface Callback
{
void someMethod();
}
让你的片段实现它。
private final MainHandler mHandler = new MainHandler(this);
然后在执行调用
remainingSecondsChanged(mRemainingSecs - 1);
这不是最好的方法,但它是您当前设计中最快的方法。
首先...为什么 Studio 会显示该消息?
背景
每个 Handler
都与一个 Thread
关联,同一 Thread
上的所有 Handler
对象共享一个公共 Looper
对象,它们 post 并阅读他们的消息。事情是......当这些对象是非静态的......非静态内部classes持有对其外部class的隐式引用。因此 Handler
将持有对您的 Activity
的引用,如果此 Handler
有延迟消息,您的 Activity
将无法在处理此消息之前被垃圾回收.
您可以阅读更多相关信息 here。
解决方案
至于你的问题。您已经做的第一件事就是让您的 Handler
成为 static
内部 class。现在,为你的外部 class 创建一个 WeakReference
(可以是一个 Activity
或者我相信在这种情况下,你的 CountDownView
)。
现在尝试将您的 Handler
更改为类似这样的内容(您可以参考您的 CountDownView
而不是 Activity
):
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);
}
}
}
}
并像这样实例化它:
// this is a reference to your Activity, or your CountDownView, wherever your method is.
private final MainHandler mHandler = new MainHandler(this);
通过 android studio 运行 代码检查后,强调 MainHandler 应该是静态的。我将 class 移动到 static 但现在它抱怨说 "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();
}
知道如何解决吗?
我不是 android 程序员,但也许与其创建扩展 Handler 的内部 class,不如像这样创建私有字段:
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
//call your non static method here
}
}
这个 Whosebug post here 解释了为什么内部 classes 应该是静态的,这与代码分析器抱怨它的原因几乎相同,假设如果你想要包含 class 的成员可以从你的内部访问 class 你可以让它成为非静态的
修改MainHandler的构造函数接收回调接口
public MainHandler(Callback cb){
this.mCallBack = cb;
}
然后在handleMessage调用回调接口执行方法
public void handleMessage(Message message) {
if (message.what == SET_TIMER_TEXT) {
mCallBack.someMethod();1);
}
}
在片段声明接口
public interface Callback
{
void someMethod();
}
让你的片段实现它。
private final MainHandler mHandler = new MainHandler(this);
然后在执行调用
remainingSecondsChanged(mRemainingSecs - 1);
这不是最好的方法,但它是您当前设计中最快的方法。
首先...为什么 Studio 会显示该消息?
背景
每个 Handler
都与一个 Thread
关联,同一 Thread
上的所有 Handler
对象共享一个公共 Looper
对象,它们 post 并阅读他们的消息。事情是......当这些对象是非静态的......非静态内部classes持有对其外部class的隐式引用。因此 Handler
将持有对您的 Activity
的引用,如果此 Handler
有延迟消息,您的 Activity
将无法在处理此消息之前被垃圾回收.
您可以阅读更多相关信息 here。
解决方案
至于你的问题。您已经做的第一件事就是让您的 Handler
成为 static
内部 class。现在,为你的外部 class 创建一个 WeakReference
(可以是一个 Activity
或者我相信在这种情况下,你的 CountDownView
)。
现在尝试将您的 Handler
更改为类似这样的内容(您可以参考您的 CountDownView
而不是 Activity
):
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);
}
}
}
}
并像这样实例化它:
// this is a reference to your Activity, or your CountDownView, wherever your method is.
private final MainHandler mHandler = new MainHandler(this);