【问题标题】:synchronous messages from service to UI layer从服务到 UI 层的同步消息
【发布时间】:2012-06-21 23:57:10
【问题描述】:

广播意图的顺序是否得到保证?也就是说,如果我这样做,

sendBroadcast(intent1);
sendBroadcast(intent2);

是否保证接收者在意图 2 之前获得意图 1?我怀疑这个答案是否定的,但在这种情况下,我不太确定如何解决我的问题。

我正在尝试为我的应用程序创建一个“忙碌”指示器,当设备在网络上通话时显示忙碌,然后在网络通信完成时消失。所有网络通信都发生在 Intent 服务中。

我的尝试是在服务中开始网络通信时发送 BUSY_START 意图,并在网络通信结束时发送 BUSY_STOP。这似乎主要工作,但我偶尔会发现我的停止和启动消息无序。

有没有更好的方法来解决这个问题?

我正在考虑为每个忙碌的意图添加一个 ID,以便它们可以配对。这样,如果我收到一个已经收到停止的开始,我可以忽略它。或者,也许更简单,在每个广播中添加一个整数序列号。如果我曾经收到一个广播,其当前意图的序列小于上次接收到的意图的序列,请忽略它。

【问题讨论】:

    标签: android android-intent android-service


    【解决方案1】:

    您是否考虑过使用Handler 对象与IntentService 中的后台线程进行通信?与BroadcastReciver 方法相比,Handler 的优势在于 Handler 使用消息队列对 Message 对象进行排序。

    (我假设您的 Service 与应用的主线程在同一个进程中)。

    【讨论】:

    • 我正在尝试从 IntentService 与 UI 线程进行通信。
    • 是的。处理程序应该这样做。还是我错过了什么?
    • 在这种情况下,您需要在活动中构造处理程序并为服务提供对其的引用。你是怎么做到的?
    • 简短的回答是将其存储在某个地方的静态变量中。您可以查看 Google 的应用内结算示例代码。他们的代码有点过度设计,但基本上他们的 Service 在帮助对象上调用静态方法,该帮助对象最终持有对 Handler 对象的静态引用。或者,如果您不喜欢静态(我不喜欢),您可以在应用的 Application 对象中存储对它的引用,并让服务从那里检索它。如果服务得到一个空处理程序,它会跳过消息传递。
    • 我不能接受使用静态字段是在组件之间传递消息的最佳实践,不管它来自谷歌示例代码。
    【解决方案2】:

    至少一种可行的意图替代方案是通过应用程序类执行消息传递,即,

    1. 创建监听接口
    2. 管理应用程序中的侦听器对象集合/提供添加/删除侦听器的方法
    3. 感兴趣的实体调用应用程序方法来添加/删除自己作为侦听器
    4. 在应用程序中添加“通知”方法,在每个注册的侦听器上调用适当的侦听器接口方法
    5. 服务调用应用程序的通知方法来

    例如,

    public class MyApplication extends Application {
      public interface MyListener {
        void onEvent();
      }
    
      private Set<MyListener> listeners = new HashSet<Listener>();
    
      public void addListener(MyListener l) {
        listeners.add(l);
      }
    
      public void removeListener(MyListener l) {
        listeners.remove(l);
      }
    
      public void sendEvent() {
        for (MyListener l: listeners) { l.onEvent(); }
      }
    }
    

    现在,从您的活动(或片段)中,

    public class MyActivity extends Activity implements MyListener {
        ...
        ...
        ...
    
        @Override
        public void onEvent() {
          // do something
        }
    
        @Override
        protected void onResume() {
            super.onResume();
    
            ((MyApplication)getApplication()).addListener(this);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
    
            ((MyApplication)getApplication()).removeListener(this);
        }
    }
    

    为您服务,

    ((MyApplication)getApplication()).sendEvent();
    

    这提供了不使用意图或静态变量的同步消息传递。

    【讨论】:

    • 这段代码,正如您在此处展示的那样,看起来像是从 Service 的线程直接调用到 Activity 的主 UI 线程。那是不行的。如果你想从一个线程调用另一个线程,我真的认为你需要一个 Handler 对象。
    • 你是对的,确实如此。假设如果活动在onEvent() 中修改了 UI 线程,它应该使用runOnUIThread() 进行修改。如果我们愿意,回调框架可以隐藏它,但我宁愿把它留给 UI 线程来决定它是否需要额外的步骤。
    • 您提到这一点是一件好事,对于希望在自己的应用程序中使用您的代码示例的任何人。
    • 我不是在这里向人们指出 android 应用程序开发的每一个细微差别。理解不能从非 UI 线程更新 UI 层次结构是一个非常基本的概念。我已经花了相当多的时间回到这里并为我自己的问题写了一个长而详细的答案。不客气。如果您对此有任何疑问,我建议您投票删除该问题。
    猜你喜欢
    • 2018-11-26
    • 2012-06-21
    • 2016-03-05
    • 1970-01-01
    • 2016-02-13
    • 2018-04-27
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多