本文翻译自:This Handler class should be static or leaks might occur: IncomingHandler
I'm developing an Android 2.3.3 application with a service. 我正在开发带有服务的Android 2.3.3应用程序。 I have this inside that service to communicate with Main activity: 我在服务内部拥有此功能,可与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());
[ ... ]
}
And here, final Messenger mMessenger = new Messenger(new IncomingHandler());
在这里, final Messenger mMessenger = new Messenger(new IncomingHandler());
, I get the following Lint warning: ,我收到以下Lint警告:
This Handler class should be static or leaks might occur: IncomingHandler
What does it mean? 这是什么意思?
#1楼
参考:https://stackoom.com/question/LRJ5/该Handler类应该是静态的-否则可能会发生泄漏-IncomingHandler
#2楼
If IncomingHandler
class is not static, it will have a reference to your Service
object. 如果IncomingHandler
类不是静态的,则它将引用您的Service
对象。
Handler
objects for the same thread all share a common Looper object, which they post messages to and read from. 同一线程的Handler
对象都共享一个公共的Looper对象,它们将消息发布到其中并从中读取。
As messages contain target Handler
, as long as there are messages with target handler in the message queue, the handler cannot be garbage collected. 由于消息包含目标Handler
,因此只要消息队列中存在带有目标处理程序的消息,就无法对处理程序进行垃圾回收。 If handler is not static, your Service
or Activity
cannot be garbage collected, even after being destroyed. 如果处理程序不是静态的,则即使销毁了Service
或Activity
也无法对其进行垃圾回收。
This may lead to memory leaks, for some time at least - as long as the messages stay int the queue. 只要消息保留在队列中,这至少可能会导致内存泄漏至少一段时间。 This is not much of an issue unless you post long delayed messages. 除非您发布长时间延迟的邮件,否则这并不是什么大问题。
You can make IncomingHandler
static and have a WeakReference
to your service: 您可以将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);
}
}
}
See this post by Romain Guy for further reference 请参阅Romain Guy的这篇文章,以获取更多参考
#3楼
As others have mentioned the Lint warning is because of the potential memory leak. 正如其他人提到的那样,Lint警告是由于潜在的内存泄漏。 You can avoid the Lint warning by passing a Handler.Callback
when constructing Handler
(ie you don't subclass Handler
and there is no Handler
non-static inner class): 您可以通过在构造Handler
时传递Handler.Callback
来避免Lint警告(即,您不Handler.Callback
Handler
且没有Handler
非静态内部类):
Handler mIncomingHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// todo
return true;
}
});
As I understand it, this will not avoid the potential memory leak. 据我了解,这将无法避免潜在的内存泄漏。 Message
objects hold a reference to the mIncomingHandler
object which holds a reference the Handler.Callback
object which holds a reference to the Service
object. Message
对象包含对mIncomingHandler
对象的引用,该对象包含对Handler.Callback
对象的引用,该对象包含对Service
对象的引用。 As long as there are messages in the Looper
message queue, the Service
will not be GC. 只要Looper
消息队列中有消息,该Service
就不会是GC。 However, it won't be a serious issue unless you have long delay messages in the message queue. 但是,除非您在消息队列中有很长的延迟消息,否则这将不是一个严重的问题。
#4楼
This way worked well for me, keeps code clean by keeping where you handle the message in its own inner class. 这种方式对我来说效果很好,通过在内部类中处理消息的位置来保持代码干净。
The handler you wish to use 您要使用的处理程序
Handler mIncomingHandler = new Handler(new IncomingHandlerCallback());
The inner class 内在阶级
class IncomingHandlerCallback implements Handler.Callback{
@Override
public boolean handleMessage(Message message) {
// Handle message code
return true;
}
}
#5楼
我不确定,但您可以尝试在onDestroy()中将处理程序初始化为null
#6楼
Here is a generic example of using a weak reference and static handler class to resolve the problem (as recommended in the Lint documentation): 这是使用弱引用和静态处理程序类解决问题的通用示例(如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);
}
}