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

时间:2022-01-31 21:01:31

In an android service I have created thread(s) for doing some background task.

在android服务中,我创建了用于做后台任务的线程。

I have a situation where the thread need 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 ?

是否有一种方法可以从我的另一个线程获取主线程的处理程序并向其发送消息/Runnable ?

Thanks,

谢谢,

9 个解决方案

#1


491  

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. So here are 2 possible solutions:

注意:这个答案引起了很多关注,我需要更新它。自从最初的答案被公布后,@dzeikei的评论几乎和原来的答案一样受到关注。这里有两种可能的解决方案:

1. If your background thread has a reference to a Context object:

1。如果您的后台线程有对上下文对象的引用:

Make sure that your background worker threads have access to a Context object (can be the Application context or the Service context). 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。如果您的后台线程没有(或不需要)上下文对象

(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);

#2


117  

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 simpliest cases.

下面的方法可以在最简单的情况下使用。

If I understand you correctly you need some code to be executed in GUI thread of the application (cannot think about anything else called "main" thread). For this there is a method on Activity:

如果我理解正确,您需要在应用程序的GUI线程中执行一些代码(不能考虑任何其他称为“main”线程的东西)。为此,有一种关于活动的方法:

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 % 28 java.lang.runnable % 29

Hope this is what you are looking for.

希望这就是你要找的。

#3


28  

There is another simple way, if you don't have an access to the Context.

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

1). Create a handler from the main looper:

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

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

2). Implement a Runnable interface:

2).实现可运行接口:

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

3). Post your Runnable to the uiHandler:

3).将Runnable发布到uiHandler:

uiHandler.post(runnable);

That's all ;-) Have fun with threads, but don't forget to synchronize them.

这就是全部;-)在线程上玩得开心,但别忘了同步它们。

#4


25  

If you run code in a thread, e.g. do delaying some action, then you need to invoke runOnUiThread from the context. For example, if your code is inside MainActivity class then use this:

如果您在线程中运行代码,例如执行延迟操作,那么您需要从上下文调用runOnUiThread。例如,如果您的代码在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:

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

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

}

#5


7  

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:

芬兰湾的科特林相当于:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })

#6


4  

One method I can think of is this:

我能想到的一个方法是:

1) Let the UI bind to the service.
2) Expose a method like the one below by the Binder that registers your Handler:

1)让UI绑定到服务。2)公开一种方法,如下面的绑定器注册您的处理程序:

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

#7


2  

HandlerThread is better option to normal java Threads in Android .

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

  1. Create a HandlerThread and start it
  2. 创建一个HandlerThread并启动它
  3. Create a Handler with Looper from HandlerThread :requestHandler
  4. 使用HandlerThread:requestHandler创建一个处理程序
  5. post a Runnable task on requestHandler
  6. 在requestHandler上发布可运行的任务

Communication with UI Thread from HandlerThread

与来自HandlerThread的UI线程的通信。

  1. Create a Handler with Looper for main thread : responseHandler and override handleMessage method
  2. 为主线程:responseHandler和重写handleMessage方法创建一个处理程序
  3. Inside Runnable task of other Thread ( HandlerThread in this case), call sendMessage on responseHandler
  4. 在其他线程(本例中为HandlerThread)的Runnable任务内部,在responseHandler上调用sendMessage
  5. This sendMessage result invocation of handleMessage in responseHandler.
  6. 这个sendMessage结果调用了responseHandler中的handleMessage。
  7. Get attributes from the Message and process it, update UI
  8. 从消息获取属性并处理它,更新UI

Example: Update TextView with data received from a web service. Since web service should be invoked on non-UI thread, created HandlerThread for Network Operation. 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服务接收的数据更新TextView。由于web服务应该在非ui线程上调用,因此创建了用于网络操作的HandlerThread。从web服务获得内容后,将消息发送到主线程(UI线程)处理程序,该处理程序将处理消息并更新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

#8


1  

Follow this method. Using this way you can simply update the UI from a background thread. runOnUiThread work on the main(UI) thread . I think this code snippet is less complex and easy, especially for beginners.

遵循这个方法。使用这种方法,您可以简单地从后台线程更新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();

                   }
                });
            }
        });

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

#9


1  

I know this is an old question, but I came across a main thread one-liner that I use in both Kotlin and 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.

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

