Android笔记(二十六) Android中的广播——BroadcastReceiver

为了方便进行系统级别的消息通知,Android有一套类似广播的消息机制,每个应用程序都可以对自己感兴趣的广播进行注册,这样该程序就只会接收自己所关心的广播内容,这些广播可能是来自于系统,也可能是来自于其他程序。

先区分两个概念:广播和广播接收器

广播是由系统或者程序发出,广播中包含某些数据或者信息。

广播接收器是一个继承了BroadcastReceiver的类,用来接收广播并做出相应响应或处理。

广播可以分为两种类型:有序广播、有序广播

标准广播是一种完全异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因为它们之间没有任何先后顺序可言,这种广播的效率会比较高,但同时也意味着它是无法被截断的

Android笔记(二十六) Android中的广播——BroadcastReceiver

如上图所示,每个人都代表一个广播接收器,在广播发出之后,每个人(广播接收器)都会接收到这条广播

有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够接收到,当这个广播接收器中的逻辑执行完毕之后,广播才会继续传递。所以有序广播是有先后顺序的,优先级高的广播接收器可以先接受到广播消息,并且还可以阻断正在传递的广播,如果截断,后面的接收器就无法收到了

Android笔记(二十六) 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:

Android笔记(二十六) Android中的广播——BroadcastReceiver

可以看到两个接收器都已经接收到了广播,这里显示的是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

这时候再看运行结果:

Android笔记(二十六) Android中的广播——BroadcastReceiver

会发现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

运行结果:

Android笔记(二十六) Android中的广播——BroadcastReceiver

可见,并没有阻断成功,所以普通广播不能阻断广播

         接下来我们修改一下两个接收器的注册方式:

将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

运行结果为:

Android笔记(二十六) Android中的广播——BroadcastReceiver

可见:普通广播中同级别的广播接收器,动态注册优先级高于静态注册。

         注意:动态注册的广播接收器,一定要记得取消注册,一般在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

将两个广播接收器都设置为静态注册,并且没有设置优先级,默认两个优先级相同,运行结果为:

Android笔记(二十六) Android中的广播——BroadcastReceiver

虽然运行结果是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

点击“发送有序广播”按钮,运行结果为:

Android笔记(二十六) Android中的广播——BroadcastReceiver

可见,有序广播下,相同优先级的广播接收器,动态注册的要优先于静态注册。

将两个接收器全部设置为静态注册,并设置优先级

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

运行结果

Android笔记(二十六) Android中的广播——BroadcastReceiver

可见,有序广播同样优先级越高,越先接收到消息

         再修改一下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

点击多次按钮,运行结果为:

Android笔记(二十六) Android中的广播——BroadcastReceiver

可见有序广播是可以阻断广播的

下面演示一下有序广播的值传递

<?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

  运行结果为:

Android笔记(二十六) Android中的广播——BroadcastReceiver

Android笔记(二十六) Android中的广播——BroadcastReceiver




上一篇:Android广播BroadcastReceiver 一


下一篇:开发iOS应用程序需要的工具和编程技术