簡體   English   中英

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情況下從線程發送消息?

看來我終於釘牢了!

為了將數據從線程傳遞回服務,您將需要執行以下操作:

  1. 在服務內部對Handler類進行子類化(例如,將其LocalHandler )。 您將不得不使其靜態。 重寫handleMessage方法,它將接收來自線程的消息。

  2. Handler參數添加到Thread構造函數。 在服務中實例化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是一個

方便的類,用於啟動具有循環程序的新線程。 然后可以使用循環程序創建處理程序類。 請注意,仍必須調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM