为了容易理解,可以将广播代入到事件模型中,发送广播消息看做是触发event,BroadcastReceiver是处理事件的回调逻辑。

广播这种模型中涉及到两个角色,就是广播的发送者和接收者,所以会涉及到如何发送和如何接收广播。

同时因为系统中可能会有很多的广播,为了不被乱七八糟的东西混淆视听,每个广播给它一个action,这样广播接收器就可以使用action来过滤出自己感兴趣的广播,也可以将action看做是一个频道,每个广播都有一个自己的频道,广播接收器为了不串台就只收听自己感兴趣的一个或多个频道。

广播的分类

按作用域划分

广播按照作用域可以分为全局广播和本地广播。

全局广播的作用域超出此应用程序,发出的全局广播可以被所有应用程序接收,也可以接收其它应用程序发出的全局广播。

 

本地广播就是作用域限定在本应用中,发出的广播只能在应用内部传递,同样也只接收应用内部的本地广播。

这样是因为我们在自己的应用内传递关键信息,如果不限制作用域的话就有可能被其它应用收到,这样很容易引起安全性问题。

按接收顺序划分

按接收顺序分为普通广播(无序广播)和有序广播。

普通广播:使用Context#sendBroadcast(Intent intent)发送,普通广播是异步的(所以又叫无序广播),广播接收者的顺序无法确定,因为是异步的,所以不能够被停止掉,这种方式保证每个广播接收器都能够接收到广播,并且收到的就是原始的广播信息(因为从发送者直接到接收者,中间没有经过其它人)。

 

有序广播:使用Context#sendOrderedBroadcast方法发送,所有要接收此条广播的接收器要排队接收,类似于一条处理链,链上的每个接收器都可以选择从这里终止不再向下传递,所以有序广播是可以被终止的,不保证每个接收器都一定能够接收到广播,同样的,因为链式向后面传递,那么前面的接收者也可以对广播修改后再往下传递,所以此方式除链上的第一个节点外其他接收器收到的数据都有可能被篡改过。另外既然有序广播接收的时候需要排队,那么排队的依据是什么呢,就是在注册的时候intent-filter的android:priority来决定。

粘性广播:使用Context#sendStickyBroadcast发送,粘性广播被发送后,最后一个粘性广播将被粘在系统上,在一段时间内如果有新的广播接收器注册的话那么它将能够接收到这个被粘住的广播,尽管在这个广播被发送的时候它还没有注册,但就是粘了一下收到了。

发送广播

发送全局广播

sendBroadcast()方法第一个参数接收一个Intent,第二个参数是与权限相关的字符串。

发送全局无序广播: Context#sendBroadcast

发送全局有序广播: Context#sendOrderedBroadcast

Intent intent = new Intent("foo.BAR");
sendOrderedBroadcast(intent, null);

发送本地广播

本地广播使用LocalBroadcastManager来管理。

发送本地有序广播:LocalBroadcastManager.getInstance(this).sendBroadcast

发送本地无序广播:LocalBroadcastManager.getInstance(this).sendBroadcastSync

接收广播

接收广播的套路

1. 要接收广播需要创建一个类继承android.content.BroadcastReceiver,并在其onReceive方法中实现对广播事件的处理逻辑

2. 然后将创建的广播接收器注册,注册的方式有静态注册(AndroidManifest.xml)和动态注册(Java代码)两种,如果接收广播需要权限的话还要声明使用相应权限。

3. 然后当有符合条件的广播到来的时候会自动调用广播接收器的onReceive方法

静态注册和动态注册的区别

静态注册:在应用程序关闭后,当有广播来临时仍然能够接收到被调用,应用场景是需要时刻监听广播(即使在应用程序退出后)。

动态注册:短命鬼,广播接收器的生命周期跟随组件在变,应用场景是只在某段时间才需要监听广播。

拦截广播

要在有序广播接收器的处理链上拦截广播,在onReceive方法中调用aboryBroadcast即可拦截广播不再向后传递而是从此处停止。

@Override
public void onReceive(Context context, Intent intent) {
boolean foo = intent.getBooleanExtra("foo", false);
if (foo) {
abortBroadcast();
}
}

本地广播的注册

本地广播只能通过动态注册的方式。因为静态广播主要是为了让应用程序在不启动的时候也能够接收到广播,而本地广播因为都是在应用程序内传递的,所以本地广播都是在应用启动时才有的,所以本地广播不能使用静态注册的方式。

注册本地广播接收器: LocalBroadcastManager.getInstance(this).registerReceiver();

取消注册本地广播接收器:LocalBroadcastManager.getInstance(this).unregisterReceiver();

onReceive的耗时操作

