我遇到一种情况,线程需要在主线程的消息队列上发布某些任务,例如
Runnable
。一种获取主线程的Handler
并从其他线程发布Message
/ Runnable
的方法?#1 楼
注意:此答案已引起广泛关注,我需要对其进行更新。自从原始答案发布以来,@ dzeikei的评论几乎和原始答案一样受到关注。因此,这里有两种可能的解决方案:1。如果您的后台线程引用了
Context
对象:请确保您的后台工作线程可以访问Context对象(可以是Application上下文或Service上下文)。然后只需在后台工作线程中执行此操作:
// 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);
评论
谢谢David,它为我解决了问题,如果您可以帮助我,还可以做一件事,如果我扩展Handler和impl handleMessage()会阻止主线程处理其消息吗?这只是出于好奇。
–艾哈迈德(Ahmed)
2012年6月20日19:03
不能。如果您将Handler子类化(或使用Handler.Callback接口),则将仅为使用处理程序发布的消息调用handleMessage()方法。主线程使用其他处理程序来发布/处理消息,因此没有冲突。
– David Wasser
2012年6月20日19:22
我相信,如果您使用Handler mainHandler = new Handler(Looper.getMainLooper()),您甚至不需要上下文。
– dzeikei
13年5月5日,下午3:57
小点;您的代码不在当前的位置。它应该是新的Runnable(){@ Override public void run(){....}};
–Richard Tingle
2014年7月31日上午10:19
@SagarDevanga这不是提出其他问题的正确位置。请发布一个新问题,而不是对无关答案的评论。这样您将获得更好,更快的响应。
– David Wasser
2015年1月21日,9:10
#2 楼
正如下面的评论者正确指出的那样,这不是服务的通用解决方案,仅适用于从您的活动启动的线程(服务可以是这样的线程,但并非所有都是这样的)。关于服务的复杂主题活动通信,请阅读正式文档的整个服务部分-这很复杂,因此需要了解以下基本知识:
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%28java.lang。 Runnable%29
希望这是您想要的。
评论
OP表示他正在Service中运行线程。您不能在服务中使用runOnUiThread()。这个答案有误导性,没有解决所问的问题。
– David Wasser
13年11月27日在9:25
#3 楼
Kotlin版本进行活动时,请使用
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(){...}
– Wex
20-05-14在9:20
在Mac上使用Android Studio 4.1.1对我来说非常有效。
–金色拇指
20 Dec 12'在0:30
#4 楼
如果您无权访问Context,则还有另一种简单的方法。1)。在主循环程序中创建处理程序:
Handler uiHandler = new Handler(Looper.getMainLooper());
2)。实现可运行的接口:
Runnable runnable = new Runnable() { // your code here }
3)。将您的Runnable发布到uiHandler:
uiHandler.post(runnable);
就这些;-)玩弄线程,但不要忘记同步它们。
#5 楼
如果您在线程中运行代码,例如确实延迟了某些操作,那么您需要从上下文中调用runOnUiThread
。例如,如果您的代码在MainActivity
类中,则使用此代码:MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
myAction();
}
});
如果可以从主(UI线程)或其他线程中调用您的方法,则需要像这样的支票:
public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {
}
评论
OP表示他正在Service中运行线程。您不能在服务中使用runOnUiThread()。
– David Wasser
13年11月27日在9:27
@DavidWasser在任何地方都有记录吗?方法文档未提及任何内容。 developer.android.com/reference/android/app/…
–格雷格·布朗(Greg Brown)
15年8月26日在12:49
@GregBrown正如到Activity文档的链接所指出的那样,runOnUiThread()是Activity的一种方法。它不是服务方法,因此您不能使用它。还有什么比这更清楚的了?
– David Wasser
16年8月4日在16:41
@DavidWasser足够公平。我什至不记得我为什么现在问这个问题(该问题已在大约一年前发布)。
–格雷格·布朗(Greg Brown)
16年8月7日在20:42
#6 楼
压缩代码块如下: 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
})
#7 楼
最简单的方法,尤其是在没有上下文的情况下,如果您使用的是RxAndroid,则可以执行以下操作:AndroidSchedulers.mainThread().scheduleDirect {
runCodeHere()
}
#8 楼
使用处理程序的更精确的Kotlin代码:Handler(Looper.getMainLooper()).post {
// your codes here run on main Thread
}
#9 楼
我可以想到的一种方法是:1)让UI绑定到服务。
2)通过注册您的
Binder
的Handler
公开一种类似于下面的方法:public void registerHandler(Handler handler) {
mHandler = handler;
}
3)在UI线程中,绑定到服务后调用上述方法:
mBinder.registerHandler(new Handler());
4 )使用服务线程中的处理程序来发布您的任务:
mHandler.post(runnable);
#10 楼
HandlerThread
是Android中普通Java线程的更好选择。创建HandlerThread并启动它
从HandlerThread使用Looper创建处理程序:
requestHandler
post
上的Runnable
任务与来自
requestHandler
的UI线程通信为主线程创建带有
HandlerThread
的Handler
:Looper
并重写responseHandler
方法在其他线程的
handleMessage
任务中(在本例中为Runnable
),在HandlerThread
上调用sendMessage
此
responseHandler
结果调用sendMessage
中的handleMessage
。从
responseHandler
并对其进行处理,更新UI 示例:使用从Web服务接收的数据更新
Message
。由于应该在非UI线程上调用Web服务,因此请为网络操作创建TextView
。从Web服务获取内容后,将消息发送到主线程(UI线程)处理程序,然后HandlerThread
将处理该消息并更新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);
有用的文章:
处理线程以及为什么要在您的Android应用程序中使用它们
android-looper-handler-handlerthread-i
#11 楼
我知道这是一个老问题,但是我遇到了在Kotlin和Java中都使用过的一个主线程单层。这可能不是服务的最佳解决方案,但是对于调用将改变片段内部的UI的东西而言,这非常简单和明显。Java(8):
getActivity().runOnUiThread(()->{
//your main thread code
});
科特琳:
this.runOnUiThread {
//your main thread code
}
#12 楼
因此,最方便的方法是执行以下操作: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)}
}
#13 楼
请遵循此方法。使用这种方法,您可以简单地从后台线程更新UI。 runOnUiThread在main(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);
}
#14 楼
对于Kotlin,可以使用Anko corountines:更新
doAsync {
...
}
已弃用的
async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}
#15 楼
public void mainWork() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//Add Your Code Here
}
});
}
这也可以在服务类中正常工作。
评论
尽管此代码可以回答问题,但您仍然可以考虑添加一些解释性的句子,因为这可以为其他用户增加答案的价值!
– MBT
18年8月23日在12:42
#16 楼
使用Kotlin,在任何函数中都就像这样:runOnUiThread {
// Do work..
}
评论
仅当您处于Activity上时。
– Farsheel
20年1月6日在6:04
评论
您还可以使用自定义广播接收器。...在此处尝试我的回答,[内部广播接收器] [1] [1]:stackoverflow.com/a/22541324/1881527有很多方法。除了David的回答和dzeikei在他的回答中的评论之外,(3)您可以使用广播接收器,或者(4)在用于启动服务的Intent的额外内容中传递处理程序,然后使用getIntent()在服务内部检索主线程的处理程序。 ).getExtras()。
@ sazzad-hissain-khan,为什么要用kotlin标记在2012年以来用Java的大部分答案标记这个问题?