首页 文章

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

提问于
浏览
257

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

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

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

谢谢,

12 回答

  • 1

    注意:这个答案引起了很多关注,我需要更新它 . 自从原始答案发布以来,@ dzeikei的评论几乎与原始答案一样受到关注 . 这里有两个可能的解决方案:

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

    确保后台工作线程有权访问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. If your background thread does not have (or need) a Context object

    (由@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);
    
  • 4

    正如下面的评论者指出的那样,这不是服务的一般解决方案,仅适用于从您的活动启动的线程(服务可以是这样的线程,但不是所有这些线程) . 关于服务活动沟通的复杂主题,请阅读官方文档的整个服务部分 - 它很复杂,因此理解基础知识是有益的:http://developer.android.com/guide/components/services.html#Notifications

    以下方法可以在最简单的情况下工作 .

    如果我理解正确,你需要在应用程序的GUI线程中执行一些代码(不能考虑其他任何称为"main"线程的东西) . 为此, 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

    希望这是你正在寻找的 .

  • 26

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

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

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

    2) . 实现Runnable接口:

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

    3) . 将Runnable发布到uiHandler:

    uiHandler.post(runnable);
    

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

  • 0

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

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

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

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

    精简代码块如下:

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

    我能想到的一种方法是:

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

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

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

    mBinder.registerHandler(new Handler());
    

    4)使用Service的线程中的处理程序发布您的任务:

    mHandler.post(runnable);
    
  • 28

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

    • 创建HandlerThread并启动它

    • 使用HandlerThread创建Handler LooperrequestHandler
      859 post Runnable 任务 requestHandler

    来自 HandlerThread 的UI线程通信

    • 为主线程创建 Handler LooperresponseHandler 并覆盖 handleMessage 方法

    • 其他线程的 Runnable 任务(本例中为 HandlerThread ),在 responseHandler 上调用 sendMessage

    • sendMessage sendMessagesendMessage 结果调用 responseHandler .

    • Message 获取属性并处理它,更新UI

    Example :使用从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-and-why-you-should-be-using-them-in-your-android-apps

    android-looper-handler-handlerthread-i

  • 12

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

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

    Java(8):

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

    科特林:

    this.runOnUiThread(()->{ 
         //your main thread code
    });
    
  • 2
    public void mainWork() {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                //Add Your Code Here
            }
        });
    }
    

    这也可以在没有问题的服务类中工作 .

  • 528

    对于Kotlin,你可以使用Anko corountines

    update

    doAsync {
       ...
    }
    

    deprecated

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

    最简单的方法,特别是如果你没有上下文,如果你使用RxAndroid,你可以这样做:

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

相关问题