广播机制
1.广播机制概述
1.1生活中的广播机制
1.显示生活中的广播就比如说村里的大喇叭,车上的收音机接收的广播FM广播,学校里的校园广播都是常见的广播,安卓中的广播和生活中的广播是十分类似的。
1.2广播特点
发送者
- 多种广播方式
- 实时
- 不关心是不是被接收
接收者
- 接收方式多种
- 实时
- 不关心谁发的
- 接收到广播后需要指定相应的操作
1.3安卓中的广播机制
白话:安卓中的事件是由事件引起的,由操作系统进行处理,并发送对应的广播,但是产生什么样的反应以及动作是由广播接收者来进行实现。
1.安卓中的广播机制的简介?
(1)Android系统中的广播跟传统现实生活中的电台广播有些相似之处。之所以叫做广播,就是因为它只负责“说”而不管“听不听”,也就是不管接收方如何处理。另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收。
(2)广播的发送者和接收者事先是不需要知道对方的存在的,这样带来的好处便是:系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。
(3)安卓中的广播其实就是操作系统发出的各种事件。
- 发送短信有一个短信事件
- 接收短信,接收电话有对应的电话事件和接收短信的事件
- 拍摄照片有对应的拍摄的事件
对于上面的事件,对于操作系统来说,会监听对应的事件并产生对应的广播事件,向所有的广播接收者发送并广播这些事件。
对于广播接收者是不是关系这些事件,以及如何进行处理这些事件对于广播接收者来说是由接收对象自己进行决定的。
(4)例如一个生活中的实例:
如:手机接到一条短信,就会产生一个收到短消息的事件。接到一个电话,就会产生一个接到电话的事件。拍摄照片后就会产生一个拍摄照片的事件。在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,比如电池的使用状态,电话的接收和短信的接收都会产生一个广播。Android系统内部产生这些事件后广播这些事件,至于广播接收对象是否关心这些事件,以及它们如何处理这些事件,都由广播接收对象自己决定。
1.4安卓中常见的广播机制
1.系统中内置的一些广播机制,都是系统内部的。
- Android系统中内置了很多系统级别的广播,如:
- 电池的状态(如:电量不足)
- 短信的接收和发送
- 电话的接听和拨打
- 系统闹钟
- 系统垃圾文件占用内存过多
- 短信拦截
- 内存存储空间满了
- 插入电脑中
- 等等,都会产生一条广播。
1.5如何监听安卓中的广播
需要使用指定的控件BroadCastReceiver去监听应用程序或者是系统的发出的广播。
1.实现监听的方式?
- 为了监听这些广播事件,Android提供了一个BroadcastReceiver组件,该组件可以监听来自系统或应用程序的广播。BroadcastReceiver是用来过滤接收并响应广播的一类组件。
1.6系统广播
总之,系统发出的广播就是全局的广播,但是对于app或者第三方的应用发出的广播就是自定义广播。
1.什么是系统广播?
- Android系统通过发出广播消息来通知各应用组件一些系统事件,如电量低或者充足,刚启动完,插入耳机,输入法改变等,每个APP都会收到,我们通常称之为系统广播或系统消息。
- 第三方应用也可以广播消息,我们称为自定义广播或自定义消息。
1.7安卓中广播机制的原理图
要使用BroadcastReceiver接收其它应用程序发出的广播,先要在本应用中创建BroadcastReceiver并进行注册。
1.8广播机制运行的机理
运行的机理就类似一种匹配。广播发出者会发出广播,有一个intent的action属性。
接收者和发送者对应的就是action的值,对应上的就是成功接收到的,接收到的话就会触发onReceive方法进行处理相关的操作。
注意:广播的内容就是Intent对象信息。
1.运行机理?
- BroadcastReceiver的运行机理比较简单,当系统或其他应用程序发送广播时,所有已经注册的BroadcastReceiver的应用程序就会检查注册时的IntentFilter里的Action是否与发送广播时的Intent的Action相匹配,若匹配则会调用BroadcastReceiver的onReceive()方法进行处理,所以主要工作是对BroadcastReceiver里的onReceive()方法的实现。
注意:一定要先进行注册,然后进行相应的处理操作。
2.BroadCastReceiver开发过程
2.1BroadCastReceiver
本质就是一个事件监听器,和学的button等的事件监听器是类似的东西,只不过作用的范围是不同的。
系统广播只有一个接收的方法。
1.简介:四大组件之一,本质就是一个系统级别的事件监听器,可以监听全局的广播事件。前面介绍的各种OnXxxListener只是程序级别的监听器,这些监听器运行在指定程序所在进程中,当程序退出时,监听器也就随之关闭了。但BroadcastReceiver属于系统级别的监听器,它拥有自己的进程,只要存在与之相配的Intent被广播出来,BroadcastReceiver总会被激发。
2.2系统广播-创建和使用
1.创建的步骤
- 创建一个类继承BroadcastReceiver,实现onReceive()方法
- 注册BroadcastReceiver
- 构建IntentFilter标签,设置其Action属性
- 系统产生事件,发送广播,检查每一个BroadcastReceiver的intent-filter里的action是否和第3步里的action匹配,如果匹配,生成相应的BroadcastReceiver对象,且调用其onReceive()方法,如果不匹配,则不生成Receiver对象。
2.3本地广播-创建和使用
对于本地广播多了一个发送的方法
BroadcastReceiver的创建及使用步骤(本地广播):
- 创建一个类继承BroadcastReceiver,实现onReceive()方法
- 注册BroadcastReceiver
- 应用中构建Intent对象,设置其Action属性
- 利用sendBroadcast(Intent)方法发送广播
- 系统产生事件,发送广播,检查AndroidManifest.xml里注册每一个BroadcastReceiver的intent-filter里的action是否和第4步里的action匹配,如果匹配,生成相应的BroadcastReceiver对象,且调用其onReceive()方法,如果不匹配,则不生成Receiver对象。
2.4BroadCastReceiver小结
- 自定义BroadcastReceiver
- 注册BroadcastReceiver
- 动态注册
- 静态注册
- 发送广播
- 标准广播的发送
- 有序广播的发送
- 本地广播
3.BroadCastReceiver的两种注册方式
白话:静态注册就是在标签中进行注册,动态注册就是在代码中进行注册的方式。
1.为什么要进行注册?注册的作用是什么?
注册的作用:
- 1、通知Android操作系统存在一个BroadcastReceiver对象,等待接收事件
- 2、在Android操作系统里有很多BroadcastReceiver,不同BroadcastReceiver处理的事件不同,例如:有的BroadcastReceiver是用来处理接收短消息的,有的是用来处理接电话的,有的是用来处理地图的,如何指明某个BroadcastReceiver对象处理哪个事件?这个receiver应该接收什么类型的事件是由Intent-filter里的Action属性来决定的。
1、使用代码进行指定。
2、在AndroidManifest.xml文件中配置。
3.1静态注册
在AndroidManifest.xml中注册;
3.2动态注册
创建IntentFilter对象设置action
创建自定义的广播接收对象
调用系统中的registerReceiver方法将创建的广播接收对象和IntentFilter对象传入进去就可以了。
在代码中进行注册
- 创建IntentFilter对象,添加其action属性
- 注册BroadcastReceiver:
Context中有如下方法:
public Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter)
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
MyBroadCastDemo receiver = new MyBroadCastDemo();
registerReceiver(receiver, filter);
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
MyBroadCastDemo receiver = new MyBroadCastDemo();
registerReceiver(receiver, filter);
3.3IntentFilter对象
1.简介:IntentFilter类用于匹配Intent中的动作(Action)、类别(Category)和数据(Data)等属性,对适合接收该Intent的组件进行匹配和筛选的机制。
每个 IntentFilter描述该组件所能响应Intent请求的能力——组件希望接收什么类型的请求行为,什么类型的请求数据。
2.常见的方法如下:
3.4案例-监听网络断开的连接情况
参考博客:
https://blog.csdn.net/gongzhiyao3739124/article/details/52818311
注意事项,采用的安卓的版本最好是5版本的不要很高,很高的安卓的版本是不适合启动的。
1.案例背景:
现在,Android手机作为市场占有量最大的移动设备,拥有着无数的需要连接网络的App,同时人们也渐渐不能离开需要网络的生活,相信大家都知道,在一些IMApp,类似于QQ,Wechat等通信工具中,并不需要很大的网络流量,普通的GPRS数据流量就可以应付自如。但是,当需要在线收看视频或者下载大型软件游戏的时候,在Wi-Fi连接下会有比较好的体验。作为开发者,在开发对网络连接非常敏感的App时,我们就需要对当前的网络做一定的判定和处理了。
总之一句话:网络很重要,没有网络啥也干不成。
2.ConnectivityManager用于监听网络状态的好坏。
3.编写监听网络好坏的测试文件
对于移动设备来说,联网类型和状态的改变是非常频繁的,所以监视网络状态连接的就变得非常必要了。Android系统在监测网络连接变化方面使用的是发送广播的方式。每当网络连接状态发生了变化,ConnectivityManager会广播一个CONNECTIVITYACTION("android.net.conn.CONNECTIVITYCHANGE")。可以在清单文件中注册一个广播接收器接收网络连接变化的广播。
4.代码如下
- 权限开启
- 静态注册
- BroadCastReceiver类的实现
权限开启
<!--开启权限-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
静态注册
<receiver android:name=".ContentChangeReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
BroadCastReceiver类的实现
package com.example.app2;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.widget.Toast;
//监听网路的好坏情况
public class ContentChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
boolean success = false;
//获得网络连接服务
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
//获取wifi连接状态
NetworkInfo.State state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
//判断是否正在使用wifi网络
if (state == NetworkInfo.State.CONNECTED) {
success = true;
}
//获取GPRS状态
state = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState();
//判断是否在使用GPRS网络
if (state == NetworkInfo.State.CONNECTED) {
success = true;
}
//如果没有连接成功
if(!success){
Toast.makeText(context,"当前网络无连接",Toast.LENGTH_SHORT).show();
}
}
}
3.5案例:创建一个监听开机的小程序
1.权限开启
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2.receiver配置
- 需要在activity中进行配置设置需要监听的action的值
<receiver android:name="com.example.app2.ContentChangeReceiver"
android:exported="true">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.HOME" />
</intent-filter>
</receiver>
3.创建自定义的实现类吗,继承BroadcastReceiver类,实现其中方法。
子类的方法的代码如下。
//监听手机的开机事件
public class ContentChangeReceiver extends BroadcastReceiver {
private static final String TAG = "BootBroadcastReceiver";
private static final String ACTION_BOOT = "android.intent.action.BOOT_COMPLETED";
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_BOOT)) {
System.out.println("开机了");
Toast.makeText(context, "开机了", Toast.LENGTH_SHORT).show();
}
}
}
Activity中是不需要任何的配置的,就可以进行实现的。
实现的效果图如下:
3.6常见的系统权限和action
注意调用系统中不同的广播需要开启系统中不同的权限,原因就是因为安卓系统是基于Linux操作系统的。
常见的系统中的action的值
如果一次监听两个的话需要写两个Intent-filter。
4.BroadCastReceiver类别
不仅可以接收广播,也是可以进行广播发送。
4.1标准广播
其实就是最基本的一种类型
1.简介:完全异步执行的广播,发出广播后,所有的广播接收器几乎会在同一时刻收到这条广播通知。
4.2标准广播发送
Intent intent=new Intent();
intent.setAction("android.intent.action.MY_BROADCAST");
intent.putExtra(“name”,”张三”);
intent.putExtra("phone", “13688625478”);
intent.putExtra("email", “android@126.com”);
sendBroadcast(intent);
标准广播的发送如果有多个BroadcastReceiver则按照Manifest.xml中注册顺序调用
步骤:
- 广播的内容在Intent中,然后调用Context的sendBrodcast方法
- 满足条件的所有的Broadcast都会执行onReceive方法进行处理响应
- 发送广播的代码如下:其实和原先学过的activity是类似的。
发送广播:
4.3顺序广播
1.也叫做有序广播,一个时间点只能允许一个广播进行接收的。同步执行的一种广播,同一时刻只有一个广播接收器能收到,这个广播接受者的逻辑执行完后,才会传递到下一广播接受者。
2.图示:
- 会按照优先级别依次进行接收
- 系统默认级别:android:priority="5"
- 取值范围:-1000到1000,数越大,优先级越高
- 优先级别声明方法
- 元素的android:priority属性中设置
- 在IntentFilter对象的setPriority()设置消息传递效率较低
4.4有序广播的发送
1.步骤:有序广播:Ordered Broadcast的接收者将按预先声明的优先级一次接收Broadcast,如:A的优先级高于B,B的优先级高于C,那么广播事件先传给A,再传给B,最后传给C。Ordered Broadcast接收者可以终止Broadcast Intent的传播, Broadcast Intent的传播一旦终止,后面的接收者就无法收到Broadcast。另外, Ordered Broadcast的接收者可以将数据传递给下一个接收者,如:A得到广播事件后,可以往它的结果对象中存入数据,当广播事件传给B时,B可以从A的结果对象中得到A存入的数据。
2.Context发送广播的方法:
- sendOrderedBroadcast(Intent intent,String str)
发送广播的方法区别于标准广播发送的方法。有序广播的发送需要设置优先级别,但是标准广播的发送是不需要设置广播的顺序的。
- str:权限参数,如果为null则表示不要求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。
- 从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有拦截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限
3.如何进行定义?
4.如何发送?
5.如何使用该权限?
4.5有序广播的获取
1.如何获取?
- 下一个接收者通过getResultExtras()可以获取上一个接收者存入的数据
public final Bundle getResultExtras(boolean makeMap),makeMap如果为true,如果当前的Bundle为null,将创建一个空的Bundle对象;否则需要准备好接收一个空Bundle对象。false:你需要准备好接收一个空Bundle
2.当前接收者如何设置刚刚接收到的数据?
- 优先接收到广播的Broadcastreceiver广播接收者可以通过setResultExtras(Bundle)方法将一个Bundle对象设置为结果集对象,传给下一个接收者。public final void setResultExtras(Bundle extras)
4.6有序广播的中断
拦截当前的广播,让其不能继续往下的传递下去。
- abortBroadcast()
4.7有序广播和标准广播的区别
对于普通广播来说消息传递的效率是最高的。
5.BroadCastReceiver生命周期
5.1常见的生命周期
1.生命周期:每次广播事件发生后,系统就会创建对应的BroadcastReceiver实例对象,并自动触发它的onReceive()方法,onReceive()方法执行完后,BroadcastReceiver的实例对象就会被销毁。
2.生命周期图示:BroadcastReceiver的生命周期很简单拿,只有一个基本的方法,调用完就会执行销毁的方法。
3.注意事项:
总之,广播监听本身就是实时的东西,不能加入太多耗时的东西,不然的话会严重降低系统的性能的。
onReceive方法中不能加入比较耗时的操作,否则系统会认为程序无响应,不要在广播里添加过多逻辑或者进行任何耗时操作,因为在广播中是不允许开辟线程的, 当onReceiver( )方法运行较长时间(超过10秒)还没有结束的话,那么程序会报错(ANR), 广播更多的时候扮演的是一个打开其他组件的角色,比如启动Service,Notification提示, Activity等。如果需要完成一项比较耗时的工作,可以通过发送Intent给Activity或Service,由Activity或Service来完成。
5.2标准广播案例
会按照注册的顺序依次执行广播的监听的。
1.广播发出者:设置广播的内容,设置actiond的值,注册接收广播的组件。
广播发出者的Java代码如下
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import androidx.appcompat.app.AppCompatActivity;
//广播发出者
/*
* 注意:因为本地广播不能静态注册,所以只能采取的方式是动态注册的方式
* */
public class MainActivity extends AppCompatActivity {
// 1.定义控件元素
Button btn_send;//点击按钮发出广播
EditText editText;//输入要广播的内容
String s;//保存当前要广播的内容
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//2.获取控件元素
initView();
//3.动态注册本地广播
btnSendListener();
}
// 方法:获取控件元素
public void initView(){
btn_send=findViewById(R.id. btn_send);
editText=findViewById(R.id.editext);
}
// 方法:设置发送广播的Button的事件监听
public void btnSendListener(){
//设置事件监听
btn_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
s=editText.getText().toString();//获取广播发送的内容
//用于动态注册的信息
IntentFilter filter = new IntentFilter("android.intent.action.MY_BROADCASTRECEIVER");
//注册第一个
FirstReceiver receiver = new FirstReceiver();
registerReceiver(receiver, filter);
//注册第二个
SecondReceiver secondReceiver = new SecondReceiver();
registerReceiver(secondReceiver, filter);
//设置需要发送的消息
Intent intent=new Intent();
//设置全限定名
intent.setAction("android.intent.action.MY_BROADCASTRECEIVER");
intent.putExtra("msg",s);
sendBroadcast(intent);
}
});
}
}
2.广播发出者的布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<!-- 广播信息-->
<EditText
android:id="@+id/editext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入要广播的内容"
android:textSize="30dp"
android:textColor="@color/black"
/>
<!-- 发送广播的按钮-->
<Button
android:layout_gravity="center"
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发送广播"
android:textSize="25dp"
/>
</LinearLayout>
3.第一个广播接收者代码
//第一个用户监听广播的类
public class FirstReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");//获取广播传递的消息
Toast.makeText(context, "第一广播接收者:"+msg, Toast.LENGTH_SHORT).show();
}
}
4.第二个广播接收者代码
public class SecondReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String msg = intent.getStringExtra("msg");
Toast.makeText(context, "第二广播接收者:"+msg, Toast.LENGTH_SHORT).show();
}
}
运行的效果图如下:
会根据注册的顺序依次进行显示广播的内容
5.3有序广播案例
注意事项,解决接收不到广播的方法,就是需给intent设置一个intent.setPackage的属性
1.包结构如下:
- 第一个是用于广播发送的
- 第2-4是用于广播接收的
2.广播发出者的代码如下:
第一种方式:采用动态注册的方法:
package com.example.app3order;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
/*
* 广播的发出者*
* */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 发送有序广播的事件监听的方法
public void send(View view) {
Toast.makeText(this, "有序广播已发送!", Toast.LENGTH_SHORT).show();
Intent intent=new Intent();
//定义广播事件类型
intent.setAction("com.example.app3order.MainActivity");
intent.setPackage("com.example.app3order");
MyBroadcastReceiverOne one=new MyBroadcastReceiverOne();
MyBroadcastReceiverTwo two=new MyBroadcastReceiverTwo();
MyBroadcastReceiverThree three=new MyBroadcastReceiverThree();
IntentFilter filter1=new IntentFilter("com.example.app3order.MainActivity");
IntentFilter filter2=new IntentFilter("com.example.app3order.MainActivity");
IntentFilter filter3=new IntentFilter("com.example.app3order.MainActivity");
filter1.setPriority(100);
filter2.setPriority(200);
filter3.setPriority(300);
registerReceiver(one,filter1);
registerReceiver(two,filter2);
registerReceiver(three,filter3);
// <action android:name="com.example.app3order.MainActivity"/>
//发送广播
sendOrderedBroadcast(intent,null);
}
}
第二种方式:采用静态注册的方法:
package com.example.app3order;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
/*
* 广播的发出者
* */
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 发送有序广播的事件监听的方法
public void send(View view) {
Toast.makeText(this, "有序广播已发送!", Toast.LENGTH_SHORT).show();
Intent intent=new Intent();
//定义广播事件类型
intent.setAction("com.example.app3order.MainActivity");
intent.setPackage("com.example.app3order");
sendOrderedBroadcast(intent,null);
}
}
3.广播接收者的代码类似:
public class MyBroadcastReceiverOne extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "第一个接收到了广播的消息!", Toast.LENGTH_LONG).show();
System.out.println("第一个接收到了广播的消息");
Log.i("广播","1");
}
}
//第三个用于接收广播的消息的
public class MyBroadcastReceiverThree extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "第三个接收到的广播消息!", Toast.LENGTH_LONG).show();
System.out.println("第三个接收到的广播消息");
Log.i("广播","3");
}
}
//第二个接收到了广播的消息
public class MyBroadcastReceiverTwo extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "第二个接收到的广播消息!", Toast.LENGTH_LONG).show();
System.out.println("第二个接收到的广播消息");
Log.i("广播","2");
}
}
效果图:接收广播的顺序。
6.本地广播
6.1本地广播简介
1.前面接触的广播都是全局广播,这同样意味着我们APP发出的广播,其他APP都会接收到,或者其他APP发送的广播,我们的APP也同样会接收到,这样容易引起一些安全性的问题,如:恶意程序脚本不断的去发送你所接收的广播!
Android中给我们提供了本地广播LocalBroadcastManager的机制,使用该机制发出的广播只会在APP内部传播,而且广播接收者也只能收到本应用发出的广播。
2.好处:更加高效更加安全但是不够共享。
- 1、因广播数据在本应用范围内传播,不用担心隐私数据泄露的问题。
- 2、不用担心别的应用伪造广播,造成安全隐患。
- 3、相比在系统内发送全局广播,它更高效。
6.2LocalBroadcastManager
1简介:LocalBroadcastManager是Android Support包提供了一个工具,用于在同一个应用内的不同组件间发送广播。
LocalBroadcastManager也称为局部通知管理器,这种通知的好处是安全性高,效率也高,适合局部通信。
2.用法:
使用LocalBroadcastManager管理广播的一些方法:
获取LocalBroadcastManager的实例对象:
static LocalBroadcastManager getInstance(Context context)
举例:
LocalBroadcastManager localBManager =
LocalBroadcastManager.getInstance( this ) ;
3.注册广播
和全局广播的区别在于现在的功能注册等方式变成了本地的注册的方式。
- 调用LocalBroadcastManager对象的registerReceiver()注册广播
- public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
举例:
MyBcReceiver localReceiver = new MyBcReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.jay.mybcreceiver.LOGIN_OTHER");
LocalBroadcastManager localBManager =
LocalBroadcastManager.getInstance( this ) ;
localBManager. registerReceiver(localReceiver, intentFilter);
4.发送广播?
- 调用LocalBroadcastManager对象的sendBroadcast()发送广播
- public boolean sendBroadcast(Intent intent)
发送广播的方法:
Intent intent = new Intent("com.jay.mybcreceiver.LOGIN_OTHER");
localBroadcastManager.sendBroadcast(intent);
5.取消注册的方法?
- 调用LocalBroadcastManager对象的unregisterReceiver ()取消注册
- public void unregisterReceiver(BroadcastReceiver receiver)
取消注册的方法如下:
localBroadcastManager.unregisterReceiver(localReceiver);
6.3注意事项
注意事项:
- 本地广播无法通过静态注册来接收
- 本地广播相比系统全局广播更加高效
6.4案例
像QQ一样,正在运行的QQ,如果我们用别的手机再次登陆自己的账号,前面这个是会提醒账户在别的终端登录,然后把我们打开的app都关掉,然后回到登陆页面。LoginActivity.java
注意:需要在模拟器中设置—应用-左上角— —打开应用信息—设置出现在其它应用上
注意:运行这个代码,需要在模拟器中设置—存储—内部共享存储空间—应用—找到该应用名(broadcastreceiverdemo)--左上角图标—打开应用信息—设置出现在其它应用上
案例源码地址:
1.项目结构
2.以下代码纯复制就可以。
MainActivity.java代码
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button forceOffline = (Button) findViewById(R.id.force_offline);
forceOffline.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE");
sendBroadcast(intent);
}
});
}
}
LoginActivity代码
//登录界面
public class LoginActivity extends BaseActivity {
private EditText accountEdit;
private EditText passwordEdit;
private Button login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
accountEdit = (EditText) findViewById(R.id.account);
passwordEdit = (EditText) findViewById(R.id.password);
login = (Button) findViewById(R.id.login);
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String account = accountEdit.getText().toString();
String password = passwordEdit.getText().toString();
// 如果账号是admin且密码是123456,就认为登录成功
if (account.equals("admin") && password.equals("123456")) {
Intent intent = new Intent(LoginActivity.this, MainActivity.
class);
startActivity(intent);
finish();
} else {
Toast.makeText(LoginActivity.this, "帐号或密码错误,请重新输入", Toast.LENGTH_SHORT).show();
}
}
});
}
}
BaseActivity代码:
public class BaseActivity extends AppCompatActivity {
private ForceOfflineReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
receiver = new ForceOfflineReceiver();
registerReceiver(receiver, intentFilter);
}
@Override
protected void onPause() {
super.onPause();
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
class ForceOfflineReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("下线警告");
builder.setMessage("你即将离线,请重新登录");
builder.setCancelable(false);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCollector.finishAll(); // 销毁所有活动
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent); // 重新启动LoginActivity
}
});
builder.show();
}
}
}
ActivityCollector代码
//管理所有的活动
public class ActivityCollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
public static void finishAll() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
activities.clear();
}
}
下面是布局文件的代码:
activity_login.xml是登录界面的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
android:layout_height="match_parent"
tools:context=".LoginActivity">
<!--用于登录的界面-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="账号:"
android:textSize="18sp" />
<EditText
android:id="@+id/account"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:orientation="horizontal">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="密码:"
android:textSize="18sp" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:inputType="textPassword" />
</LinearLayout>
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="Login" />
</LinearLayout>
activity_main.xml的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/force_offline"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="广播离线信息" />
</LinearLayout>
效果图:
点击OK之后返回到刚刚的登录界面。
7.小结
- BroadcastReceiver开发过程
- BroadcastReceiver的两种注册方式
- BroadcastReceiver的生命周期
- BroadcastReceiver类别
- BroadcastReceiver发送
- 本地广播