在一个android服务,我已经创建线程(s)做一些后台任务。

我有一个线程需要在主线程的消息队列上发布某个任务的情况,例如一个可运行的。

有没有办法得到主线程的处理程序和post Message/Runnable到它从我的其他线程?


当前回答

我能想到的一个方法是:

1)让UI绑定到服务。 2)暴露一个方法,就像下面一个由Binder注册你的处理程序:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3)在UI线程中,绑定到服务后调用上述方法:

mBinder.registerHandler(new Handler());

4)使用服务线程中的处理程序来发布你的任务:

mHandler.post(runnable);

其他回答

HandlerThread是更好的选择,以正常的java线程在Android。

创建一个HandlerThread并启动它 从HandlerThread:requestHandler中创建一个Looper Handler 在requestHandler上发布一个可运行任务

从HandlerThread与UI线程通信

为主线程创建一个Looper Handler: responseHandler并重写handleMessage方法 在其他线程(在本例中为HandlerThread)的可运行任务中,调用responseHandler上的sendMessage responseHandler中handleMessage的sendMessage结果调用。 从Message中获取属性并处理它,更新UI

示例:用从web服务接收到的数据更新TextView。由于web服务应该在非ui线程上调用,因此为网络操作创建了HandlerThread。一旦你从web服务获得内容,发送消息到你的主线程(UI线程)处理程序,该处理程序将处理消息并更新UI。

示例代码:

HandlerThread handlerThread = new HandlerThread("NetworkOperation");
handlerThread.start();
Handler requestHandler = new Handler(handlerThread.getLooper());

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        txtView.setText((String) msg.obj);
    }
};

Runnable myRunnable = new Runnable() {
    @Override
    public void run() {
        try {
            Log.d("Runnable", "Before IO call");
            URL page = new URL("http://www.your_web_site.com/fetchData.jsp");
            StringBuffer text = new StringBuffer();
            HttpURLConnection conn = (HttpURLConnection) page.openConnection();
            conn.connect();
            InputStreamReader in = new InputStreamReader((InputStream) conn.getContent());
            BufferedReader buff = new BufferedReader(in);
            String line;
            while ((line = buff.readLine()) != null) {
                text.append(line + "\n");
            }
            Log.d("Runnable", "After IO call:"+ text.toString());
            Message msg = new Message();
            msg.obj = text.toString();
            responseHandler.sendMessage(msg);


        } catch (Exception err) {
            err.printStackTrace();
        }
    }
};
requestHandler.post(myRunnable);

有用的文章:

handlerthreads-and-why-you-should-be-using-them-in-your-android-apps

android-looper-handler-handlerthread-i

正如下面一位评论者正确指出的那样,这不是服务的通用解决方案,只适用于从您的活动中启动的线程(服务可以是这样的线程,但不是所有线程都是)。 关于服务-活动通信这个复杂的话题,请阅读官方文档的整个服务部分——它很复杂,所以了解基本知识是有好处的: http://developer.android.com/guide/components/services.html#Notifications

下面的方法可能适用于最简单的情况:

如果我理解正确的话,你需要在应用程序的GUI线程中执行一些代码(不能考虑任何其他称为“主线程”的线程)。 为此,Activity上有一个方法:

someActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
           //Your code to run in GUI thread here
        }//public void run() {
});

道格:http://developer.android.com/reference/android/app/Activity.html runOnUiThread % 28 java.lang.runnable % 29

希望这就是你要找的。

使用处理器的更精确的Kotlin代码:

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }

注意:这个答案已经得到了如此多的关注,我需要更新它。自从原来的答案被发布后,@dzeikei的评论获得了几乎和原来答案一样多的关注。这里有两种可能的解决方案:

1. 如果你的后台线程有一个Context对象的引用:

确保您的后台工作线程可以访问Context对象(可以是应用程序上下文或服务上下文)。然后在后台工作线程中这样做:

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(context.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

2. 如果你的后台线程没有(或不需要)Context对象

(@dzeikei建议):

// Get a handler that can be used to post to the main thread
Handler mainHandler = new Handler(Looper.getMainLooper());

Runnable myRunnable = new Runnable() {
    @Override 
    public void run() {....} // This is your code
};
mainHandler.post(myRunnable);

我能想到的一个方法是:

1)让UI绑定到服务。 2)暴露一个方法,就像下面一个由Binder注册你的处理程序:

public void registerHandler(Handler handler) {
    mHandler = handler;
}

3)在UI线程中,绑定到服务后调用上述方法:

mBinder.registerHandler(new Handler());

4)使用服务线程中的处理程序来发布你的任务:

mHandler.post(runnable);