广播(Broadcast)是一种广泛运用的在应用程序之间传输信息的机制,在 Android 里面有各种各样的广播,比如电池的使用状态,电话的接收和短信的接收都会产生一个广播,应用程序也可以接受广播并做出程序逻辑上的处理, 比如我们需要让应用程序开机自动启动,其实就是应用了广播的知识。
广播的三要素分别是:
1.广播(Broadcast) - 用于发送广播;
2.广播接收器(BroadcastReceiver) - 用于接收广播;
3.意图(Intent)-用于保存广播相关信息的媒介。
下面是我从网上搜集的一些广播的知识点:
1.普通广播
普通广播是完全异步的,可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高,但缺点是接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。
2.有序广播
有序广播是按照接收者声明的优先级别(声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000。也可以调用IntentFilter对象的setPriority()进行设置),被接收者依次接收广播。如:A的级别高于B, B的级别高于C,那么,广播先传给A,再传给B,最后传给C。A得到广播后,可以往广播里存入数据,当广播传给B时,nB可以从广播中得到A存入的数据。
3系统广播
系统广播是Android内置的广播,满足一定条件后系统会自动发送这个广播,不需要我们再定义发送,只需要用的时候接收就可以了,比如手机开机完成后会发出一条广播,电池的电量发生变化会发出一 条广播,时间或时区发生改变也会发出一条广播,摄像头按被按下会触发广播等等。
4自定义广播
自定义广播是用户可以自己定义发送一个广播,看到很多书籍都是这么讲,可以我一直在思考为什么需要自定义广播,或者说自定义广播在Android程序中一般是用在什么地方,因为广播是为了给不同的组件中通信而使用的例如service 与 Activity 不同的进程中,或者不同的应用程序中就会使用广播机制来通信的。
5本地广播
系统广播和自定义广播都属于全局广播,即发出的广播可以被其他任何 的任何应用程序接收到, 并且我们也可以接收来自于其他任何应用程序的广播。这样就很容易会引起安全性的问题, 比如说我们发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。
为了能够简单地解决广播的安全性问题,Android 引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
6动态注册广播
动态注册就是在程序中使用Context.registerReceiver注册。动态注册的广播接收器可以自由地控制注册与注销,在灵活性方面有很大的优势,但是它也存在着一个缺点,即必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在 onCreate()方法中的。
7静态注册广播
在AndroidManifest.xml中注册广播称之为静态注册,静态注册是常驻型 ,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行,所以一些系统级别的广播比如开机启动广播就必须要用到静态注册的方法,而有些系统广播也是可以动态注册的,比如电量变化广播等可以在程序启动后监听即可。
下面我通过例子简单的介绍一下广播机理:
(1)首先举一个系统广播的例子,这里我们通过静态注册广播的方式来完成
首先要再AndroidManifest.xml中注册广播接收机
<pre>
//注册广播接收机,监听开机广播
<receiver android:name=".MyBroadcastReceive">
<intent-filter>
//通过android:name来指定具体注册哪一个广播接收器
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</pre>
新建广播接收机,创建MyBroadcastReceive.java
<pre>
public class MyBroadcastReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"开机启动",Toast.LENGTH_LONG).show();
}
}
</pre>
运行程序候,重启虚拟机,在开机时可以看到“开机启动”的Toast
(2)下面我们通过静态注册广播的方式完成自定义广播
首先在AndroidManifest.xml文件中静态注册自定广播接收机
<pre>
<receiver android:name=".DiyBroadReceive">
<intent-filter>
//通过android:name来指定具体注册哪一个广播接收器,这里可以自己任意指定name
<action android:name="linus.diyBroadReceive" />
</intent-filter>
</receiver>
</pre>
创建自定义广播接收机,新建DiyBroadReceive.java
<pre>
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("linus.diyBroadReceive");
intent.putExtra("name", "linus");
sendBroadcast(intent);
}
});
</pre>
(3)下面我们来看一下如何动态注册一个自定义广播接收机
<pre>
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//实例化广播接收器
dynamicBroadReceive = new DynamicBroadReceive();
//实例化意图过滤器
filter = new IntentFilter();
//为过滤器添加一个定义的广播,当然这里也可以填系统广播
filter.addAction("linus.dynamicBroadReceive");
//可以通过setPriority()设置动态广播的优先级,优先级取值范围是-1000到1000
//注意的是的静态注册的广播要快于动态注册的广播,不管动态注册的优先级设置的多高,不管静态注册的优先级有多低
filter.setPriority(1000);
//第一步,注册广播
registerReceiver(dynamicBroadReceive, filter);
//第二部,发送广播
Intent intent = new Intent();
intent.setAction("linus.dynamicBroadReceive");
intent.putExtra("name","linus-dynamic");
sendBroadcast(intent);
}
});
</pre>
创建自定义广播,新建DynamicBroadReceive.java
<pre>
public class DynamicBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//第三部,接收广播
String name = intent.getExtras().getString("name");
Toast.makeText(context,"动态注册广播后,接收到的名字是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
动态注册广播,在结束时必须注销广播
<pre>
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(dynamicBroadReceive);
}
</pre>
(4)下面在举例说明一下本地广播,本地广播无法通过静态注册完成广播注册。因为当广播到来时,应用一定时启动的。本地广播一般时通过LocalBroadcastManager进行管理的
<pre>
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
localBroadcastManager = LocalBroadcastManager.getInstance(getBaseContext());
localBroadReceive = new LocalBroadReceive();
filter = new IntentFilter();
filter.addAction("linus.localBroadReceive");
localBroadcastManager.registerReceiver(localBroadReceive,filter);
Intent intent = new Intent();
intent.setAction("linus.localBroadReceive");
intent.putExtra("name","linus-local");
localBroadcastManager.sendBroadcast(intent);
}
});
</pre>
创建本地广播接收机,创建LocalBroadReceive.java
<pre>
public class LocalBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"本地广播接收到的name是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
本地广播在结束时,也是需要注销广播的。
<pre>
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localBroadReceive);
}
</pre>
(5)有序广播就是按照广播的优先级进行广播,不同的应用接收到广播的先后顺序不同。同时先接收到广播的应用可以向后接收到的广播传递数据。这里就不举例说明了。
为了方面大家实践测试,我将整个demo的源码分享一下。
MainActivity.java
<pre>
package linuszhao.js.one.jsbroadcast;
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.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button btn1, btn2,btn3;
//定义意图过滤器
private IntentFilter filter;
//定义广播接收器
DynamicBroadReceive dynamicBroadReceive;
LocalBroadReceive localBroadReceive;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button) findViewById(R.id.btn1);
btn2 = (Button) findViewById(R.id.btn2);
btn3 = (Button) findViewById(R.id.btn3);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setAction("linus.diyBroadReceive");
intent.putExtra("name", "linus");
sendBroadcast(intent);
}
});
btn2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//实例化广播接收器
dynamicBroadReceive = new DynamicBroadReceive();
//实例化意图过滤器
filter = new IntentFilter();
//为过滤器添加一个定义的广播,当然这里也可以填系统广播
filter.addAction("linus.dynamicBroadReceive");
//可以通过setPriority()设置动态广播的优先级,优先级取值范围是-1000到1000
//注意的是的静态注册的广播要快于动态注册的广播,不管动态注册的优先级设置的多高,不管静态注册的优先级有多低
filter.setPriority(1000);
//注册广播
registerReceiver(dynamicBroadReceive, filter);
Intent intent = new Intent();
intent.setAction("linus.dynamicBroadReceive");
intent.putExtra("name","linus-dynamic");
sendBroadcast(intent);
}
});
btn3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
localBroadcastManager = LocalBroadcastManager.getInstance(getBaseContext());
localBroadReceive = new LocalBroadReceive();
filter = new IntentFilter();
filter.addAction("linus.localBroadReceive");
localBroadcastManager.registerReceiver(localBroadReceive,filter);
Intent intent = new Intent();
intent.setAction("linus.localBroadReceive");
intent.putExtra("name","linus-local");
localBroadcastManager.sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(dynamicBroadReceive);
localBroadcastManager.unregisterReceiver(localBroadReceive);
}
}
</pre>
activity_main.xml
<pre>
<?xml version="1.0" encoding="utf-8"?>
<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"
tools:context="linuszhao.js.one.jsbroadcast.MainActivity"
android:orientation="vertical">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:text="发起自定义广播"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn2"
android:text="动态发送广播"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn3"
android:text="发起本地广播"/>
</LinearLayout>
</pre>
Androidmanifest.xml
<pre>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="linuszhao.js.one.jsbroadcast">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
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=".MyBroadcastReceive">
<intent-filter>
//通过android:name来指定具体注册哪一个广播接收器
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
//注册广播接收机
<receiver android:name=".DiyBroadReceive">
<intent-filter>
//通过android:name来指定具体注册哪一个广播接收器,这里可以自己任意指定name
<action android:name="linus.diyBroadReceive" />
</intent-filter>
</receiver>
</application>
</manifest>
</pre>
DiyBroadReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class DiyBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"自定义广播接收机接收到的名字是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
MyBroadcastReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class MyBroadcastReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"开机启动",Toast.LENGTH_LONG).show();
}
}
</pre>
DynamicBroadReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class DynamicBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"动态注册广播后,接收到的名字是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>
LocalBroadReceive.java
<pre>
package linuszhao.js.one.jsbroadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/**
- Created by linus on 2017/3/5.
*/
public class LocalBroadReceive extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String name = intent.getExtras().getString("name");
Toast.makeText(context,"本地广播接收到的name是"+name,Toast.LENGTH_SHORT).show();
}
}
</pre>