定义
在Android中,广播Broadcast也是四大组件之一,它是一种广泛运用在应用程序内部或不同应用程序之间传输信息的机制。比如像一些垃圾短信骚扰电话拦截程序,他们会在接收到短信和拔入电话时,接收系统这两个广播,然后在系统做出反应前先做相应用过滤逻辑处理。除了系统广播外,我们也可以自定义一些广播用来传输数据和接收数据,又或者在Service(如不清楚Service的使用,请看《Android里服务Service的使用》)中要通知主程序更新界面,等。其实简单地理解就是,Broadcast跟我们传统意义中的电台广播有些相似之处。之所以叫做广播,就是因为它只负责“说”而不管你“听不听”,也就是不管你接收方如何处理。另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收。
广播的注册方式
广播有两种注册接收的方式,分别是在代码中动态注册和在AndroidManifest.xml静态注册。前者只在程序运行时才能接收广播,而后者可以在程序没有启动的情况下也能接收广播。下面来看看它们的实现。
动态注册方式
假设我们目前示例工程中存在一个MainActivity.java的Activity和MyService.java的Service,现在希望在Service里发一条广播并带参数给Activity,好让界面做出相应的逻辑,那么代码可以这样:
MyService:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent intentBroadcast = new Intent();
intentBroadcast.setAction("BroadcastAction"); // 设置广播的Action
intentBroadcast.putExtra("parameter", "helloworld!"); // 带的参数
getBaseContext().sendBroadcast(intentBroadcast); // 发送广播
return super.onStartCommand(intent, flags, startId);
}
发送广播很简单,这里在Service的onStartCommand中用sendBroadcast方法来实现发送广播,发送前,设定了广播的Action和带上参数
MainActivity:
private IntentFilter mIntentFilter;
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if ("BroadcastAction".equalsIgnoreCase(intent.getAction())) {
Toast.makeText(context, "这是动态注册,接收到了一个广播,parameter是:" + intent.getStringExtra("parameter"),Toast.LENGTH_LONG).show();
}
}
};
@Override
protected void onResume() {
super.onResume();
if (mIntentFilter == null) {
mIntentFilter = new IntentFilter();
mIntentFilter.addAction("BroadcastAction"); // 广播的Action是:BroadcastAction,必须要与发送广播的Action一样才能接收到广播
}
registerReceiver(mBroadcastReceiver, mIntentFilter);
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
可以看到,Activity中onResume()和onPause()方法分别做了注册广播和取消注册广播的操作,其中注册方法registerReceiver中第一个参数是接收一个BroadcastReceiver对象,有方法onReceive,这是当这个广播被接收的时候就会执行这个方法(也可以弄一个继承BroadcastReceiver的内部类)。第二个参数是一个IntentFilter对象,要注意的是filter.addAction方法添加了一个Action,这个Action是必须要和发送广播的Action一样,这就像我们在接收电台时,必须要调到跟发射电台的频道一样才能接收到该电台的广播道理一样。
静态注册方式
上面提到,静态注册是可以在程序没有启动的情况下也能接收广播,比如要拦截短信和电话的话,那必须要使用静态注册方式了。上面示例中要修改成静态注册方式,只要修改接收方就可以,我们还是继续保留Service里发送广播的部分。要注意一点,静态注册中必须要新建一个接收类,并继承BroadcastReceiver类(内部类也不行),实现onReceive方法。那么代码可以这样:
MyReceiver:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if ("BroadcastAction".equalsIgnoreCase(intent.getAction())) {
Toast.makeText(context, "这是静态注册,接收到了一个广播,parameter是:" +intent.getStringExtra("parameter"), Toast.LENGTH_LONG).show();
}
}
}
AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MyReceiver">
<intent-filter android:priority="100">
<action android:name="BroadcastAction" />
</intent-filter>
</receiver>
</application>
receiver中的android:name就是我们在程序中的那个接收广播的类。intent-filter里的android:priority属性为广播接收的优先级,数字越大,就会越早接收到广播。action中的android:name属性就是我们上面提到的像广播电台的率道action。
拦截短信实现
前面一直提到拦截短信和电话,现在我们就来简单实现一下拦截短信的做法,只要简单修改一下上面的静态注册示例即可:
MyReceiver:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if("android.provider.Telephony.SMS_RECEIVED".equalsIgnoreCase(intent.getAction())){
if (这里执行是否垃圾短信的判断) {
abortBroadcast(); //如果是垃圾短信,则中断广播
}
}
}
}
是不是发现修改的地方非常的少,"android.provider.Telephony.SMS_RECEIVED"就是系统里接收短信的广播Action,我们在判断Action中换成了它,然后增加一个判断是否垃圾短信的判断(详细逻辑这里省略),如果条件成立,则使用 abortBroadcast()方法将广播中断,从而系统的短信程序便收不到此短信,这样用户就不会被垃圾的短信给骚扰了。
AndroidManifest.xml:
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MyReceiver">
<intent-filter android:priority="999">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
前面提到,intent-filter里的android:priority属性为广播接收的优先级,为了赶在系统短信程序前,我们把此值设定为较大的值999,然后修改action名为"android.provider.Telephony.SMS_RECEIVED"。还有要记得,千万要给你的程序加入监控接收短信的权限,这样一个拦截垃圾短信的程序便大功告成了。