在主线程中从另一个线程运行代码

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

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

有没有一种方法来获得主线程的Handler,并从我的其他线程发布Message/Runnable ?

344786 次浏览

我能想到的一个方法是:

1)让UI绑定到服务 2)通过Binder公开一个类似下面的方法,它注册你的Handler:

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

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

mBinder.registerHandler(new Handler());

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

mHandler.post(runnable);

注意:这个答案已经得到了如此多的关注,我需要更新它。自从原来的答案被发布后,@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);
正如下面一位评论者正确指出的那样,这不是服务的通用解决方案,只适用于从您的活动中启动的线程(服务可以是这样的线程,但不是所有线程都是)。 关于服务-活动通信这个复杂的话题,请阅读官方文档的整个服务部分——它很复杂,所以了解基本知识是有好处的: http://developer.android.com/guide/components/services.html#Notifications < / p >

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

如果我理解正确的话,你需要一些代码在应用程序的GUI线程中执行(不能考虑任何其他叫做“;main";线程)。 为此,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%28java.lang.Runnable%29

希望这就是你要找的。

如果你在线程中运行代码,例如延迟一些动作,那么你需要从上下文调用runOnUiThread。例如,如果你的代码在MainActivity类中,那么使用这个:

MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
myAction();
}
});

如果你的方法可以从main (UI线程)或其他线程调用,你需要像这样检查:

public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {


}

还有另一种简单的方法,如果你没有访问Context的权限。

1).从主循环程序创建一个处理程序:

Handler uiHandler = new Handler(Looper.getMainLooper());

2).实现一个可运行的接口:

Runnable runnable = new Runnable() { // your code here }

3).发布你的Runnable到uiHandler:

uiHandler.post(runnable);

这就是全部;-)享受线程的乐趣,但不要忘记同步它们。

在Android中,HandlerThread是比普通java线程更好的选择。

  1. 创建一个HandlerThread并启动它
  2. 用HandlerThread:requestHandler中的电影创建一个处理程序
  3. postrequestHandler上的Runnable任务

HandlerThread与UI线程通信

  1. 为主线程:responseHandler创建带有LooperHandler,并重写handleMessage方法
  2. 在其他线程的Runnable任务中(在本例中为HandlerThread),在responseHandler上调用sendMessage
  3. sendMessage结果调用responseHandler中的handleMessage
  4. Message中获取属性并处理它,更新UI

例子:用从web服务接收的数据更新TextView。由于web服务应该在非ui线程上调用,因此为网络操作创建了HandlerThread。一旦你从web服务获得内容,发送消息到主线程(UI线程)处理程序,Handler将处理消息并更新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- their -in-your-android-apps

< a href = " https://blog.nikitaog。我/ 2014/10/11 / android-looper-handler-handlerthread-i / noreferrer“rel = > android-looper-handler-handlerthread-i < / >

遵循这个方法。使用这种方法,您可以简单地从后台线程更新UI。runOnUiThread工作在主(UI)线程上。我认为这个代码片段不那么复杂,而且简单,特别是对初学者来说。

AsyncTask.execute(new Runnable() {
@Override
public void run() {


//code you want to run on the background
someCode();


//the code you want to run on main thread
MainActivity.this.runOnUiThread(new Runnable() {


public void run() {


/*the code you want to run after the background operation otherwise they will executed earlier and give you an error*/
executeAfterOperation();


}
});
}
});

对于服务

在oncreate中创建一个处理程序

 handler = new Handler();

然后像这样使用它

 private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}

压缩代码块如下所示:

   new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// things to do on the main thread
}
});

这并不涉及传递活动引用或应用程序引用。

芬兰湾的科特林相当于:

    Handler(Looper.getMainLooper()).post(Runnable {
// things to do on the main thread
})

我知道这是一个老问题,但我遇到了一个在Kotlin和Java中都使用的主线程一行程序。对于服务来说,这可能不是最好的解决方案,但对于调用将改变片段内UI的东西来说,这是非常简单和明显的。

Java (8):

 getActivity().runOnUiThread(()->{
//your main thread code
});

芬兰湾的科特林:

this.runOnUiThread {
//your main thread code
}
public void mainWork() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//Add Your Code Here
}
});
}

这也可以在服务类中毫无问题地工作。

对于Kotlin,你可以使用像corountines:

更新

doAsync {
...
}

弃用

async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}

最简单的方法,特别是如果你没有context,如果你在使用RxAndroid,你可以这样做:

AndroidSchedulers.mainThread().scheduleDirect {
runCodeHere()
}

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

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

芬兰湾的科特林版本

你正在进行一项活动时,则使用

runOnUiThread {
//code that runs in main
}

你有活动环境时,mContext则使用

mContext.runOnUiThread {
//code that runs in main
}

当你在某个地方没有上下文可用,然后使用

Handler(Looper.getMainLooper()).post {
//code that runs in main
}

使用Kotlin,在任何函数中都是这样的:

runOnUiThread {
// Do work..
}

所以最方便的方法是:

import android.os.AsyncTask
import android.os.Handler
import android.os.Looper


object Dispatch {
fun asyncOnBackground(call: ()->Unit) {
AsyncTask.execute {
call()
}
}


fun asyncOnMain(call: ()->Unit) {
Handler(Looper.getMainLooper()).post {
call()
}
}
}

后:

Dispatch.asyncOnBackground {
val value = ...// super processing
Dispatch.asyncOnMain { completion(value)}
}
ContextCompat.getMainExecutor(context).execute {
// do something
}