这个Handler类应该是静态的,否则可能会发生泄漏

我正在开发一个带有服务的Android 2.3.3应用程序。我在这个服务中有这个来与Main活动通信:

public class UDPListenerService extends Service
{
private static final String TAG = "UDPListenerService";
//private ThreadGroup myThreads = new ThreadGroup("UDPListenerServiceWorker");
private UDPListenerThread myThread;
/**
* Handler to communicate from WorkerThread to service.
*/
private Handler mServiceHandler;


// Used to receive messages from the Activity
final Messenger inMessenger = new Messenger(new IncomingHandler());
// Use to send message to the Activity
private Messenger outMessenger;


class IncomingHandler extends Handler
{
@Override
public void handleMessage(Message msg)
{
}
}


/**
* Target we publish for clients to send messages to Incoming Handler.
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
[ ... ]
}

在这里,final Messenger mMessenger = new Messenger(new IncomingHandler());,我得到以下Lint警告:

This Handler class should be static or leaks might occur: IncomingHandler

这是什么意思?

145130 次浏览

如果IncomingHandler类不是静态的,它将有一个对你的Service对象的引用。

同一个线程的Handler对象都共享一个共同的Looper对象,它们向该对象发布消息并从中读取消息。

由于消息包含目标Handler,只要消息队列中有带有目标处理程序的消息,处理程序就不能被垃圾收集。如果处理器不是静态的,你的ServiceActivity不能被垃圾收集,即使在被销毁之后。

这可能会导致内存泄漏,至少在一段时间内——只要消息处于队列中。这不是什么大问题,除非您发布的消息延迟了很长时间。

你可以把IncomingHandler设为静态的,并给你的服务添加一个WeakReference:

static class IncomingHandler extends Handler {
private final WeakReference<UDPListenerService> mService;


IncomingHandler(UDPListenerService service) {
mService = new WeakReference<UDPListenerService>(service);
}
@Override
public void handleMessage(Message msg)
{
UDPListenerService service = mService.get();
if (service != null) {
service.handleMessage(msg);
}
}
}

参见Romain Guy的帖子以获得进一步的参考

正如其他人所提到的,Lint警告是因为潜在的内存泄漏。你可以通过在构造Handler时传递Handler.Callback来避免Lint警告(即你不继承Handler,并且没有Handler非静态内部类):

Handler mIncomingHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// todo
return true;
}
});

据我所知,这并不能避免潜在的内存泄漏。Message对象持有对mIncomingHandler对象的引用,mIncomingHandler对象持有对Service对象的引用。只要Looper消息队列中有消息,Service就不会被GC。但是,除非消息队列中有长时间延迟的消息,否则这不会是一个严重的问题。

这种方法对我来说很有效,通过将处理消息的位置保留在它自己的内部类中,从而保持代码干净。

您希望使用的处理程序

Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());

内部类

class IncomingHandlerCallback implements Handler.Callback{


@Override
public boolean handleMessage(Message message) {


// Handle message code


return true;
}
}

我不确定,但你可以尝试初始化处理程序为空在onDestroy()

下面是一个使用弱引用和静态处理程序类来解决问题的通用示例(在Lint文档中推荐):

public class MyClass{


//static inner class doesn't hold an implicit reference to the outer class
private static class MyHandler extends Handler {
//Using a weak reference means you won't prevent garbage collection
private final WeakReference<MyClass> myClassWeakReference;


public MyHandler(MyClass myClassInstance) {
myClassWeakReference = new WeakReference<MyClass>(myClassInstance);
}


@Override
public void handleMessage(Message msg) {
MyClass myClass = myClassWeakReference.get();
if (myClass != null) {
...do work here...
}
}
}


/**
* An example getter to provide it to some external class
* or just use 'new MyHandler(this)' if you are using it internally.
* If you only use it internally you might even want it as final member:
* private final MyHandler mHandler = new MyHandler(this);
*/
public Handler getHandler() {
return new MyHandler(this);
}
}

借助@Sogger的回答,我创建了一个通用的Handler:

public class MainThreadHandler<T extends MessageHandler> extends Handler {


private final WeakReference<T> mInstance;


public MainThreadHandler(T clazz) {
// Remove the following line to use the current thread.
super(Looper.getMainLooper());
mInstance = new WeakReference<>(clazz);
}


@Override
public void handleMessage(Message msg) {
T clazz = mInstance.get();
if (clazz != null) {
clazz.handleMessage(msg);
}
}
}

的接口:

public interface MessageHandler {


void handleMessage(Message msg);


}

我是这样使用的。但我不能百分百确定这是否安全。也许有人可以对此发表评论:

public class MyClass implements MessageHandler {


private static final int DO_IT_MSG = 123;


private MainThreadHandler<MyClass> mHandler = new MainThreadHandler<>(this);


private void start() {
// Do it in 5 seconds.
mHandler.sendEmptyMessageDelayed(DO_IT_MSG, 5 * 1000);
}


@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case DO_IT_MSG:
doIt();
break;
}
}


...


}
< p >我困惑。 我找到的例子完全避免了static属性,并使用UI线程:

    public class example extends Activity {
final int HANDLE_FIX_SCREEN = 1000;
public Handler DBthreadHandler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(Message msg) {
int imsg;
imsg = msg.what;
if (imsg == HANDLE_FIX_SCREEN) {
doSomething();
}
}
};
}

我喜欢这个解决方案的一点是,混合使用类变量和方法变量是没有问题的。

如果你正在使用Kotlin,在声明嵌套类时只需删除inner关键字。

Kotlin中的嵌套类是静态的默认情况下,用inner声明它们使它们不是静态的。

将嵌套的Handler子类声明更改为

class myService : Service() {


inner class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}


}

class myService : Service() {


class IncomingHandler : Handler(Looper.getMainLooper()) {
/////
}


}