为了容易理解,可以将广播代入到事件模型中,发送广播消息看做是触发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. pygame学习笔记(2)——从画点到动画

    转载请注明:@小五义 http://www.cnblogs.com/xiaowuyi 1.单个像素(画点)利用pygame画点主要有三种方法:方法一:画长宽为1个像素的正方形 #@小五义 http:/ ...

  2. QtCreator源码分析—2.启动主程序(4篇)

    QtCreator采用插件体系结构.主程序启动插件管理器(PluginManager),再通过插件管理器加载其插件,QtCreator的所有功能均使用插件实现. 我们先来分析主程序对插件管理器的主要操 ...

  3. Majority Number III

    Given an array of integers and a number k, the majority number is the number that occursmore than 1/ ...

  4. crosses initialization of “XXX” 的问题

    在switch-case中定义了变量,用g++编译的时候报错crosses initialization of “XXX” ,在网上一查,说是gcc要求变量的定义不能位于goto之后 将变量定义放在s ...

  5. linux下安装java jdk

    第一步:查看java对应版本               yum search java 我自己装的是1.8版本的java包 第二步:装java包 yum install java-1.8.0-ope ...

  6. BZOJ3083 遥远的国度(树链剖分+线段树)

    考虑暴力树剖.那么修改路径和查询子树最小值非常简单. 对于换根当然不能真的给他转一下,我们只记录当前根是哪个.对于查询,如果查询点不在当前根到原根的路径上,显然换根是对答案没有影响的:如果是当前根,答 ...

  7. 五种并发包总结ConcurrentHashMap CopyOnWriteArrayList ArrayblockingQueue

    五种并发包总结 1.常用的五种并发包 ConcurrentHashMap CopyOnWriteArrayList CopyOnWriteArraySet ArrayBlockingQueue Lin ...

  8. GPU并行编程小结

    http://peghoty.blog.163.com/blog/static/493464092013016113254852/ http://blog.csdn.net/augusdi/artic ...

  9. 【题解】JSOI2009球队收益 / 球队预算

    为什么大家都不写把输的场次增加的呢?我一定要让大家知道,这并没有什么关系~所以 \(C[i] <= D[i]\) 的条件就是来卖萌哒?? #include <bits/stdc++.h&g ...

  10. swift网络数据请求方法

    搭建一个apache服务器,用php编写一个返回给客户端请求数据的脚本 <?php // header("Content-type:text/html;charset=utf-8&qu ...