简体   繁体   English

使用广播意图/广播接收器将消息从服​​务发送到活动

[英]Using a broadcast intent/broadcast receiver to send messages from a service to an activity

So I understand (I think) about broadcast intents and receiving messages to them. 所以我理解(我认为)关于广播意图和接收消息给他们。

So now, my problem/what I can't work out is how to send a message from the onReceive method of a receiver to an activity. 所以现在,我的问题/我无法解决的问题是如何从接收器的onReceive方法向活动发送消息。 Lets say I have a receiver as such: 让我们说我有一个接收器:

public class ReceiveMessages extends BroadcastReceiver 
{
@Override
   public void onReceive(Context context, Intent intent) 
   {    
       String action = intent.getAction();
       if(action.equalsIgnoreCase(TheService.DOWNLOADED)){    
           // send message to activity
       }
   }
}

How would I send a message to an activity? 我如何向活动发送消息?

Would I have to instantiate the receiver in the activity I want to send messages to and monitor it somehow? 我是否必须在我想要发送消息的活动中实例化接收器并以某种方式监视它? Or what? 或者是什么? I understand the concept, but not really the application. 我理解这个概念,但不是真正的应用程序。

Any help would be absolutely amazing, thank you. 任何帮助都会非常棒,谢谢。

Tom 汤姆

EDITED Corrected code examples for registering/unregistering the BroadcastReceiver and also removed manifest declaration. EDITED更正了注册/取消注册BroadcastReceiver并删除了清单声明的代码示例。

Define ReceiveMessages as an inner class within the Activity which needs to listen for messages from the Service . ReceiveMessages定义为Activity中需要侦听来自Service消息的内部类。

Then, declare class variables such as... 然后,声明类变量,如...

ReceiveMessages myReceiver = null;
Boolean myReceiverIsRegistered = false;

In onCreate() use myReceiver = new ReceiveMessages(); onCreate()使用myReceiver = new ReceiveMessages();

Then in onResume() ... 然后在onResume() ...

if (!myReceiverIsRegistered) {
    registerReceiver(myReceiver, new IntentFilter("com.mycompany.myapp.SOME_MESSAGE"));
    myReceiverIsRegistered = true;
}

...and in onPause() ... ......并在onPause() ......

if (myReceiverIsRegistered) {
    unregisterReceiver(myReceiver);
    myReceiverIsRegistered = false;
}

In the Service create and broadcast the Intent ... Service创建并广播Intent ...

Intent i = new Intent("com.mycompany.myapp.SOME_MESSAGE");
sendBroadcast(i);

And that's about it. 这就是它。 Make the 'action' unique to your package / app, ie, com.mycompany... as in my example. 让'action'对你的包/ app来说是唯一的,就像我的例子中的com.mycompany...一样。 This helps avoiding a situation where other apps or system components might attempt to process it. 这有助于避免其他应用程序或系统组件可能尝试处理它的情况。

No offense, but your question is still damn vague. 没有冒犯,但你的问题仍然模糊不清。 So, I'm going to outline a whole mess of scenarios and hope that one of them actually hits whatever problem you think you have. 所以,我将概述一堆乱七八糟的场景,希望其中一个实际上能够解决你认为的任何问题。

Scenario A: Only The Activity 场景A:仅活动

If you only need to receive the broadcast when you have an activity in the foreground, have the activity register the BroadcastReceiver using registerReceiver() . 如果您只需要在前台有活动时接收广播,请让活动使用registerReceiver()注册BroadcastReceiver As @MisterSquonk indicated, you would register the receiver in onResume() and unregister it in onPause() . 正如@MisterSquonk所指出的那样,你将在onResume()注册接收器并在onPause()注销它。

Scenario B: Activity If In Foreground, Else Other; 情景B:活动如果在前景,其他; Ordered Broadcast 有序广播

If you want the foreground activity to handle the broadcast, but you want something else to happen if that activity is not in the foreground (eg, raise a Notification ), and the broadcast is an ordered broadcast (eg, incoming SMS), then you would still use the Scenario A solution, but with a higher-priority IntentFilter (see setPriority() ). 如果您希望前台活动处理广播,但如果该活动不在前台(例如,提出Notification ),并且广播是有序广播(例如,传入SMS),则您希望发生其他事情,那么您仍将使用Scenario A解决方案,但具有更高优先级的IntentFilter (请参阅setPriority() )。 In addition, you would register a BroadcastReceiver via a <receiver> element in the manifest, with a lower-priority <intent-filter> for the same broadcast. 此外,您将通过清单中的<receiver>元素注册BroadcastReceiver ,并为同一广播使用较低优先级的<intent-filter> In the activity's BroadcastReceiver , call abortBroadcast() to consume the event and prevent it from reaching your manifest-registered BroadcastReceiver . 在活动的BroadcastReceiver ,调用abortBroadcast()来使用该事件并阻止它到达清单注册的BroadcastReceiver

