大家好,又见面了,我是你们的朋友全栈君。
Android应用程序可以发送广播,也可以接收Android系统或者其它应用发出的广播,这跟发布-订阅设计模式很相似。当一些受到关心的事件发生后,广播会被自动发送。举例来说,当一些系统事件(如开机,设备开始充电等)发生,Android系统会发送广播。应用程序也可以发送自定义的广播,比如当某个应用关注的事件(如数据更新等)发生后可以发送广播提醒它。
当一系列系统事件发生的时候,系统会自动发送广播,比如飞行模式的切换。系统广播会发送给所有注册监听广播的应用。
广播消息封装在一个Intent对象中,其中的action属性标识的事件的类型(比如android.intent.action.AIRPLANE_MODE),可能在intent的附件字段还包含了附加的信息。比如,用于表示飞行模式的intent包含一个附加的布尔字段来表示飞行模式的状态是开启还是关闭。
如果想要具体了解如何如何读取一个intent并且获取附加字段,参阅Intents and Intent Filters
参阅Android SDK中的BROADCAST_ACTIONS.TXT来了解所有系统广播的action。每一个系统广播都有一个常量与其绑定。比如,常量ACTION_AIRPLANE_MODE_CHANGED表示android.intent.action.AIRPLANE_MODE。每一个广播的action的文档都在与其关联的常量域中。
Android 7.0或更高版本不再发送下列系统广播,这项优化会影响所有的应用程序,而不只是那些针对Android 7.0开发的程序。
针对Android 7.0(API level 24)或更新版本开发的应用必须在程序中使用 ACTION_NEW_PICTURE
ACTION_NEW_VIDEO
注册监听下列的广播,在程序清单中声明不再有效。
应用程序可以使用两种方式接收广播:在应用清单中定义一个广播接收器;在程序中注册一个广播接收器。
要定义一个静态广播接收器,执行下面的步骤:
当应用程序安装的时候,软件包管理器会在系统中注册广播接收器。之后这个广播接收器就变成了你的应用程序中一个独立的入口,这就意味着如果你的应用程序不在运行,系统可以启动你的程序并传递广播。
系统会创建一个新的BroadcastReceiver组件对象来处理接收到的广播。这个对象只在调用onReceive(Context, Intent)方法期间有效。一旦从该方法返回,系统就认为这个组件对象已经失效。
要注册一个上下文相关的动态广播接收器,执行以下步骤:
你的广播接收器的状态会影响它所在的进程的状态,转而会影响进程被系统杀死的可能性。比如,当一个进程执行一个广播接收器(执行onReceive()方法中的代码),它会被当作一个前台进程。除非内存极度匮乏,否则系统会一直让该进程运行。
然而,一旦从onReceive()返回,广播接收器就不再处于激活状态,它的宿主进程也就跟其它的普通进程具有相同的优先级。如果那个进程只拥有一个在应用清单中定义的接收器,那么当从onReceive()返回后,系统会把它当作一个低优先级的进程,当其它优先级更高的进程需要更多内存的时候,它就可能被杀掉。
鉴于这个原因,你不应该在一个广播接收器中启动一个长时间在后台运行的线程。当从onReceive()返回后,系统可能会杀掉进程来回收内存,这会结束所有运行在这个进程中的线程。为了避免这种情况,你要么调用goAsync()(如果你希望能够长时间在后台线程中运行广播接收器),要么在接收器中使用JobScheduler调度一个JobService。这样系统就直到你的进程还在继续执行任务。参阅 Processes and Application Life Cycle来获取更多信息。
下面的代码片段展示了使用goAsync()来标识进程需要更多时间来完成任务。如果你要执行的任务会造成UI阻塞(>16ms),这种方式非常有效。
```
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(final Context context, final Intent intent) {
final PendingResult pendingResult = goAsync();
AsyncTask<String, Integer, String> asyncTask = new AsyncTask<String, Integer, String>() {
@Override
protected String doInBackground(String... params) {
StringBuilder sb = new StringBuilder();
sb.append("Action: " + intent.getAction() + "\n");
sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
Log.d(TAG, log);
// Must call finish() so the BroadcastReceiver can be recycled.
pendingResult.finish();
return data;
}
};
asyncTask.execute();
}
}
```
Android提供了三种发送广播的方式:
下面的代码片段示范了如何通过创建Intent并且调用sendBroadcast(Intent)来发送广播:
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("data","Notice me senpai!");
sendBroadcast(intent);
广播消息被封装在一个Intent对象中。intent的action属性必须提供应用的包名并且能够唯一地标识一个广播事件。你可以通过调用putExtra(String, Bundle)来附加额外的xinxi。你也可以通过调用intent的setPackage(String)方法来将广播范围限定在某个组织的一系列应用的范围之内。
注意:虽然intents同时被用来发送广播和启动Activity,但是这些行为之间并没有任何关联。广播接收器无法捕捉到用来启动Activity的intent;同样地,当你广播一个intent,你也无法启动一个Activity。
权限机制可以让你将广播的范围限制在一系列拥有特定权限的应用之间。你既可以限制发送发,也可以限制接收方。
当你调用sendBroadcast(Intent, String)或者 sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)时,你可以指定一个权限参数。只有应用在应用清单中申请了那个权限,其中的receiver才能接收到广播。比如下面的代码发送了一个带权限的广播:
sendBroadcast(new Intent("com.example.NOTIFY"),
Manifest.permission.SEND_SMS);
要接收这个广播,应用必须申请下面的权限:
<uses-permission android:name="android.permission.SEND_SMS"/>
你既可以指定一个系统中已经存在的权限,比如SEND_SMS,也可以用自定义一个权限。关于权限的详情请参考System Permissions。
如果你在注册receiver的时候指定了一个权限参数,那么只有申请了相应权限的应用才能够向你的receiver发送广播。
比如,假设你的receiver在应用清单中这样定义:
<receiver android:name=".MyBroadcastReceiver" android:permission="android.permission.SEND_SMS">
<intent-filter>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
</intent-filter>
</receiver>
或者在代码中这样定义一个上下文相关的receiver:
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
registerReceiver(receiver, filter, Manifest.permission.SEND_SMS, null );
那么,如果你要向这些receiver发送广播,发送方必须申请如下的权限:
<uses-permission android:name="android.permission.SEND_SMS"/>
下面是关于发送和接收广播的安全性考虑和最佳使用方案:
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/148542.html原文链接:https://javaforall.cn