Android:如何从工作线程到服务进行通信

我已经创建了一个服务类和一个在一个单独的线程中执行的worker类。 我想在它们之间建立通信,因此工作人员可以将某些状态发送回服务。

我试图将我的工作Thread转换为HandlerThread并在服务端设置一个Handler ,但后来我不知道如何实际从工作人员发送消息。 看起来我无法理解这个概念。

这是我的课程(没有沟通逻辑):

服务类

 package com.example.app; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.util.Log; public class ConnectionService extends Service { protected ConnectionWorker thread; @Override public void onCreate() { super.onCreate(); // Creating a connection worker thread instance. // Not starting it yet. this.thread = new ConnectionWorker(); Log.d(this.getClass().getName(), "Service created"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(this.getClass().getName(), "Service started"); // Checking if worker thread is already running. if (!this.thread.isAlive()) { Log.d(this.getClass().getName(), "Starting working thread"); // Starting the worker thread. this.thread.start(); } return Service.START_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { Log.d(this.getClass().getName(), "Stopping thread"); // Stopping the thread. this.thread.interrupt(); Log.d(this.getClass().getName(), "Stopping service"); super.onDestroy(); Log.d(this.getClass().getName(), "Service destroyed"); } } 

工人阶级

 package com.example.app; import android.os.SystemClock; import android.util.Log; public class ConnectionWorker extends Thread { public ConnectionWorker() { super(ConnectionWorker.class.getName()); } @Override public void run() { super.run(); Log.d(this.getClass().getName(), "Thread started"); // Doing the work indefinitely. while (true) { if (this.isInterrupted()) { // Terminating this method when thread is interrupted. return; } // @todo: send a message to the service Log.d(this.getClass().getName(), "Doing some work for 3 seconds..."); SystemClock.sleep(3 * 1000); } } } 

如何实现HandlerThread ,从工作线程发送消息并在我的服务中接收它们?

我将非常感谢代码示例。

更新

实际上,看起来我不能在我的线程中使用Looper因为它会阻止线程执行而我不希望这样。 是否可以在不使用Looper情况下从线程发送消息?

看起来我终于把它钉了!

为了将数据从线程传递回服务,您需要执行以下操作:

  1. 在服务LocalHandler类化一个Handler类(称之为例如LocalHandler )。 你必须使它静止。 覆盖handleMessage方法,它将从线程接收消息。

  2. Thread构造函数添加一个Handler参数。 在服务中实例化LocalHandler类并通过构造函数将其注入到线程中。

  3. 保存对线程内部Handler引用,并在适当时使用它来发送消息。

这是完整的例子:

服务类

 package com.example.app; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; public class ConnectionService extends Service { protected ConnectionWorker thread; static class LocalHandler extends Handler { @Override public void handleMessage(Message msg) { Log.d(this.getClass().getName(), "Message received: " + (String) msg.obj); } } protected Handler handler; @Override public void onCreate() { super.onCreate(); // Instantiating overloaded handler. this.handler = new LocalHandler(); // Creating a connection worker thread instance. // Not starting it yet. // Injecting our handler. this.thread = new ConnectionWorker(this.handler); Log.d(this.getClass().getName(), "Service created"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(this.getClass().getName(), "Trying to start the service"); // Checking if worker thread is already running. if (!this.thread.isAlive()) { Log.d(this.getClass().getName(), "Starting working thread"); // Starting the worker thread. this.thread.start(); Log.d(this.getClass().getName(), "Service started"); } return Service.START_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { Log.d(this.getClass().getName(), "Stopping thread"); // Stopping the thread. this.thread.interrupt(); Log.d(this.getClass().getName(), "Stopping service"); super.onDestroy(); Log.d(this.getClass().getName(), "Service destroyed"); } } 

工人类(线程)

 package com.example.app; import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.Log; public class ConnectionWorker extends Thread { // Reference to service's handler. protected Handler handler; public ConnectionWorker(Handler handler) { super(ConnectionWorker.class.getName()); // Saving injected reference. this.handler = handler; } @Override public void run() { super.run(); Log.d(this.getClass().getName(), "Thread started"); // Doing the work indefinitely. while (true) { if (this.isInterrupted()) { // Terminating this method when thread is interrupted. return; } Log.d(this.getClass().getName(), "Doing some work for 3 seconds..."); // Sending a message back to the service via handler. Message message = this.handler.obtainMessage(); message.obj = "Waiting for 3 seconds"; this.handler.sendMessage(message); SystemClock.sleep(3 * 1000); } } } 

我希望这是一个有效的实现。 如果您现在有更好的方法 – 请告诉我。

Slava,实际上,你的答案不起作用。 让我解释一下原因。

当Thread已经存在时,为什么Android有HandlerThread?

这是因为正如文档所说,HandleThread是一个

用于启动具有looper的新线程的方便类。 然后可以使用looper来创建处理程序类。 请注意,仍然必须调用start()。

Looper如何用于创建处理程序?

应该在Handler的构造函数中传递一个Looper来告诉Handler它正在使用哪个Looper。

因此每个HandlerThread都有一个Looper,并且可以有许多处理程序处理Looper循环的消息。


使用默认构造函数在Service类中创建新的Handler时,Handler会与当前的Looper关联,如文档中所述。

处理程序()

默认构造函数将此处理程序与当前线程的Looper相关联。 如果此线程没有looper,则此处理程序将无法接收消息,因此会引发exception。

您可以通过打印来确认问题仍然存在

 Thread.currentThread().getId() 

在适当的位置 – 在Service的onCreate()内,在Handler的handleMessage()内和ConnectionWorker的run()内。 那怎么解决你的问题呢?

您甚至可以在服务中创建HandlerThread,并且当Looper准备就绪时,使用该Looper创建Handler。

 new HandlerThread("ConnectionWorker") { @Override protected void onLooperPrepared() { new Handler(getLooper()).post(new Runnable() { @Override public void run() { // do your stuff getLooper().quitSafely(); } }); } }.start(); 

希望答案还不算太晚:P