onReceive的执行时间最多只有10秒钟,当超过10秒的时候将会报错,所以不应该在其中执行耗时的方法,正确的方式是启动一个Service执行耗时操作。

静态注册

在AndroidManifest.xml文件中注册广播接收器:

<!-- 静态注册广播接收器 -->
<receiver
android:name=".FooBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="1000">
<action android:name="cc11001100.foo" />
</intent-filter>
</receiver>

name: 继承了BroadcastReceiver的广播接收器

enable: 是否启动此接收器

exported:是否允许接收此应用以外的广播,如果为false表示只接收此应用内的广播,即本地广播接收器,否则为全局广播接收器。

intent-filter:增加action过滤广播,其属性priority用于设置此广播接收器的优先级,范围是[-1000, 1000]

action ,系统中会有很多乱七八糟的广播,这个是用来过滤只接收自己需要的广播,intent-filter下可以有多个action

对于静态注册,如果使用的是Android Studio的话,可以通过:

创建的类会继承BroadcastReceiver并且自动在AndroidManifest.xml文件中静态注册。

下面是一个静态注册的例子:

广播接收器:

package cc11001100.androidstudy_005;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast; /**
* @author CC11001100
*/
public class FooBroadcastReceiver extends BroadcastReceiver { @Override
public void onReceive(Context context, Intent intent) {
int value = intent.getIntExtra("foo", 0);
Toast.makeText(context, Integer.toString(value), Toast.LENGTH_LONG).show();
Log.i("FooBroadcastReceiver", "onReceive: " + value);
} }

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cc11001100.androidstudy_005.MainActivity"> <Button
android:id="@+id/sendBroadcastBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Broadcast"
tools:ignore="MissingConstraints"
android:onClick="sendBroadcastBtn"/> </android.support.constraint.ConstraintLayout>

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cc11001100.androidstudy_005"> <application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
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=".FooBroadcastReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="cc11001100.foo" />
</intent-filter>
</receiver> </application> </manifest>

MainActivity:

package cc11001100.androidstudy_005;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View; import java.util.Random; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getName(); @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
} /**
* 绑定的按钮事件,发送广播事件供接收
*/
public void sendBroadcastBtn(View view) {
Intent intent = new Intent();
intent.setAction("cc11001100.foo");
intent.putExtra("foo", new Random().nextInt());
sendBroadcast(intent);
Log.i(TAG, "sendBroadcastBtn: ");
}
}

前面提到过静态注册的广播接收器即使在应用退出后仍然可以接收广播,那么有没有办法停掉它呢?

PackageManager

动态注册

在程序运行的时候使用Java代码注册,称为动态注册,动态注册要记得在组件的onDestroy中unregisterReceiver广播接收器。

动态注册的步骤:

1. 定义广播接收器类

2. 创建IntentFilter,通过setAction设置所要接收的广播

3. 使用Context#registerReceiver(BroadcastReceiver receiver, IntentFilter filter)方法注册接收器

下面是一个动态注册的例子,广播接收器,对接收到的广播做处理:

package cc11001100.androidstudy_005;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast; /**
* @author CC11001100
*/
public class FooBroadcastReceiver extends BroadcastReceiver { @Override
public void onReceive(Context context, Intent intent) {
int value = intent.getIntExtra("foo", 0);
Toast.makeText(context, Integer.toString(value), Toast.LENGTH_LONG).show();
Log.i("FooBroadcastReceiver", "onReceive: " + value);
} }

布局文件,放一个按钮,每单击一次就发送一个广播供广播接收器接收:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cc11001100.androidstudy_005.MainActivity"> <Button
android:id="@+id/sendBroadcastBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Send Broadcast"
tools:ignore="MissingConstraints"
android:onClick="sendBroadcastBtn"/> </android.support.constraint.ConstraintLayout>

MainActivity:

package cc11001100.androidstudy_005;

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.util.Log;
import android.view.View; import java.util.Random; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getName();
private FooBroadcastReceiver fooBroadcastReceiver; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); // 动态注册广播接收器
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("cc11001100.foo");
fooBroadcastReceiver = new FooBroadcastReceiver();
registerReceiver(fooBroadcastReceiver, intentFilter);
} @Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(fooBroadcastReceiver);
} /**
* 绑定的按钮事件,发送广播事件供接收
*/
public void sendBroadcastBtn(View view) {
Intent intent = new Intent();
intent.setAction("cc11001100.foo");
intent.putExtra("foo", new Random().nextInt());
sendBroadcast(intent);
Log.i(TAG, "sendBroadcastBtn: ");
}
}

.

