【问题标题】:Accessing UI thread handler from a service从服务访问 UI 线程处理程序
【发布时间】:2011-06-16 08:53:02
【问题描述】:

我正在 Android 上尝试一些新的东西,我需要访问 UI 线程的处理程序。

我知道以下几点:

  1. UI 线程有自己的处理程序 和弯针
  2. 将放置任何消息 进入 UI 的消息队列 线程
  3. looper 接收事件 并将其传递给处理程序
  4. 处理程序处理消息并 将特定事件发送到 UI

我希望我的服务必须获取 UI 线程处理程序并将消息放入此处理程序。 这样这个消息就会被处理并发送到 UI。 这里的服务将是一个正常的服务,将由某个应用程序启动。

我想知道这是否可能。 如果是,请推荐一些代码sn-ps,以便我可以尝试。

问候 吉里什

【问题讨论】:

    标签: android multithreading user-interface service handler


    【解决方案1】:

    这段代码的 sn-p 构造了一个与主(UI)线程关联的 Handler:

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

    然后您可以像这样在主 (UI) 线程中发布要执行的内容:

    handler.post(runnable_to_call_from_main_thread);
    

    如果处理程序本身是从主 (UI) 线程创建的,则为简洁起见,可以省略该参数:

    Handler handler = new Handler();
    

    关于进程和线程的Android Dev Guide 有更多信息。

    【讨论】:

    • 经过测试,效果很好!用例示例:我有一个 Web 界面,由直接在设备上运行的服务器提供服务。由于该界面可用于直接与 UI 交互,并且由于服务器需要在其自己的线程上运行,因此我需要一种从 Activity 外部触摸 UI 线程的方法。您描述的方法效果很好。
    • 太棒了。像魅力一样工作,非常有用。谢谢。
    • 完美 ^^ 只是用它从 StreamingService 更新我的 ui。正是我需要的谢谢!
    • 你知道我是否可以创建一个处理程序的单例实例,并在每次我需要在 ui 线程上运行某些东西时使用它吗?
    • 我想我们永远不会知道
    【解决方案2】:

    创建一个附加到您的HandlerMessenger 对象,并将该Messenger 传递给Service(例如,在Intent 中为startService() 附加)。然后Service 可以通过MessengerHandler 发送MessageHere is a sample application 演示了这一点。

    【讨论】:

    • 感谢您的提示。这很有帮助。请参阅以下堆栈以了解我的活动 MyDemo.dispatchTouchEvent(MotionEvent) 行的触摸事件流:20 PhoneWindow$DecorView.dispatchTouchEvent(MotionEvent) 行:1696 ViewRoot.handleMessage(Message) 行:1658 ViewRoot(Handler).dispatchMessage(Message ) line: 99 Looper.loop() line: 123 //事件处理从这里开始 ActivityThread.main(String[]) line: 4203 这里的ViewRoot是一个Handler。我想获取此处理程序的引用...是否可以从我的应用程序中获取它?
    • @iLikeAndroid:如果您没有创建Handler,您将无法访问它,AFAIK。
    • 谢谢。我试图创建一个 ViewRoot 的实例。这不过是一个处理程序。现在我可以在这个处理程序上发出消息了。处理程序正在获取消息。但是 ViewRoot 无法处理该消息,因为它没有正确初始化。我需要调用 ViewRoot.setView() 将正确的数据初始化到 ViewRoot。我想知道是否有可以用来初始化的默认视图或基本视图等?
    • @iLikeAndroid:Android SDK 中没有ViewRoot,AFAICT。
    • @hadez30:就我个人而言,我不怎么使用绑定服务。仍然欢迎您使用Handler/Messenger,尽管我会用事件总线(例如,greenrobot 的 EventBus)替换所有这些。
    【解决方案3】:

    目前我更喜欢使用Otto 等事件总线库来解决此类问题。只需订阅所需的组件(活动):

    protected void onResume() {
        super.onResume();
        bus.register(this);
    }
    

    然后提供回调方法:

    public void onTimeLeftEvent(TimeLeftEvent ev) {
        // process event..
    }
    

    然后当您的服务执行如下语句时:

    bus.post(new TimeLeftEvent(340));
    

    该 POJO 将传递给您的上述活动和所有其他订阅组件。简洁大方。

    【讨论】:

      【解决方案4】:

      我建议尝试以下代码:

          new Handler(Looper.getMainLooper()).post(() -> {
      
              //UI THREAD CODE HERE
      
      
      
          });
      

      【讨论】:

      • 需要一些额外的解释来协助 OP。
      【解决方案5】:

      可以通过广播接收器获取值......如下,首先创建自己的IntentFilter为,

      Intent intentFilter=new IntentFilter();
      intentFilter.addAction("YOUR_INTENT_FILTER");
      

      然后创建内部类BroadcastReceiver为,

          private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
          /** Receives the broadcast that has been fired */
          @Override
          public void onReceive(Context context, Intent intent) {
              if(intent.getAction()=="YOUR_INTENT_FILTER"){
                 //HERE YOU WILL GET VALUES FROM BROADCAST THROUGH INTENT EDIT YOUR TEXTVIEW///////////
                 String receivedValue=intent.getStringExtra("KEY");
              }
          }
      };
      

      现在在 onResume() 中注册您的广播接收器,

      registerReceiver(broadcastReceiver, intentFilter);
      

      最后在 onDestroy() 中将 BroadcastReceiver 注销为,

      unregisterReceiver(broadcastReceiver);
      

      现在最重要的部分...您需要从需要发送值的任何地方触发广播...这样做,

      Intent i=new Intent();
      i.setAction("YOUR_INTENT_FILTER");
      i.putExtra("KEY", "YOUR_VALUE");
      sendBroadcast(i);
      

      ....干杯:)

      【讨论】:

        【解决方案6】:

        kotlin 你可以这样做

        如果你想显示来自服务的 Toast 消息,可以说

        val handler = Handler(Looper.getMainLooper())
        handler.post {
           Toast.makeText(context, "This is my message",Toast.LENGTH_LONG).show()
        }
        

        【讨论】:

          【解决方案7】:

          解决方案:

          1. 从主线程创建一个HandlerLooper:requestHandler
          2. 从主线程中使用Looper 创建一个Handler:responseHandler 并覆盖handleMessage 方法
          3. 在 requestHandler 上发布 Runnable 任务
          4. Runnable任务内部,调用responseHandler上的sendMessage
          5. 这个sendMessage导致在responseHandler中调用handleMessage。
          6. Message获取属性并处理它,更新UI

          示例代码:

              /* Handler from UI Thread to send request */
          
              Handler requestHandler = new Handler(Looper.getMainLooper());
          
               /* Handler from UI Thread to process messages */
          
              final Handler responseHandler = new Handler(Looper.getMainLooper()) {
                  @Override
                  public void handleMessage(Message msg) {
          
                      /* Processing handleMessage */
          
                      Toast.makeText(MainActivity.this,
                              "Runnable completed with result:"+(String)msg.obj,
                              Toast.LENGTH_LONG)
                              .show();
                  }
              };
          
              for ( int i=0; i<10; i++) {
                  Runnable myRunnable = new Runnable() {
                      @Override
                      public void run() {
                          try {
                             /* Send an Event to UI Thread through message. 
                                Add business logic and prepare message by 
                                replacing example code */
          
                              String text = "" + (++rId);
                              Message msg = new Message();
          
                              msg.obj = text.toString();
                              responseHandler.sendMessage(msg);
                              System.out.println(text.toString());
          
                          } catch (Exception err) {
                              err.printStackTrace();
                          }
                      }
                  };
                  requestHandler.post(myRunnable);
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2012-06-21
            • 2015-06-02
            • 1970-01-01
            • 2020-10-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多