Android Activity 中的广播接收器

52

我只是在尝试这个小样例项目,它所做的事情如下: Activity一有一个按钮可以发送广播。Activity二在接收到广播时显示一个toast提示。 以下是代码,但广播从未被接收。我错在哪里了?

发送广播

public class SendBroadcast extends Activity {

    public static String BROADCAST_ACTION = "com.unitedcoders.android.broadcasttest.SHOWTOAST";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public void sendBroadcast(View v){
        Intent broadcast = new Intent();
        broadcast.setAction(BROADCAST_ACTION);
        sendBroadcast(broadcast);
    }
}

接收它

public class ToastDisplay extends Activity {

    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);
        }
    };

    @Override
    protected void onResume() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(SendBroadcast.BROADCAST_ACTION);
        registerReceiver(receiver, filter);
        super.onResume();
    }

    @Override
    protected void onPause() {
        unregisterReceiver(receiver);
        super.onPause();
    }
}

清单

<application android:icon="@drawable/icon" android:label="@string/app_name">
    <activity android:name=".SendBroadcast" android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity android:name=".ToastDisplay">
        <intent-filter>
            <action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"></action>
        </intent-filter>
    </activity>
</application>

你有找到这个问题的答案吗?我也遇到了同样的问题。我实际上有一个本地服务,它广播一个意图,当前打开的活动会监听它(注册广播接收器,就像你上面所做的那样)。但是活动从未收到消息。我没有在清单中放置任何内容,但由于我正在注册广播接收器,因此我认为我不需要。你最后解决了吗? - Garret Wilson
谢谢。事实证明我的问题涉及指定MIME类型。 - Garret Wilson
嗨nheid,我也在寻找同样的东西...并且正在实现您上面的代码,但它不起作用,意思是广播正在发送到其他活动..请帮忙。 - SRam
Broadcat没有发送到其他活动。 - SRam
嗨,Garret Wilson,你找到上述问题的解决方案了吗? - shyam
显示剩余2条评论
7个回答

42

我做错了什么?

ToastDisplay的源代码没问题(我的类似并且可用),但它只有在前台时才会接收到信息(你在onResume中注册接收器)。但如果显示不同的活动(在这种情况下是SendBroadcast活动),它将无法接收任何内容。

相反,您可能希望从第一个活动startActivity ToastDisplay?

BroadcastReceiver和Activity在不同的用例中是有意义的。在我的应用程序中,我需要从后台GPS跟踪服务接收通知,并在活动中显示它们(如果活动在前台)。

没有必要在清单中注册接收器。在我的用例中甚至会造成危害——我的接收器操作活动的UI,如果活动当前未显示,则在onReceive期间UI将不可用。相反,我按照BroadcastReceiver文档中所述,在onResume和onPause中为活动注册和注销接收器:

您可以通过Context.registerReceiver()动态注册此类的实例,也可以通过AndroidManifest.xml中的静态发布实现。


如何在BroadcastReceiver的onReceive()方法中检查前台活动是哪个? - zmeda
2
@zmeda,这不是你应该思考的方式:要么你知道哪些活动可以受到广播接收器的影响,并为所有活动注册一个接收器,要么你不想与活动交互,就在应用程序清单中注册接收器。 - Vince
一个问题。在这两个方法的结尾都调用super有什么原因吗?或者不调用也可以吗?谢谢。 - Ricardo

39
 Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT);

制作了吐司,但没有显示。

您需要进行以下操作:Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT).show();


2
+1:如果可以的话,我会点赞多次——我以前经常这样做。我认为这是一个非常常见的错误。 - Richard Le Mesurier
5
谁想制作吐司但不想展示它。不必要的命令:show()。哈哈 - alicanbatur
3
尽管晚了一些,因为你可以操纵烤面包对象。 - Derk-Jan

5

通过BroadcastReceiver扩展ToastDisplay类,并在清单文件中注册接收器,不要在onResume()中注册广播接收器。

<application
  ....
  <receiver android:name=".ToastDisplay">
    <intent-filter>
      <action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"/>
    </intent-filter>
  </receiver>
</application>

如果您想在活动中进行注册,则应在onCreate()方法中进行注册,例如:
onCreate(){

    sentSmsBroadcastCome = new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "SMS SENT!!", Toast.LENGTH_SHORT).show();
        }
    };
    IntentFilter filterSend = new IntentFilter();
    filterSend.addAction("m.sent");
    registerReceiver(sentSmsBroadcastCome, filterSend);
}

4

您需要在清单文件中将接收器定义为一个类,并且它将会接收到意图:

<application
  ....
  <receiver android:name=".ToastReceiver">
    <intent-filter>
      <action android:name="com.unitedcoders.android.broadcasttest.SHOWTOAST"/>
    </intent-filter>
  </receiver>
</application>

您不需要在ToastDisplay内手动创建类。

在您提供的代码中,您必须在ToastDisplay活动中才能实际接收意图。


好的,我明白了。这样做是可以的。但如果我想把它变成一个活动怎么办呢?比如说我想改变一些标签? - nheid
请更详细地解释一下你想要做什么。也许你不需要使用BroadcastReceiver,只需启动另一个线程(AsyncTask是最好的)?或者你可以向Activity发送一个意图。 - m_vitaly
假设活动二(接收部分)是显示统计数据的活动。每当用户在活动一中执行某些特殊事件或后台服务有新信息时,我希望更新活动二中的信息。 - nheid
发送一个带有特殊属性的Intent,只有在活动已经打开的情况下才会传递该意图。请参阅Intent的javadoc以了解如何实现此操作。 - m_vitaly
另一个提示:请查看SDK中的samples/android-8/ApiDemos/src/com/example/android/apis/app/OneShotAlarm.java - Steve Pomeroy

1
你忘记在最后加上 .show(),它用于显示提示消息。
Toast.makeText(getApplicationContext(), "received", Toast.LENGTH_SHORT).show();

程序员常犯的一个错误,但我相信在阅读完这篇文章后,你不会再重复这个错误了... :D


1

我认为你的问题是在另一个活动开始之前发送了广播!因此,另一个活动将不会接收到任何内容。

  1. 测试代码的最佳实践是从线程或服务中发送广播,以便打开活动并注册接收器,然后后台进程发送消息。
  2. 从发送者活动启动ToastDisplay活动(我没有测试过,但可能有效)

0

你还需要在onCreate()中注册接收器,像这样:

IntentFilter filter = new IntentFilter();
filter.addAction("csinald.meg");
registerReceiver(receiver, filter);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接