Broadcast Receiver—大喇叭
Broadcast Receiver的一些理解
1:and中的大喇叭,四大组件之一;
2:分类:按照接收消息的机制不同分为标准广播(和现实生活中的广播一样),顺序广播;
按照广播范围不同可分为:全局广播,应用内广播;
3:使用:
1.同一app内部的同一组件内的消息通信(单个或多个线程之间);(一般不用)
2.同一app内部的不同组件之间的消息通信(单个进程);(一般不用)
3.同一app具有多个进程的不同组件之间的消息通信;
4.不同app之间的组件之间消息通信;
5.Android系统在特定情况下与App之间的消息通信。
机制:
标准广播
标准广播机制中:广播发送者会将广播发往指定的地址,只要注册了该地址的广播都会收到消息,没有谁能够阻止广播继续分发;
顺序广播
在顺序广播中,接收者是有优先级别的,优先级高的能够先接收广播,并由该接收着向下继续分发,任一级别的接收者都有权力终止广播的继续分发,或者修改广播信息之后分发;
标准版广播:
1:发送广播:
public void send(String value){
Intent intent = new Intent("and.intent.action.MY_BROADCAST");
intent.putExtra("msg",value);
sendBroadcast(intent);
}
广播信息是通过隐式intetnt发送的,在创建intetn对象的时候必须传入指定的广播地址作为参数;表示将该广播信息发往指定的广播地址!
2:接收广播:
public class MyReceiver extends BroadCastReceiver{
public void onReceive(Context context,Intent intent){
//通过intent对象解析出广播消息
String string = intent.getStringExtra("msg");
}
}
3:注册网络广播地址:
1:静态注册
方式:在注册文件中直接写死的方式;
特点:常驻型;开机之后无论应用是否启动,如果该广播地址被发送了消息,则该广播接收者即可接收到消息;
<receiver and:name="package_name.my_receiver">
<intent-filter>
<action and:name="and.intent.action.MY_BROADCAST">
<category and:name="and.intent.category.DEFAULT">
</intent-filter>
</receiver>
参数说明:
action:广播地址。可自定义,可使用系统的地址;intetn也就是通过这个参数的内容来匹配广播接收者的
2:动态注册
方式:在activity中调用函数注册的方式:
特点:可自由在需要的地方注册,在不需要的地方解除注册;一般是在onCreat()中注册,在onDestory()中解除注册;
并且只有在应用启动的时候才能接收到广播消息,当应用关闭之后将无法获取广播消息;
注册:
MyReceiver mr = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("MY_BROADCAST_RECEIVER");
registerReceiver(mr,filter);
解除注册:
public void onDestory(){
super.onDestory();
//解除注册
unregisterReceiver(myreceiver);
}
实例:
标准版静态注册
AndroidManifest.xml:
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="MY_BROADCAST_RECEIVER"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</receiver>
activity_a.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.lk.myactivityceshi.ActivityA">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="ActivityA页面"
android:textSize="75dp"
android:id="@+id/textView"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="63dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送标准广播---静态注册"
android:textSize="50dp"
android:id="@+id/buttona"
android:layout_marginBottom="63dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
ActivityA.java:
package com.example.lk.myactivityceshi;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class ActivityA extends Activity {
Button button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
button = (Button) findViewById(R.id.buttona);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send("标准广播!!!静态注册");
}
});
}
//发送广播
public void send(String str){
Intent intent = new Intent("MY_BROADCAST_RECEIVER");
intent.putExtra("msg",str);
sendBroadcast(intent);
}
}
标准版动态注册
activity_a.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.lk.myactivityceshi.ActivityA">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="ActivityA页面"
android:textSize="75dp"
android:id="@+id/textView"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="63dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送标准广播---动态注册"
android:textSize="50dp"
android:id="@+id/buttona"
android:layout_marginBottom="63dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"/>
</RelativeLayout>
ActivityA.java:
package com.example.lk.myactivityceshi;
import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class ActivityA extends Activity {
Button button;
MyReceiver mr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_a);
button = (Button) findViewById(R.id.buttona);
//动态注册
mr = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("MY_BROADCAST_RECEIVER");
registerReceiver(mr,filter);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send("标准广播!!!动态注册");
}
});
}
//发送广播
public void send(String str){
Intent intent = new Intent("MY_BROADCAST_RECEIVER");
intent.putExtra("msg",str);
sendBroadcast(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mr);
}
}
结果:
顺序广播:
1:发送广播:
public void send(String str){
Intent intent = new Intent("and.intent.action.MY_BROADCAST");
intent.putExtra("msg",str);
//注意这里是sendOrderBroadcast();
sendOrderBroadcast(intent,"scott.permission.MY_BROADCAST_PERMISSION");
//第二个参数是权限参数,如果为null则表示不要求接收者指定权限;否则,要求接收这必须指定权限;
}
注:sendboradcast()中第二个参数是权限;如果不指定该权限,则注册了该地址的广播接收者均能收到广播(在不被截断的情况下)!如果指定了权限则要求注册了改地址的广播接收者还要具备该权限,否则将接收不到消息;
如果加入了此权限,当然不能忘了在注册文件中声明该权限:
<permission android:name="scott.permission.MY_BROADCAST_PERMISSION" />
2:接收广播:
public class MyReceiver extends BroadCastReceiver{
public void onReceive(Context context,Intent intent){
//接收广播消息
String recvMsg = intent.getStringExtra("msg");
//正常向下分发消息:
Bundle bundle1 = new Bundle();
bundle1.putExtras('msg1',recvMsg);
setResultExtras (Bundle extras);
//修改广播信息,再下发:
Bundle bundle2 = new Bundle();
bundle2.putExtras('msg2',"消息已被修改"+recvMsg);
setResultExtras (Bundle extras)
//截断广播,禁止继续下发
abortBroadcast();
}
}
注册:
注:因为顺序模式的广播接收者是有优先级顺序的,因此在注册的时候要注明优先级 android:priority=”“;优先级参数范围在-1000~1000;数值越大级别越高;
代码:
<receiver and:name="package_name.my_receiver" and:priority="50">
<intent-filter>
<action and:name="and.intent.action.MY_BROADCAST">
<category and:name="and.intent.category.DEFAULT">
</intent-filter>
</receiver>
权限问题:
上面说过了;在有序广播中是可以指定接收该消息的权限的;如果广播发送者制定了权限,则接收者想要接收到消息必须申请该权限;
代码:
<uses-permission and:name="MY_PREMISSION"></uses-permisson>
//实例:
顺序版无权限
MyReceiver.java:
package com.example.lk.myactivityceshi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
/**
* Created by Administrator on 2016/11/21 0021.
*/
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String str = intent.getStringExtra("msg");
//在这我们先测试终止广播分发的情况:
Bundle bundle = new Bundle();
bundle.putString("msg2", "信息由MyReceiver转发" + str);
abortBroadcast();
Log.i("broad","MyReceiver----"+str);
}
}
MyReceiverTwo.java
package com.example.lk.myactivityceshi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
/**
* Created by Administrator on 2016/11/21 0021.
*/
public class MyReceiverTwo extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String str = intent.getStringExtra("msg");
Log.i("broad", "MyReceiverTwo----" + str);
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.example.lk.myactivityceshi"
xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:icon = "@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ActivityA">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ActivityB">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</activity>
<receiver android:name=".MyReceiver">
<!-- 注意这里的优先级,设为100 -->
<intent-filter android:priority="100">
<action android:name="MY_BROADCAST_RECEIVER"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</receiver>
<receiver android:name=".MyReceiverTwo" >
<!-- 注意这里的优先级,设为10 -->
<intent-filter android:priority="10">
<action android:name="MY_BROADCAST_RECEIVER"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</receiver>
</application>
</manifest>
结果:
结果很明显:广播并未向下分发;
第二种情况:
我们改变广播内容之后向下分发:
主要是在MyReceiver.java中设置:
MyReceiver.java:
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String str = intent.getStringExtra("msg");
//在这我们改变信息之后向下分发
Log.i("broad","MyReceiver----"+str);
Bundle bundle = new Bundle();
str += "信息由MyReceiver转发";
bundle.putString("msg2", str);
setResultExtras(bundle);
}
}
MyReceiverTwo.java:
public class MyReceiverTwo extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//先获取系统发送的广播
String str = intent.getStringExtra("msg");
Log.i("broad", "MyReceiverTwo1----" + str);
//再获取MyReceiver更改之后的广播
String str2 = getResultExtras(true).getString("msg2");
Log.i("broad", "MyReceiverTwo2----" + str2);
}
}
结果如下:
顺序版有权限
主要代码和上述无权限的一样,区别在一下几个方面:
MyReceiver.java的send()方法:
public void send(String str){
Intent intent = new Intent("MY_BROADCAST_RECEIVER");
intent.putExtra("msg", str);
//第二个参数声明要接收该广播所需要的权限,必须以包名.权限名为格式,否则将无法识别!
sendOrderedBroadcast(intent,"com.example.lk.myactivityceshi.have_permission");
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.example.lk.myactivityceshi"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 这里要声明接收者所需要的权限 -->
<permission android:name="com.example.lk.myactivityceshi.have_permission" android:protectionLevel="normal"></permission>
<application
android:icon = "@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ActivityA">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".ActivityB">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</activity>
<receiver android:name=".MyReceiver">
<intent-filter android:priority="100">
<action android:name="MY_BROADCAST_RECEIVER"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</receiver>
<receiver android:name=".MyReceiverTwo" >
<intent-filter android:priority="10">
<action android:name="MY_BROADCAST_RECEIVER"></action>
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</receiver>
</application>
<!-- 这里给receiver添加权限 -->
<uses-permission android:name="com.example.lk.myactivityceshi.have_permission"/>
</manifest>
测试结果如下:
应用内广播:
上述两种广播在整个系统不同应用间均可分发消息,而应用内广播则只能在应用内部分发消息;
此时用到了:LoadBordCastManger类来管理本地广播:
1:发送广播:
LoadBordCastManger mLoadBroadCast = LoadBordCastManger.getInstance(this);
发送方法使用mLoadBroadCast.sendBoradCast(intent);
public void send(String str){
Intent intent = new Intent(“and.intent.action.MY_BROADCAST);
intent.putExtra(“msg”,str);
//注意这里是mLoadBroadCast.sendBoradCast(intent);需要通过LoadBordCastManger类实例来发送广播
mLoadBroadCast.sendBoradCast(intent);
}
2:接收广播:
public class MyReceiver extends BroadCastReceiver{
public void onReceive(Context context,Intent intent){
//通过intent对象解析出广播消息
String string = intent.getStringExtra("msg");
}
}
注册广播:
MyReceiver myreceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.MY_BROADCAST")
//如果category不是default的话同样也要添加category
mLoadBroadCast.registerReceiver(myreceiver,filter);
解除注册
public void onDestory(){
super.onDestory();
//解除注册
mLoadBroadCast.unregisterReceiver(myreceiver);
}
实例:应用内广播;
MainActivity.java:
package com.example.lk.broadcastshili;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button button;
LocalBroadcastManager localBroadcastManger;
LocalBroadcast localBroadcast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册应用内广播广播
localBroadcastManger = LocalBroadcastManager.getInstance(this);
localBroadcast = new LocalBroadcast();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.MY_BROADCAST_LOCAL");
localBroadcastManger.registerReceiver(localBroadcast, intentFilter);
//给按钮添加点击事件
button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
send();
}
});
}
//发送广播
public void send(){
Intent intent = new Intent("android.intent.action.MY_BROADCAST_LOCAL");
intent.putExtra("msg","broadcast local!");
//在此处需要通过manger来发送广播
localBroadcastManger.sendBroadcast(intent);
}
//在onDestory中杰出广播注册
public void onDestory(){
localBroadcastManger.unregisterReceiver(localBroadcast);
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.example.lk.broadcastshili"
xmlns:android="http://schemas.android.com/apk/res/android">
<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=".LocalBroadcast">
<intent-filter >
<action android:name="android.intent.action.MY_BROADCAST_LOCAL">
</action>
</intent-filter>
</receiver>
</application>
</manifest>
LocalBroadcast.java:
package com.example.lk.broadcastshili;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class LocalBroadcast extends BroadcastReceiver {
@Override
//接收消息和其他形式的广播是一致的
public void onReceive(Context context, Intent intent) {
String strmsg = intent.getStringExtra("msg");
Log.i("local", strmsg);
}
}
结果如下: