这个Handler类应该是静态的或者可能发生泄漏:IncomingHandler

我正在开发一个带有服务的Android 2.3.3应用程序。 我有这个服务与主要活动沟通:

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()); ,我得到以下警告:

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

这是什么意思?

如果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的这篇文章以作进一步参考

正如其他人所说,林特警告是由于潜在的内存泄漏。 你可以通过在构造Handler时传递Handler.Callback来避免Lint警告(也就是说,你不需要Handler.Callback Handler ,也没有Handler非静态的内部类):

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

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

以下是使用弱引用和静态处理程序类来解决问题的一般示例(如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); } } 

这种方式对我来说很好,保持代码的清洁,保持在你自己的内部类中处理消息的地方。

您希望使用的处理程序

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

内部类

 class IncomingHandlerCallback implements Handler.Callback{ @Override public boolean handleMessage(Message message) { // Handle message code return true; } 

我不知道,但你可以尝试intialising处理程序null onDestroy()

在@ 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); } 

我正在使用它如下。 但是,我不是100%确定这是否是防漏的。 也许有人可以对此发表评论:

 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; } } ... }