android - 从另一个线程在主线程中运行代码
在android服务中,我创建了一些用于执行某些后台任务的线程。
我有一种情况,线程需要在主线程的消息队列上发布某些任务,例如Handler。
有没有办法获得主线程Handler并从我的其他线程发布Message/Runnable?
谢谢,
12个解决方案
525 votes
注意:这个答案引起了很多关注,我需要更新它。 自从原始答案发布以来,@ 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 Wasser answered 2019-02-23T10:57:13Z
121 votes
正如下面的评论者所指出的,这不是服务的一般解决方案,仅适用于从您的活动启动的线程(服务可以是这样的线程,但不是所有这些线程)。关于服务活动沟通的复杂话题,请阅读官方文档的整个服务部分 - 这很复杂,因此理解基础知识是值得的:[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() {
});
Doc:[http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29]
希望这是你正在寻找的。
Alexey Vassiliev answered 2019-02-23T10:58:09Z
28 votes
如果您无法访问Context,还有另一种简单的方法。
1)。 从主循环器创建一个处理程序:
Handler uiHandler = new Handler(Looper.getMainLooper());
2)。 实现Runnable接口:
Runnable runnable = new Runnable() { // your code here }
3)。 将Runnable发布到uiHandler:
uiHandler.post(runnable);
这就是全部;-)享受线程的乐趣,但不要忘记同步它们。
tema_man answered 2019-02-23T10:59:03Z
26 votes
如果您在线程中运行代码,例如 延迟一些动作,然后你需要从上下文调用runOnUiThread。 例如,如果您的代码位于MainActivity类内,则使用此:
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
myAction();
}
});
如果您的方法可以从main(UI线程)或其他线程调用,则需要检查:
public void myMethod() {
if( Looper.myLooper() == Looper.getMainLooper() ) {
myAction();
}
else {
}
Alexander Volkov answered 2019-02-23T10:59:38Z
12 votes
精简代码块如下:
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
// things to do on the main thread
}
});
这不涉及传递Activity引用或Application引用。
Kotlin等效物:
Handler(Looper.getMainLooper()).post(Runnable {
// things to do on the main thread
})
david m lee answered 2019-02-23T11:00:18Z
4 votes
我能想到的一种方法是:
1)让UI绑定到服务。
2)通过注册您的Handler的Binder公开类似下面的方法:
public void registerHandler(Handler handler) {
mHandler = handler;
}
3)在UI线程中,绑定到服务后调用上面的方法:
mBinder.registerHandler(new Handler());
4)使用Service的线程中的处理程序发布您的任务:
mHandler.post(runnable);
Dheeraj V.S. answered 2019-02-23T11:01:13Z
2 votes
TextView是Android中普通java线程的更好选择。
创建一个HandlerThread并启动它
使用HandlerThread的Looper创建一个处理程序:TextView
TextView a HandlerThread任务Handler
与UI线程的通信来自TextView
使用HandlerThread为主线程创建TextView:Handler并覆盖responseHandler方法
其他线程TextView任务(本例中为HandlerThread),电话Handler,电话:responseHandler
此TextView结果调用HandlerThread在Handler。
从TextView获取属性并处理它,更新UI
示例:使用从Web服务接收的数据更新TextView。 由于应在非UI线程上调用Web服务,因此为网络操作创建了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和 - 为什么 - 你 - 应该待使用了他们,在你的Android的应用程序
Android的尺蠖处理程序,handlerthread-I
Ravindra babu answered 2019-02-23T11:03:08Z
1 votes
按照这种方法。 使用这种方式,您只需从后台线程更新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);
}
MarGin answered 2019-02-23T11:03:54Z
1 votes
我知道这是一个老问题,但我遇到了一个主线程单线程,我在Kotlin和Java中都使用过。 这可能不是服务的最佳解决方案,但是为了调用会改变片段内部UI的内容,这非常简单明了。
Java(8):
getActivity().runOnUiThread(()->{
//your main thread code
});
科特林:
this.runOnUiThread(()->{
//your main thread code
});
mevdev answered 2019-02-23T11:04:30Z
0 votes
public void mainWork() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//Add Your Code Here
}
});
}
这也可以在没有问题的服务类中工作。
NUSKTECsoft answered 2019-02-23T11:04:58Z
0 votes
对于Kotlin,你可以使用Anko协同程序:
更新
doAsync {
...
}
弃用
async(UI) {
// Code run on UI thread
// Use ref() instead of this@MyActivity
}
Francis answered 2019-02-23T11:05:36Z
0 votes
最简单的方法,特别是如果你没有上下文,如果你使用RxAndroid,你可以这样做:
AndroidSchedulers.mainThread().scheduleDirect {
runCodeHere()
}
Inn0vative1 answered 2019-02-23T11:06:04Z