![](/img/trans.png)
[英]How to get notification from worker thread to main thread when worker thread done with its work in android
[英]Android: how to communicate from worker thread to a service
我創建了一個服務類和一個工作器類,它們在單獨的線程中執行。 我想在它們之間建立通信,以便工作人員可以將一些狀態發送回服務。
我試圖將我的工作Thread
轉換為HandlerThread
並在服務端設置Handler
,但是后來我不知道如何實際從工作Thread
發送消息。 看來我無法理解這個概念。
這是我的課程(沒有通信邏輯):
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
情況下從線程發送消息?
看來我終於釘牢了!
為了將數據從線程傳遞回服務,您將需要執行以下操作:
在服務內部對Handler
類進行子類化(例如,將其LocalHandler
)。 您將不得不使其靜態。 重寫handleMessage
方法,它將接收來自線程的消息。
將Handler
參數添加到Thread
構造函數。 在服務中實例化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是一個
方便的類,用於啟動具有循環程序的新線程。 然后可以使用循環程序創建處理程序類。 請注意,仍必須調用start()。
Looper如何用於創建處理程序?
應該在Handler的構造函數中傳遞一個Looper,以告知Handler它正在使用哪個Looper。
因此,每個HandlerThread都有一個Looper,並且可以有很多Handler處理Looper循環通過的消息。
當使用默認構造函數在Service類中創建新的Handler時,該Handler將與當前Looper關聯,如其文檔中所述。
處理程序()
默認構造函數將此處理程序與當前線程的Looper關聯。 如果此線程沒有循環程序,則此處理程序將無法接收消息,因此將引發異常。
您可以通過打印此來確認問題仍然存在
Thread.currentThread().getId()
在適當的位置-在服務的onCreate()
內,處理程序的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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.