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
情况下从线程发送消息?
看起来我终于把它钉了!
为了将数据从线程传递回服务,您需要执行以下操作:
-
在服务
LocalHandler
类化一个Handler
类(称之为例如LocalHandler
)。 你必须使它静止。 覆盖handleMessage
方法,它将从线程接收消息。 -
向
Thread
构造函数添加一个Handler
参数。 在服务中实例化LocalHandler
类并通过构造函数将其注入到线程中。 -
保存对线程内部
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
- 如何在android上调用另一个页面/从空闲时间弹出一条消息?
- 如何在单击不同的按钮时在片段中的Textview中设置不同的字符串?
- 在android中使用asynctask为RecyclerView下载图像
- 使用Java android中的Math.round方法舍入到小数点后6位
- 反映清除Android应用缓存的方法
- 从android中的edittext框获取XXX-XXX-XXXX格式的电话号码
- Skobbler。 当我设置自己的注释时,onAnnotationSelected未被调用
- 如何通过XML和Java代码使用OnClickListener接口?
- 绘图文本(TimeStamp)覆盖从独立摄像头捕获的图像