[英]Running code in main thread from another thread
In an android service I have created thread(s) for doing some background task.在 android 服务中,我创建了线程来执行一些后台任务。
I have a situation where a thread needs to post certain task on main thread's message queue, for example a Runnable
.我有一个线程需要在主线程的消息队列上发布某些任务的情况,例如
Runnable
。
Is there a way to get Handler
of the main thread and post Message
/ Runnable
to it from my other thread?有没有办法获取主线程的
Handler
并从我的另一个线程向它发布Message
/ Runnable
?
NOTE: This answer has gotten so much attention, that I need to update it.注意:这个答案受到了如此多的关注,我需要更新它。 Since the original answer was posted, the comment from @dzeikei has gotten almost as much attention as the original answer.
自从发布原始答案以来,@dzeikei 的评论几乎与原始答案一样受到关注。 So here are 2 possible solutions:
所以这里有两种可能的解决方案:
1. If your background thread has a reference to a Context
object: 1. 如果你的后台线程有一个
Context
对象的引用:
Make sure that your background worker threads have access to a Context object (can be the Application context or the Service context).确保您的后台工作线程可以访问 Context 对象(可以是 Application 上下文或 Service 上下文)。 Then just do this in the background worker thread:
然后在后台工作线程中执行此操作:
// 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. If your background thread does not have (or need) a Context
object 2. 如果你的后台线程没有(或需要)一个
Context
对象
(suggested by @dzeikei): (由@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);
As a commenter below pointed correctly, this is not a general solution for services, only for threads launched from your activity (a service can be such a thread, but not all of those are).正如下面的评论者正确指出的那样,这不是服务的通用解决方案,仅适用于从您的活动启动的线程(服务可以是这样的线程,但并非所有这些都是)。 On the complicated topic of service-activity communication please read the whole Services section of the official doc - it is complex, so it would pay to understand the basics: http://developer.android.com/guide/components/services.html#Notifications
关于服务-活动通信的复杂主题,请阅读官方文档的整个服务部分 - 它很复杂,因此了解基础知识是值得的: http : //developer.android.com/guide/components/services.html #通知
The method below may work in the simplest cases:下面的方法可能适用于最简单的情况:
If I understand you correctly you need some code to be executed in the GUI thread of the application (cannot think about anything else called "main" thread).如果我理解正确,您需要在应用程序的 GUI 线程中执行一些代码(无法考虑任何其他称为“主”线程的内容)。 For this there is a method on
Activity
:为此,
Activity
有一个方法:
someActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
//Your code to run in GUI thread here
}//public void run() {
});
Doc: http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29文档: http : //developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29
Hope this is what you are looking for.希望这是你正在寻找的。
When you are on an activity , then use当您进行活动时,请使用
runOnUiThread {
//code that runs in main
}
When you have activity context , mContext then use当您有活动上下文时, mContext 然后使用
mContext.runOnUiThread {
//code that runs in main
}
When you are in somewhere where no context available , then use当您处于没有可用上下文的地方时,请使用
Handler(Looper.getMainLooper()).post {
//code that runs in main
}
There is another simple way, if you don't have an access to the Context.如果您无权访问上下文,还有另一种简单的方法。
1). 1)。 Create a handler from the main looper:
从主循环器创建一个处理程序:
Handler uiHandler = new Handler(Looper.getMainLooper());
2). 2)。 Implement a Runnable interface:
实现 Runnable 接口:
Runnable runnable = new Runnable() { // your code here }
3). 3)。 Post your Runnable to the uiHandler:
将您的 Runnable 发布到 uiHandler:
uiHandler.post(runnable);
That's all ;-) Have fun with threads, but don't forget to synchronize them.这就是全部;-) 享受线程的乐趣,但不要忘记同步它们。
If you run code in a thread, eg do delaying some action, then you need to invoke runOnUiThread
from the context.如果您在线程中运行代码,例如延迟某些操作,那么您需要从上下文调用
runOnUiThread
。 For example, if your code is inside MainActivity
class then use this:例如,如果您的代码在
MainActivity
类中,则使用以下代码:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
myAction();
}
});
If your method can be invoked either from main (UI thread) or from other threads you need a check like:如果您的方法可以从主(UI 线程)或其他线程调用,则需要进行以下检查:
public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {
}
A condensed code block is as follows:一个精简的代码块如下:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// things to do on the main thread
}
});
This does not involve passing down the Activity reference or the Application reference.这不涉及向下传递活动引用或应用程序引用。
Kotlin Equivalent: Kotlin 等效项:
Handler(Looper.getMainLooper()).post(Runnable {
// things to do on the main thread
})
The simplest way especially if you don't have a context, if you're using RxAndroid you can do:最简单的方法,尤其是在没有上下文的情况下,如果您使用的是 RxAndroid,则可以执行以下操作:
AndroidSchedulers.mainThread().scheduleDirect {
runCodeHere()
}
More precise Kotlin code using handler :使用 handler 更精确的 Kotlin 代码:
Handler(Looper.getMainLooper()).post {
// your codes here run on main Thread
}
One method I can think of is this:我能想到的一种方法是:
1) Let the UI bind to the service. 1) 让 UI 绑定到服务。
2) Expose a method like the one below by the Binder
that registers your Handler
: 2)通过注册您的
Handler
的Binder
公开一个类似于下面的方法:
public void registerHandler(Handler handler) {
mHandler = handler;
}
3) In the UI thread, call the above method after binding to the service: 3)在UI线程中,绑定服务后调用上述方法:
mBinder.registerHandler(new Handler());
4) Use the handler in the Service's thread to post your task: 4)使用服务线程中的处理程序发布您的任务:
mHandler.post(runnable);
HandlerThread
is better option to normal java Threads in Android . HandlerThread
是 Android 中普通 java 线程的更好选择。
requestHandler
requestHandler
post
a Runnable
task on requestHandler
requestHandler
上post
一个Runnable
任务Communication with UI Thread from HandlerThread
从
HandlerThread
与 UI 线程通信
Handler
with Looper
for main thread : responseHandler
and override handleMessage
methodLooper
的Handler
: responseHandler
并覆盖handleMessage
方法Runnable
task of other Thread ( HandlerThread
in this case), call sendMessage
on responseHandler
HandlerThread
)的Runnable
任务内部,在responseHandler
上调用sendMessage
sendMessage
result invocation of handleMessage
in responseHandler
.sendMessage
的结果调用handleMessage
在responseHandler
。Message
and process it, update UIMessage
获取属性并进行处理,更新 UI Example : Update TextView
with data received from a web service.示例:使用从 Web 服务接收到的数据更新
TextView
。 Since web service should be invoked on non-UI thread, created HandlerThread
for Network Operation.由于应该在非 UI 线程上调用 Web 服务,因此为网络操作创建了
HandlerThread
。 Once you get the content from the web service, send message to your main thread (UI Thread) handler and that Handler
will handle the message and update UI.从 Web 服务获取内容后,将消息发送到主线程(UI 线程)处理程序,该
Handler
程序将处理消息并更新 UI。
Sample code:示例代码:
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);
Useful articles:有用的文章:
handlerthreads-and-why-you-should-be-using-them-in-your-android-apps handlerthreads-and-why-you-should-be-using-them-in-your-android-apps
android-looper-handler-handlerthread-i android-looper-handler-handlerthread-i
I know this is an old question, but I came across a main thread one-liner that I use in both Kotlin and Java.我知道这是一个老问题,但我遇到了一个在 Kotlin 和 Java 中都使用的主线程单行。 This may not be the best solution for a service, but for calling something that will change the UI inside of a fragment this is extremely simple and obvious.
这可能不是服务的最佳解决方案,但对于调用会改变片段内 UI 的东西,这是非常简单和明显的。
Java (8):爪哇(8):
getActivity().runOnUiThread(()->{
//your main thread code
});
Kotlin:科特林:
this.runOnUiThread {
//your main thread code
}
So most handy is to do sort of:所以最方便的是做一些事情:
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()
}
}
}
And after:之后:
Dispatch.asyncOnBackground {
val value = ...// super processing
Dispatch.asyncOnMain { completion(value)}
}
Follow this method.按照这个方法。 Using this way you can simply update the UI from a background thread.
使用这种方式,您可以简单地从后台线程更新 UI。 runOnUiThread work on the main(UI) thread .
runOnUiThread 在主(UI)线程上工作。 I think this code snippet is less complex and easy, especially for beginners.
我认为这个代码片段不那么复杂和简单,特别是对于初学者来说。
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();
}
});
}
});
in the case of a service在服务的情况下
create a handler in the oncreate在 oncreate 中创建一个处理程序
handler = new Handler();
then use it like this然后像这样使用它
private void runOnUiThread(Runnable runnable) {
handler.post(runnable);
}
for Kotlin, you can use Anko corountines :对于 Kotlin,您可以使用Anko 协程:
update更新
doAsync {
...
}
deprecated已弃用
async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}
public void mainWork() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//Add Your Code Here
}
});
}
This can also work in a service class with no issue.这也可以在服务类中正常工作。
With Kotlin, it is just like this inside any function:使用 Kotlin,在任何函数中都是这样的:
runOnUiThread {
// Do work..
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.