Scenario C: Activity If In Foreground, Else Other; 情景C:活动如果在前景,其他; Regular Broadcast 定期广播

If Scenario B almost fits, but the broadcast you are listening for is not an ordered broadcast, you will need to start with Scenario B. However, have the broadcast that both receivers have in their respective filters be one of your own, using a private action string as @MisterSquonk suggested. 如果场景B几乎适合,但您正在收听的广播不是有序广播,则需要从场景B开始。但是,让两个接收者在其各自的过滤器中拥有的广播是您自己的广播,使用私有@MisterSquonk建议的动作字符串。 In addition, have another BroadcastReceiver registered in the manifest, whose <intent-filter> is for the real broadcast you're listening for. 此外,在清单中注册了另一个 BroadcastReceiver ,其<intent-filter>用于您正在侦听的真实广播。 That receiver would simply call sendOrderedBroadcast() to send out the ordered broadcast that the other receivers are listening on. 该接收器将简单地调用sendOrderedBroadcast()来发送其他接收器正在侦听的有序广播。

Scenario D: Activity Regardless of Foreground 情景D:活动无论前景如何

If some activity of yours needs to know about the broadcast, and it does not matter whether or not it is in the foreground, you need to rethink what you mean by that. 如果您的某些活动需要了解广播,并且它是否在前台并不重要,您需要重新考虑您的意思。 Usually, this really means that the broadcast affects your data model in some way, in which case your concern should not be to let the activities know, but rather to update your data model, and use your already-existing "let the activities know about the data model change" logic handle the rest. 通常情况下,这实际上意味着广播影响某种方式对你的数据模型,在这种情况下,你的关注应该是让活动的认识,而是更新数据模型,并使用已经存在的“让活动的了解数据模型改变“逻辑处理其余部分。

If, however, you are convinced that this is not part of your data model, you can implement Scenario B or Scenario C, plus stick some information in a static data member. 但是,如果您确信这不是数据模型的一部分,则可以实现方案B或方案C,并在静态数据成员中添加一些信息。 Your activities can examine that static data member in onResume() to pick up the information about the broadcast when they return to the foreground. 您的活动可以检查onResume()中的静态数据成员,以便在返回到前台时获取有关广播的信息。

If you're thinking "but, what if my process is terminated between the broadcast and the other activity coming to the foreground?", then your broadcast really is updating your data model, per the opening paragraph of this scenario. 如果您正在考虑“但是,如果我的进程在广播和其他活动到达前台之间终止怎么办?”,那么根据此场景的开头段落,您的广播确实正在更新您的数据模型。

If you're thinking "but, I want to update an activity that is doing work in the background", then the activity in question is broken. 如果您正在考虑“但是,我想要更新正在后台工作的活动”,那么相关的活动就会被破坏。 Activities should never be doing work in the background. 活动永远不应该在后台工作。 That work should be delegated to some form of service, and there's a whole related set of scenarios for getting a broadcast to the service. 这项工作应该委托给某种形式的服务,并且有一整套相关的场景来获得广播服务。

To broadcast an intent: 广播意图:

Intent intent = new Intent("com.yourcompany.testIntent");
intent.putExtra("value","test");
sendBroadcast(intent);

To receive the same intent use: 要获得相同的意图用途:

IntentFilter filter = new IntentFilter("com.yourcompany.testIntent");
        BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
              String value =  intent.getExtras().getString("value");
            }
        };
registerReceiver(receiver, filter);

Possibly not relevant at the time of the question being asked but there is now the LocalBroadcastManager in the Android Support Package. 在询问问题时可能不相关,但现在Android支持包中有LocalBroadcastManager

Works pretty much the same way as normal broadcasts but all "chatter" is local to the app it is running in. 与普通广播的工作方式几乎相同,但所有“聊天”都是其运行的应用程序的本地。

Advantages: 好处:

  • You know that the data you are broadcasting won't leave your app, so don't need to worry about leaking private data. 您知道您正在播放的数据不会离开您的应用,因此无需担心泄露私人数据。
  • It is not possible for other applications to send these broadcasts to your app, so you don't need to worry about having security holes they can exploit. 其他应用程序无法将这些广播发送到您的应用程序,因此您无需担心他们可以利用安全漏洞。
  • It is more efficient than sending a global broadcast through the system. 它比通过系统发送全局广播更有效。

Example: 例:

Intent i = new Intent("my.local.intent");
LocalBroadcastManager.getInstance(context).sendBroadcast(i);

and to receive 并接受

receiver = new MyBroadcastReceiverToHandleLocalBroadcast();

IntentFilter i = new IntentFilter();
i.addAction("my.local.intent");
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, i);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM