为了方便进行系统级别的消息通知,Android有一套类似广播的消息机制,每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能是来自于系统,也可能是来自于其他程序。
先区分两个概念:广播和广播接收器
广播是由系统或者程序发出,广播中包含某些数据或者信息。
广播接收器是一个继承了BroadcastReceiver的类,用来接收广播并做出相应响应或处理。
广播可以分为两种类型:有序广播、有序广播
标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因为它们之间没有任何先后顺序可言,这种广播的效率会比较高,但同时也意味着它是无法被截断的
如上图所示,每个人都代表一个广播接收器,在广播发出之后,每个人(广播接收器)都会接收到这条广播
有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到,当这个广播接收器中的逻辑执行完毕之后,广播才会继续传递。所以有序广播是有先后顺序的,优先级高的广播接收器可以先接受到广播消息,并且还可以阻断正在传递的广播,如果截断,后面的接收器就无法收到了
总结一下普通广播和有序广播的特点:
普通广播:
使用sendBroadcast()发送广播
同级别的广播接收器接收先后顺序是随机的
不同级别的广播接收器,级别低的后收到广播
接收器不能阻断广播,也不能处理广播
同级别的广播接收器,动态注册优先级高于静态注册
有序广播:
使用sendOrderedBroadcast()发送广播
同级别的广播接收器顺序是随机的(级别越高,越先收到)
能阻断广播,也能处理广播
同级别的广播接收器,动态注册优先级高于静态注册
一个简单的示例演示一下:
看代码
package cn.lixyz.broadcasttest; import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText; public class MainActivity extends Activity { private EditText editText; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //设置两个按钮的点击事件
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent intent = new Intent();
intent.setAction("cn.lixyz.broadcasttest.MainActivity");
sendBroadcast(intent);
break;
case R.id.button2: break;
}
}
}
MainActivity.java
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/11.
*/
public class MyFirstReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST","MyFirstReceiver广播接收器接收到了广播");
}
}
MyFirstReceiver.java
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/11.
*/
public class MySecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MySecondReceiver广播接收器接收到广播了");
}
}
MySecondReceiver.java
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity"> <EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入您要广播的消息" /> <!-- 设置一个发送普通广播的按钮 -->
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="doClick"
android:text="发送普通广播" /> <!-- 设置一个发送有序广播的按钮 -->
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="doClick"
android:text="发送有序广播" /> </LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter>
<action android:name="cn.lixyz.broadcasttest.MainActivity" /> </intent-filter>
</receiver>
<receiver android:name=".MySecondReceiver">
<intent-filter>
<action android:name="cn.lixyz.broadcasttest.MainActivity" /> </intent-filter>
</receiver>
</application>
</manifest>
AndroidManiFest.xml
运行结果
点击“发送普通广播按钮”,有如下Log:
可以看到两个接收器都已经接收到了广播,这里显示的是MyFirstReceiver先接收到,但其实是随机的。
现在我们修改一下两个接收器的优先级,修改AndroidManiFest.xml文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter android:priority="200">
<action android:name="cn.lixyz.broadcasttest.MainActivity" /> </intent-filter>
</receiver>
<receiver android:name=".MySecondReceiver">
<intent-filter android:priority="300">
<action android:name="cn.lixyz.broadcasttest.MainActivity" /> </intent-filter>
</receiver>
</application>
</manifest>
AndroidManiFest.xml
这时候再看运行结果:
会发现MySecondReceiver首先接收到,所以同级别的广播接收器接收先后顺序是随机的而不同级别的广播接收器,级别低的后收到广播
我们再尝试阻断一下广播,使用abortBroadcast()方法来阻断广播:
修改MySecondReceiver.java
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/11.
*/
public class MySecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MySecondReceiver广播接收器接收到广播了");
abortBroadcast();
}
}
MySecondReceiver.java
运行结果:
可见,并没有阻断成功,所以普通广播不能阻断广播
接下来我们修改一下两个接收器的注册方式:
将MySecondReceiver改为动态注册
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/11.
*/
public class MySecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MySecondReceiver广播接收器接收到广播了");
abortBroadcast();
}
}
MySecondReceiver.java
package cn.lixyz.broadcasttest; import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText; public class MainActivity extends Activity { private EditText editText;
private IntentFilter intentFilter;
private MySecondReceiver mySecondReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); intentFilter = new IntentFilter("cn.lixyz.broadcasttest.MainActivity");
mySecondReceiver = new MySecondReceiver();
registerReceiver(mySecondReceiver, intentFilter); } @Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mySecondReceiver);
} //设置两个按钮的点击事件
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent intent = new Intent();
intent.setAction("cn.lixyz.broadcasttest.MainActivity");
intent.putExtra("data", "这是广播信息");
sendBroadcast(intent);
break;
case R.id.button2: break;
}
}
}
MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter>
<action android:name="cn.lixyz.broadcasttest.MainActivity" /> </intent-filter>
</receiver>
</application>
</manifest>
AndroidManiFest.xml
运行结果为:
可见:普通广播中同级别的广播接收器,动态注册优先级高于静态注册。
注意:动态注册的广播接收器,一定要记得取消注册,一般在onDestroy()方法中调用unregisterReceiver(Receiver)来取消注册。
看一下有序广播,修改代码:
package cn.lixyz.broadcasttest; import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText; public class MainActivity extends Activity { private EditText editText;
private IntentFilter intentFilter;
private MySecondReceiver mySecondReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} //设置两个按钮的点击事件
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent intent = new Intent();
intent.setAction("cn.lixyz.broadcasttest.MainActivity");
intent.putExtra("data", "这是广播信息");
sendBroadcast(intent);
break;
case R.id.button2:
Intent intent2 = new Intent();
intent2.setAction("cn.lixyz.broadcasttest.MainActivity");
sendOrderedBroadcast(intent2, null);
break;
}
}
}
MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter>
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver>
<receiver android:name=".MySecondReceiver">
<intent-filter>
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver>
</application>
</manifest>
AndroidManiFest.xml
将两个广播接收器都设置为静态注册,并且没有设置优先级,默认两个优先级相同,运行结果为:
虽然运行结果是MyFirstReceiver先执行,但实际上有序广播对于优先级相同的接收器也是随机随机的。
我们将MySecondReceiver修改为动态注册
package cn.lixyz.broadcasttest; import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText; public class MainActivity extends Activity { private EditText editText;
private IntentFilter intentFilter;
private MySecondReceiver mySecondReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mySecondReceiver = new MySecondReceiver();
intentFilter = new IntentFilter("cn.lixyz.broadcasttest.MainActivity");
registerReceiver(mySecondReceiver, intentFilter); } @Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mySecondReceiver);
} //设置两个按钮的点击事件
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent intent = new Intent();
intent.setAction("cn.lixyz.broadcasttest.MainActivity");
intent.putExtra("data", "这是广播信息");
sendBroadcast(intent);
break;
case R.id.button2:
Intent intent2 = new Intent();
intent2.setAction("cn.lixyz.broadcasttest.MainActivity");
sendOrderedBroadcast(intent2, null);
break;
}
}
}
MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter>
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver>
</application>
</manifest>
AndroidManiFest.xml
点击“发送有序广播”按钮,运行结果为:
可见,有序广播下,相同优先级的广播接收器,动态注册的要优先于静态注册。
将两个接收器全部设置为静态注册,并设置优先级
package cn.lixyz.broadcasttest; import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText; public class MainActivity extends Activity { private EditText editText;
private IntentFilter intentFilter;
private MySecondReceiver mySecondReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); } //设置两个按钮的点击事件
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent intent = new Intent();
intent.setAction("cn.lixyz.broadcasttest.MainActivity");
intent.putExtra("data", "这是广播信息");
sendBroadcast(intent);
break;
case R.id.button2:
Intent intent2 = new Intent();
intent2.setAction("cn.lixyz.broadcasttest.MainActivity");
sendOrderedBroadcast(intent2, null);
break;
}
}
}
MainActivity.java
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter android:priority="100">
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver>
<receiver android:name=".MySecondReceiver">
<intent-filter android:priority="200">
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver> <receiver android:name=".MyThirdReceiver">
<intent-filter android:priority="300">
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter> </receiver>
</application>
</manifest>
AndroidManiFest.xml
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/12.
*/
public class MyThirdReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MyThirdReceiver广播接收器接收到广播了");
}
}
MyThirdReceiver.java
运行结果
可见,有序广播同样优先级越高,越先接收到消息
再修改一下MyThirdReceiver.java
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/12.
*/
public class MyThirdReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MyThirdReceiver广播接收器接收到广播了");
abortBroadcast();
}
}
MyThirdReceiver.java
点击多次按钮,运行结果为:
可见有序广播是可以阻断广播的
下面演示一下有序广播的值传递
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.lixyz.broadcasttest"> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"> <activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity> <receiver android:name=".MyFirstReceiver">
<intent-filter android:priority="300">
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver>
<receiver android:name=".MySecondReceiver">
<intent-filter android:priority="200">
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter>
</receiver> <receiver android:name=".MyThirdReceiver">
<intent-filter android:priority="100">
<action android:name="cn.lixyz.broadcasttest.MainActivity" />
</intent-filter> </receiver>
</application>
</manifest>
AndroidManifest.xml
package cn.lixyz.broadcasttest; import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText; public class MainActivity extends Activity { private EditText editText;
private IntentFilter intentFilter;
private MySecondReceiver mySecondReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); } //设置两个按钮的点击事件
public void doClick(View view) {
switch (view.getId()) {
case R.id.button1:
Intent intent = new Intent();
intent.setAction("cn.lixyz.broadcasttest.MainActivity");
intent.putExtra("data", "这是广播信息");
sendBroadcast(intent);
break;
case R.id.button2:
Intent intent2 = new Intent();
intent2.setAction("cn.lixyz.broadcasttest.MainActivity");
editText = (EditText) findViewById(R.id.editText);
String str = editText.getText().toString();
intent2.putExtra("data", str);
sendOrderedBroadcast(intent2, null);
break;
}
}
}
MainActivity
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log; /**
* Created by LGB on 2015/9/11.
*/
public class MyFirstReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MyFirstReceiver广播接收器接收到了广播,广播内容是:" + intent.getStringExtra("data"));
}
}
MyFirstReceiver.java
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log; /**
* Created by LGB on 2015/9/11.
*/
public class MySecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d("TEST", "MySecondReceiver广播接收器接收到广播了,广播内容是:" + intent.getStringExtra("data"));
String str = "MySecondReceiver新增内容";
Bundle bundle = getResultExtras(true);
bundle.putString("data", intent.getStringExtra("data"));
bundle.putString("data2", str);
setResultExtras(bundle); }
}
MySecondReceiver.java
package cn.lixyz.broadcasttest; import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log; /**
* Created by LGB on 2015/9/12.
*/
public class MyThirdReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = getResultExtras(true);
String data = bundle.getString("data");
String data2 = bundle.getString("data2");
Log.d("TEST", "MyThirdReceiver广播接收器接收到广播了,广播内容是:" + data + data2);
}
}
MyThirdReceiver.java
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity"> <EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入您要广播的消息" /> <!-- 设置一个发送普通广播的按钮 -->
<Button
android:id="@+id/button1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="doClick"
android:text="发送普通广播" /> <!-- 设置一个发送有序广播的按钮 -->
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:onClick="doClick"
android:text="发送有序广播" /> </LinearLayout>
activity_main.xml
运行结果为: