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

Ahm*_*med 302 java multithreading android android-handler

在android服务中,我创建了一些用于执行某些后台任务的线程.

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

有没有办法获得Handler主线程并从我的其他线程发布Message/ Runnable到它?

谢谢,

Dav*_*ser 593

注意:这个答案引起了很多关注,我需要更新它.自从原始答案发布以来,@ 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);
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

  • 我相信如果使用`Handler mainHandler = new Handler(Looper.getMainLooper()),你甚至不需要上下文;` (197认同)
  • 小点; 你的代码不会出现......目前的情况.它应该是`new Runnable(){@ Override public void run(){....}};` (6认同)
  • 不.如果你继承`Handler`(或使用`Handler.Callback`接口),你的`handleMessage()`方法只会被调用使用你的处理程序发布的消息.主线程使用不同的处理程序来发布/处理消息,因此没有冲突. (2认同)
  • @SagarDevanga 这不是提出不同问题的正确地方。请发布一个新问题,而不是对不相关的答案发表评论。这样你会得到更好更快的响应。 (2认同)

小智 136

正如下面的评论者所指出的,这不是服务的一般解决方案,仅适用于从您的活动启动的线程(服务可以是这样的线程,但不是所有这些线程).关于服务活动沟通的复杂主题,请阅读官方文档的整个服务部分 - 它很复杂,因此理解基础知识是值得的: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() {
});
Run Code Online (Sandbox Code Playgroud)

Doc:http://developer.android.com/reference/android/app/Activity.html#runOnUiThread%28java.lang.Runnable%29

希望这是你正在寻找的.

  • OP说他正在"服务"中运行线程.你不能在`Service`中使用`runOnUiThread()`.这个答案具有误导性,并没有解决问题. (18认同)

tem*_*man 30

如果您无法访问Context,还有另一种简单的方法.

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

Handler uiHandler = new Handler(Looper.getMainLooper());
Run Code Online (Sandbox Code Playgroud)

2).实现Runnable接口:

Runnable runnable = new Runnable() { // your code here }
Run Code Online (Sandbox Code Playgroud)

3).将Runnable发布到uiHandler:

uiHandler.post(runnable);
Run Code Online (Sandbox Code Playgroud)

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


Ale*_*kov 28

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

MainActivity.this.runOnUiThread(new Runnable() {
    @Override
    public void run() {
        myAction();
    }
});
Run Code Online (Sandbox Code Playgroud)

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

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

}
Run Code Online (Sandbox Code Playgroud)

  • OP说他正在"服务"中运行线程.你不能在`Service`中使用`runOnUiThread()`. (7认同)

dav*_*lee 21

精简代码块如下:

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

这不涉及传递Activity引用或Application引用.

Kotlin等效物:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })
Run Code Online (Sandbox Code Playgroud)


mev*_*dev 8

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

爪哇 (8):

 getActivity().runOnUiThread(()->{
      //your main thread code
 });
Run Code Online (Sandbox Code Playgroud)

科特林:

this.runOnUiThread {
     //your main thread code
}
Run Code Online (Sandbox Code Playgroud)


Saz*_*han 8

Kotlin versions

When you are on an activity, then use

runOnUiThread {
    //code that runs in main
}
Run Code Online (Sandbox Code Playgroud)

When you have activity context, mContext then use

mContext.runOnUiThread {
    //code that runs in main
}
Run Code Online (Sandbox Code Playgroud)

When you are in somewhere where no context available, then use

Handler(Looper.getMainLooper()).post {  
    //code that runs in main
}
Run Code Online (Sandbox Code Playgroud)


Rav*_*abu 6

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

  1. 创建一个HandlerThread并启动它
  2. 从 HandlerThread创建带有Looper 的处理程序requestHandler
  3. post一项Runnable任务requestHandler

与 UI 线程的通信来自HandlerThread

  1. 创建一个主线程: Handler并覆盖方法LooperresponseHandlerhandleMessage
  2. 其他线程的内部Runnable任务(HandlerThread在本例中),sendMessage调用responseHandler
  3. sendMessage结果调用handleMessagein responseHandler
  4. 从中获取属性Message并处理它,更新 UI

示例TextView使用从 Web 服务接收的数据进行更新。由于 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);
Run Code Online (Sandbox Code Playgroud)

有用的文章:

处理程序线程以及为什么你应该在你的 Android 应用程序中使用它们

android-looper-handler-handlerthread-i


Inn*_*ve1 5

最简单的方法,尤其是在没有上下文的情况下,如果您使用的是 RxAndroid,则可以执行以下操作:

AndroidSchedulers.mainThread().scheduleDirect {
    runCodeHere()
}
Run Code Online (Sandbox Code Playgroud)


Ham*_*ani 5

使用 handler 更精确的 Kotlin 代码:

Handler(Looper.getMainLooper()).post {  
 // your codes here run on main Thread
 }
Run Code Online (Sandbox Code Playgroud)


phi*_*r97 5

ContextCompat.getMainExecutor(context).execute {
  // do something
}
Run Code Online (Sandbox Code Playgroud)