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

时间:2015-03-07 13:57:05

标签: java android multithreading android-service

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

我已尝试将我的工作人员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的情况下从线程发送消息?

2 个答案:

答案 0 :(得分:2)

看起来我终于把它钉了!

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

  1. 在您的服务中对Handler类进行子类化(称之为LocalHandler)。你必须使它静止。覆盖handleMessage方法,它将从线程接收消息。

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

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

  4. 以下是完整的示例:

    服务类

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

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

答案 1 :(得分:0)

实际上,Slava,你的回答并不奏效。让我解释一下原因。

为什么Android在Thread存在时会有HandlerThread?

这是因为正如documentation所说,HandleThread是

  

用于启动具有looper的新线程的方便类。弯针   然后可以用于创建处理程序类。请注意start()必须   仍被称为。

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

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

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

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

  

处理程序()

     

默认构造函数将此处理程序与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