我正在开发一个带有服务的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类应该是静态的,否则可能会发生泄漏

这是什么意思?


当前回答

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

其他回答

如果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);
         }
    }
}

请参阅罗曼盖伊的这篇文章以获得进一步的参考

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

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

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

class myService : Service() {

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

}

to

class myService : Service() {

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

}

我不确定,但你可以尝试初始化处理程序为空在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);

}

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

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

    ...

}

我困惑。 我找到的例子完全避免了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();
                }
            }
        };
    }

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