Java (8):

Java(8):

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

Kotlin:

芬兰湾的科特林:

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

#1


491  

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. So here are 2 possible solutions:

注意:这个答案引起了很多关注,我需要更新它。自从最初的答案被公布后,@dzeikei的评论几乎和原来的答案一样受到关注。这里有两种可能的解决方案:

1. If your background thread has a reference to a Context object:

1。如果您的后台线程有对上下文对象的引用:

Make sure that your background worker threads have access to a Context object (can be the Application context or the Service context). 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。如果您的后台线程没有(或不需要)上下文对象

(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);

#2


117  

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 simpliest cases.

下面的方法可以在最简单的情况下使用。

If I understand you correctly you need some code to be executed in GUI thread of the application (cannot think about anything else called "main" thread). For this there is a method on Activity:

如果我理解正确,您需要在应用程序的GUI线程中执行一些代码(不能考虑任何其他称为“main”线程的东西)。为此,有一种关于活动的方法:

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 % 28 java.lang.runnable % 29

Hope this is what you are looking for.

希望这就是你要找的。

#3


28  

There is another simple way, if you don't have an access to the Context.

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

1). Create a handler from the main looper:

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

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

2). Implement a Runnable interface:

2).实现可运行接口:

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

3). Post your Runnable to the uiHandler:

3).将Runnable发布到uiHandler:

uiHandler.post(runnable);

That's all ;-) Have fun with threads, but don't forget to synchronize them.

这就是全部;-)在线程上玩得开心,但别忘了同步它们。

#4


25  

If you run code in a thread, e.g. do delaying some action, then you need to invoke runOnUiThread from the context. For example, if your code is inside MainActivity class then use this:

如果您在线程中运行代码,例如执行延迟操作,那么您需要从上下文调用runOnUiThread。例如,如果您的代码在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:

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

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

}

#5


7  

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:

芬兰湾的科特林相当于:

    Handler(Looper.getMainLooper()).post(Runnable {
        // things to do on the main thread
    })

#6


4  

One method I can think of is this:

我能想到的一个方法是:

1) Let the UI bind to the service.
2) Expose a method like the one below by the Binder that registers your Handler:

1)让UI绑定到服务。2)公开一种方法,如下面的绑定器注册您的处理程序:

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

#7


2  

HandlerThread is better option to normal java Threads in Android .

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

  1. Create a HandlerThread and start it
  2. 创建一个HandlerThread并启动它
  3. Create a Handler with Looper from HandlerThread :requestHandler
  4. 使用HandlerThread:requestHandler创建一个处理程序
  5. post a Runnable task on requestHandler
  6. 在requestHandler上发布可运行的任务

Communication with UI Thread from HandlerThread

与来自HandlerThread的UI线程的通信。

  1. Create a Handler with Looper for main thread : responseHandler and override handleMessage method
  2. 为主线程:responseHandler和重写handleMessage方法创建一个处理程序
  3. Inside Runnable task of other Thread ( HandlerThread in this case), call sendMessage on responseHandler
  4. 在其他线程(本例中为HandlerThread)的Runnable任务内部,在responseHandler上调用sendMessage
  5. This sendMessage result invocation of handleMessage in responseHandler.
  6. 这个sendMessage结果调用了responseHandler中的handleMessage。
  7. Get attributes from the Message and process it, update UI
  8. 从消息获取属性并处理它,更新UI

Example: Update TextView with data received from a web service. Since web service should be invoked on non-UI thread, created HandlerThread for Network Operation. 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服务接收的数据更新TextView。由于web服务应该在非ui线程上调用,因此创建了用于网络操作的HandlerThread。从web服务获得内容后,将消息发送到主线程(UI线程)处理程序,该处理程序将处理消息并更新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

#8


1  

Follow this method. Using this way you can simply update the UI from a background thread. runOnUiThread work on the main(UI) thread . I think this code snippet is less complex and easy, especially for beginners.

遵循这个方法。使用这种方法,您可以简单地从后台线程更新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();

                   }
                });
            }
        });

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

#9


1  

I know this is an old question, but I came across a main thread one-liner that I use in both Kotlin and 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.

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

Java (8):

Java(8):

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

Kotlin:

芬兰湾的科特林:

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