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

时间:2012-06-20 16:07:11

标签: android multithreading android-handler

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

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

有没有办法获取主线程的Handler并从我的其他帖子发布Message / Runnable

谢谢,

16 个答案:

答案 0 :(得分:560)

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

答案 1 :(得分:129)

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

希望这就是你要找的东西。

答案 2 :(得分:28)

如果您无法访问上下文,还有另一种简单的方法。

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

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

2)。实现Runnable接口:

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

3)。将Runnable发布到uiHandler:

uiHandler.post(runnable);

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

答案 3 :(得分:27)

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

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

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

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

}

答案 4 :(得分:16)

精简代码块如下:

   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
    })

答案 5 :(得分:4)

我能想到的一个方法是:

1)让UI绑定到服务 2)通过注册Binder的{​​{1}}公开类似下面的方法:

Handler

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

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

4)使用服务主题中的处理程序发布您的任务:

mBinder.registerHandler(new Handler());

答案 6 :(得分:4)

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

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

答案 7 :(得分:2)

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

  1. 创建HandlerThread并启动它
  2. 使用HandlerThread创建Handler LooperrequestHandler
  3. {li> post Runnable 上的requestHandler任务

    与来自HandlerThread

    的UI主题进行通信
    1. 为主线程Handler创建Looper responseHandler并覆盖handleMessage方法
    2. 其他主题的Runnable内部任务(本例中为HandlerThread),在sendMessage上致电responseHandler
    3. sendMessage handleMessage responseHandler MessageTextView次结果调用。{/ 1}
    4. HandlerThread获取属性并对其进行处理,更新用户界面
    5. 示例:使用从Web服务收到的数据更新Handler。由于应在非UI线程上调用Web服务,因此为网络操作创建了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); 。从Web服务获取内容后,将消息发送到主线程(UI线程)处理程序,Array=[ "10", "1", "101", "NA", "100", "20", "210", "200", "NA", "7" ] 将处理消息并更新UI。

      示例代码:

      Sorted=[ "1", "7", "10", "20", "100", "101", "200", "210", "NA", "NA" ]
      

      有用的文章:

      handlerthreads-and-why-you-should-be-using-them-in-your-android-apps

      android-looper-handler-handlerthread-i

答案 8 :(得分:2)

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

Java(8):

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

科特林:

this.runOnUiThread {
     //your main thread code
}

答案 9 :(得分:2)

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

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

答案 10 :(得分:1)

遵循此方法。使用这种方式,您只需从后台线程更新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);
    }

答案 11 :(得分:1)

所以最方便的是执行以下操作:

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)}
}

答案 12 :(得分:0)

public void mainWork() {
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            //Add Your Code Here
        }
    });
}

这也可以在服务类中正常工作。

答案 13 :(得分:0)

对于Kotlin,您可以使用Anko corountines

更新

doAsync {
   ...
}

已弃用

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

答案 14 :(得分:0)

科特林版本

您正在参加活动时,请使用

runOnUiThread {
    //code that runs in main
}

您具有活动上下文时,然后使用mContext

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

当您位于没有可用上下文的地方时,请使用

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

答案 15 :(得分:-1)

对于Kotlin,它在任何函数中都是这样的:

runOnUiThread {
   // Do work..
}