我正在开发一个带有服务的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警告:
这个Handler类应该是静态的,否则可能会发生泄漏
这是什么意思?
借助@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;
}
}
...
}
如果IncomingHandler类不是静态的,它将有一个对Service对象的引用。
同一个线程的处理程序对象都共享一个共同的Looper对象,它们向该对象发布消息并从中读取消息。
由于消息包含目标处理程序,只要消息队列中有带有目标处理程序的消息,处理程序就不能被垃圾收集。如果处理程序不是静态的,你的服务或活动不能被垃圾收集,即使在被销毁之后。
这可能会导致内存泄漏,至少在一段时间内——只要消息处于队列中。这不是什么大问题,除非您发布的消息延迟了很长时间。
你可以让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);
}
}
}
请参阅罗曼盖伊的这篇文章以获得进一步的参考