Android笔记之广播的更多相关文章

  1. Android学习笔记(广播机制)

    1.Android的广播机制介绍 收听收音机也是一种广播,在收音机中有很多个广播电台,每个广播电台播放的内容都不相同.接受广播时广播(发送方)并不在意我们(接收方)接收到广播时如何处理.好比我们收听交 ...

  2. Android学习笔记_19_广播接收者 BroadcastReceiver及其应用_窃听短信_拦截外拨电话

    一.广播接收者类型: 广播被分为两种不同的类型:“普通广播(Normal broadcasts)”和“有序广播(Ordered broadcasts)”. 普通广播是完全异步的,可以在同一时刻(逻辑上 ...

  3. android菜鸟学习笔记26----Android广播消息及BroadcastReceiver

    1.广播类型: Android中的广播有两种类型:标准广播和有序广播.其中,标准广播是完全异步发送的广播,发出之后,几乎所有的广播接收者都会在同一时刻收到这条广播消息,因而,这种类型的广播消息是不可拦 ...

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

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

  5. 我的Android笔记--我对安卓系统的一些了解

    敲了这么长时间代码,记录一下我对Android的一些概念,下面大部分内容来源自网络资料和官方给的文档.     1,Android操作系统的核心属于Linux的一个分支,具有典型的Linux调度和功能 ...

  6. Android开发之广播

    广播是Android开发中的一个重要的功能,在Android里面有各式各样的广播,比如:电池的状态变化.信号的强弱状态.电话的接听和短信的接收等等,现在给大家简单介绍一下系统发送.监听这些广播的机制. ...

  7. android之自定义广播

    布局文件 点击按钮发送广播 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmln ...

  8. Android之旅---广播(BroadCast)

    什么是广播 在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制.我们拿广播电台来做个比方.我们平常使用收音机收音是这样的:许许多多不同的广播电台通过特定的频率来发送他们 ...

  9. Android笔记——Android中数据的存储方式(二)

    我们在实际开发中,有的时候需要储存或者备份比较复杂的数据.这些数据的特点是,内容多.结构大,比如短信备份等.我们知道SharedPreferences和Files(文本文件)储存这种数据会非常的没有效 ...

随机推荐

  1. xshell 常用快捷键

    1.连接mysql数据库mysql -uroot -p -h127.0.0.1 -P3306 2.列出所有sessionshow full processlist; 3.查看20条执行时间最长的SQL ...

  2. 斑马条码打印机GK888T打印标签是间隔的 ,不是连续的

    有间断的标签纸和连续的标签纸是两种不同的纸张类型, 打印机的标签感应器需要工作在不同的模式来跟踪感应它们. 打印机正确感应纸张才不会红灯闪烁,打印的内容才按文件设计打印到标签的对应位置上. 所以要在驱 ...

  3. VIM 命令收藏

    1.vim#在命令行中输入vim,进入vim编辑器2.i#按一下i键,下端显示 --INSERT--#插入命令,在vim中可能任意字符都有作用3.Esc#退出i(插入)命令进行其它命令使用4.:r f ...

  4. ACdream1092

    题意是给出某个地鼠的出现位置以及出现时间,人有一个移动速度,求此人最多可以打多少个地鼠? 我们根据时间把所有的地鼠排序,如果两个地鼠之间的距离不超过时间只差与速度的乘积,那说明打完上一只地鼠还可以打到 ...

  5. [CF671E] Organizing a Race

    题目大意 有\(n\)个加油站排成一行,编号为\(1\sim n\) ,\(i\)与\(i+1\)间有一条长为\(w_i\)千米的道路. 一辆汽车在经过加油站\(i\)时会得到\(g_i\)升汽油 , ...

  6. Vue里边接口访问Post、Get

    原文地址: http://www.cnblogs.com/JimmyBright/p/7356502.html 通常js里面都用ajax来和服务器交换数据,Vue里边当然也可以用ajax,ajax是基 ...

  7. Container With Most Water - LeetCode

    目录 题目链接 注意点 解法 小结 题目链接 Container With Most Water - LeetCode 注意点 没什么好注意的... 解法 解法一:暴力求解,假设任意两个端点会是最佳答 ...

  8. shell实践(一)---判断远程服务器中文件是否存在

    1.判断一个文件的常见形式为 if [ -f filename ]  #此处有-e和-f的区别 注意: 1)中括号之间的空格: 2)filename最好是绝对路径,在判断远程服务器中文件是否存在时尤为 ...

  9. java多线程 -- 同步鎖

    为了解决多线程安全问题在 Java 5.0 之前,协调共享对象的访问时可以使用的机制只有 synchronized 和 volatile .Java 5.0 后增加了一些新的机制,但并不是一种替代内置 ...

  10. shell 变量匹配

    ${var%pattern} ${var%%pattern} ${var#pattern} ${var##pattern} ${var%pattern},${var%%pattern} 从右边开始匹配 ...