AndroidAZ系列:四大组件之Broadcast(All,F
AndroidAZ系列有以下目的:
- Android程序猿的面试(初级,中级,高级,资深),拿到满意的offer。
- Android程序猿学习进阶。
标记说明:因为笔者是列出所有的Android知识点,因此面试不需要看那么多内容,如果是面试的知识点。笔者会加上标记Face,而如果不是面试的知识点,笔者会加上No标记,它是要学的东西;然后笔者将Android面试者或者面试者分为4个等级,初级A1,中级A2,高级A3,资深A4,如果这个知识点是所有等级的范围,那么笔者将会以all标记上。因此进阶路线就是A1->A2->A3->A4。也是面试者挑选的复习范围,假如你是中级程序员,那么你面试要看的内容就是包含A2&Face的标记。
-
All : 所有的Android工程师都看。
-
A1: 初级Android工程师。
-
A2: 中级Android工程师。
-
A3: 高级Android工程师。
-
A4: 资深Android工程师。
-
Face: 是面试的知识点。
-
No: 面试基本遇不到。
1.广播是什么
在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。
2.广播的种类
2.1 无序广播(普通广播)
普通广播是完全异步的,通过Context
的SendBroadcast()
函数来发送,消息传递的效率比较高,但所有的receivers
(接收器)的执行顺序不确定,缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent
的传播,直到没有与之匹配的的广播接收器为止。
使用方法:
首先继承BroadcastReceiver
,然后需要重写onReceiver()
方法,这样我们就实现了一个接收器。
public class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "hello", Toast.LENGTH_SHORT).show();
}
}
2.2 有序广播
有序广播是一种同步执行的广播,在广播发出后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递. 有先后顺序,前面的广播能够截断正在传递的广播.
有序广播通过Context.sendOrderdBroadcast()来发送,所有的广播按照优先级顺序依次进行,广播接收器的 优先级通过receiver的intent-filter中的priority属性来设置,数组越大优先级越高(最大为最大数),当广播接收器结收到广播后可以使用setResult()函数来将结果传递给下一个接收器接收,然后通过getResult来获取上 一个接收器的返回的结果,并可以用abortBroadcast()函数来让系统丢弃该广播,该广播不在传递到别的广播接收器接收。
首先我们注册两个广播接收器
public class MyBroadcastReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int i=1;
Toast.makeText(context, i+"", Toast.LENGTH_SHORT).show();
Bundle bundle=new Bundle();
bundle.putInt("I",i);
setResult(1,i+"",bundle);
}
}
public class MyBroadcastReceiver2 extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Bundle resultExtras = getResultExtras(true);
int i = resultExtras.getInt("I");
Toast.makeText(context, i+1+"", Toast.LENGTH_SHORT).show();
}
}
并在androidManifest中注册并设置两个广播接收器的优先级
<receiver android:name=".MyBroadcastReceiver">
<intent-filter android:priority="10">
<action android:name="hello"></action>
</intent-filter>
</receiver>
<receiver android:name=".MyBroadcastReceiver2">
<intent-filter android:priority="1">
<action android:name="hello"></action>
</intent-filter>
</receiver>
然后发送一条有序广播,第二个参数是权限相关的字符串,可以传入null。
sendOrderedBroadcast(new Intent("hello"),null);
这时Toast分别弹出的是1和2,说明我们获取到了上一个广播接收器的结果,当然我们也能通过给优先级较高的接收器设置截断广播
abortBroadcast();
这样,之后的广播接收器都不会再接收到广播了。
2.3 本地广播
前面的两种广播都是全局广播,这样的广播可以被任意应用程序接收,并且我们也能接收到来自其他应用程序的广播,这样很容易引起安全问题,android为了解决这个问题引入了本地广播。,使用这个机制发送的广播只能在本应用程序内部进行传递,并且广播接收器也只能接收本应用程序的广播,这样所有的安全问题就不存在了。
首先先获取本地广播实例,并发送一条异步广播
localBroadcastManager=LocalBroadcastManager.getInstance(this);
localBroadcastManager.sendBroadcast(new Intent("hello1"));
然后通过本地广播接收者接收本地广播
private BroadcastReceiver register=new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "hello1", Toast.LENGTH_SHORT).show();
}
};
localBroadcastManager.registerReceiver(register,new IntentFilter("hello1"));
最后在onDestory中注销本地广播接收者,避免oom。
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(register);
}
2.4 黏性广播(Android5.0 Api21失效)
sticky广播通过Context。sendStickyBroadcast()函数来发送,用此函数发送的广播会一直滞留,当有与之匹配的 广播接收器接被注册后,该广播接收器就会接收到广播,当然sticky广播需要下面权限。
<uses-permission android:name="android.permission.BROADCAST_STICKY"></uses-permission>
sticky只保留最后一条广播,并且一直保留下去,这样即使有广播接收器处理了该广播,当有再与之匹配的广播接收器接收时,此广播任会被接收,如果你只想处理一次广播,可以通过removeStickyBroadcast()函数实现。
3.广播接收器
3.1 静态注册
四大组件都需要在Androidmanifest
中进行注册
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="hello"></action>
</intent-filter>
</receiver>
3.2 动态注册
registerReceiver(new MyBroadcastReceiver(),new IntentFilter("hello"));
如果是动态注册的,别忘了在onDestory()
中注销广播
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(new MyBroadcastReceiver());
}
现在我们能给发送一条广播了
sendBroadcast(new Intent("hello"));
当我们发送一条广播是会弹出一条Toast
,说明广播接收器接收到了。
3.3 静态注册和动态注册的区别
-
动态注册受Activity的生命周期影响,当Activity销毁的时候,广播就失效了.而静态注册的广播即使Activity销毁了,仍然可以收到广播,即使杀死进程,仍然可以收到广播
-
动态注册的广播永远要快于静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级多低.
3.4 系统发送的广播有哪些
常见系统广播
打电话
<intent-filter >
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
接电话
<intent-filter >
<action android:name="android.intent.action.PHONE_STATE"/>
</intent-filter>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
开机
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
安装包相关
<intent-filter >
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
//注意这个是必须的
<data android:scheme="package"/>
</intent-filter>
<uses-permission android:name="android.permission.RESTART_PACKAGES"/>
接收短信
<intent-filter >
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Object[] object = (Object[]) intent.getExtras().get("pdus");
for (Object obj : object) {
SmsMessage ss = SmsMessage.createFromPdu((byte[]) obj);
String messageBody = ss.getMessageBody();
String originatingAddress = ss.getDisplayOriginatingAddress();
System.out.println(messageBody+":"+originatingAddress);
}
}
}
屏幕的锁屏和解锁(只能动态注册)
receiver = new BootReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.SCREEN_OFF");
filter.addAction("android.intent.action.SCREEN_ON");
registerReceiver(receiver, filter);
unregisterReceiver(receiver);
下面5个系统广播只能动态注册而不支持静态注册
android.intent.action.SCREEN_ON
android.intent.action.SCREEN_OFF
android.intent.action.BATTERY_CHANGED
android.intent.action.CONFIGURATION_CHANGED
android.intent.action.TIME_TICK