Android -- 广播
广播
发送一条广播,可以被不同的广播接收者所接收,广播接收者收到广播之后,再进行逻辑处理。
广播与活动的区别(1)活动只能一对一通信;而广播可以一对多,一人发送广播,多人接收处理。
(2)对于发送方来说,广播不需要考虑接收方有没有在工作,接收方在工作就接收广播,不在工作就丢 弃广播。
(3)对于接收方来说,因为可能会收到各式各样的广播,所以接收方要自行过滤符合条件的广播,之后 再解包处理。
广播当中三个方法-
sendBroadcast发送广播。
-
registerReceiver注册广播的接收器,可在onStart或onResume方法中注册接收器。
-
unregisterReceiver注销广播的接收器,可在onS或onDestroy方法中注销接收器。
-
发送标准广播
-
定义广播接收器
-
开关广播接收器
-
先创建意图对象,再调用sendBroadcast方法发送广播
-
广播发出来之后,还得有设备去接收广播,也就是需要广播接收器。接收器主要规定两个事情,一个是 接收什么样的广播,另一个是收到广播以后要做什么。由于接收器的处理逻辑大同小异,Android 提供了抽象之后的接收器基类BroadcastReceiver,开发者自定义的接收器都从BroadcastReceiver派生 而来。新定义的接收器需要重写onReceive方法,方法内部先判断当前广播是否符合待接收的广播名 称,校验通过再开展后续的业务逻辑
-
通过意图过滤器挑选动作名称一致的广播
收发标准广播是无序的广播
主程序实现package .kcs.broadcast; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.vie.Vie; import androidx.apppat.app.AppCompatActivity; import .kcs.broadcast.receiver.StandardReceiver; public class BroadcastStrandActivity extends AppCompatActivity implements Vie.OnClickListener { private StandardReceiver standardReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVie(R.layout.activity_broadcast_strand); findVieById(R.id.send_standbroad).setOnClickListener(this); } @Override public void onClick(Vie v) { //发送标准广播 Intent intent = ne Intent(StandardReceiver.STANDARD_ACTION); sendBroadcast(intent); } @Override protected void onStart() { super.onStart(); standardReceiver = ne StandardReceiver(); //创建意图过滤器,处理STANDARD_ACTION的广播 IntentFilter filter = ne IntentFilter(StandardReceiver.STANDARD_ACTION); registerReceiver(standardReceiver,filter); } @Override protected void onS() { super.onS(); //注销接收器 unregisterReceiver(standardReceiver); } }接受者
package .kcs.broadcast.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; public class StandardReceiver extends BroadcastReceiver { public static final String STANDARD_ACTION = ".kcs.broadcast.standard"; @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.getAction().equals(STANDARD_ACTION)){ Log.d("kong","收到广播!!"); } } }布局文件
收发有序广播
(1)一个广播存在多个接收器,这些接收器需要排队收听广播,这意味着该广播是条有序广播。(2)先收到广播的接收器A,既可以让其他接收器继续收听广播,也可以中断广播不让其他接收器收听。
-
优先级,级别越大,数字越大
-
优先级大截断了优先级小的广播
以震动为例
主程序package .kcs.broadcast; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.vie.Vie; import androidx.apppat.app.AppCompatActivity; import .kcs.broadcast.receiver.OrderReceiver; import .kcs.broadcast.receiver.OrderReceiverB; public class BroadOrderActivity extends AppCompatActivity implements Vie.OnClickListener { public static final String ORDER_ACTION = ".kcs.broadcast.order"; private OrderReceiver orderReceiverA; private OrderReceiverB orderReceiverB; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVie(R.layout.activity_broad_order); findVieById(R.id.send_orderbroad).setOnClickListener(this); } @Override public void onClick(Vie v) { //动作意图 Intent intent = ne Intent(ORDER_ACTION); sendOrderedBroadcast(intent,null); } @Override protected void onStart() { super.onStart(); orderReceiverA = ne OrderReceiver(); //创建意图过滤器,处理STANDARD_ACTION的广播 IntentFilter filterA = ne IntentFilter(ORDER_ACTION); //设置优先级 filterA.setPriority(8); registerReceiver(orderReceiverA,filterA); orderReceiverB = ne OrderReceiverB(); //创建意图过滤器,处理STANDARD_ACTION的广播 IntentFilter filterB = ne IntentFilter(ORDER_ACTION); //设置优先级 filterB.setPriority(10); //因为B的优先级比A的高,优先收到广播 registerReceiver(orderReceiverB,filterB); } @Override protected void onS() { super.onS(); //注销接收器 unregisterReceiver(orderReceiverA); unregisterReceiver(orderReceiverB); } }接收方
两个接收者, 来比较优先级,下面的优先级是B的比A大,所以A被拦截了,没有接收到广播
package .kcs.broadcast.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import .kcs.broadcast.BroadOrderActivity; public class OrderReceiverB extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.getAction().equals(BroadOrderActivity.ORDER_ACTION)){ Log.d("kong","B===》收到广播!!"); abortBroadcast();//中断广播,比B低的接收器就无法接收到信息 } } }
package .kcs.broadcast.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; import .kcs.broadcast.BroadOrderActivity; public class OrderReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.getAction().equals(BroadOrderActivity.ORDER_ACTION)){ Log.d("kong","A===》收到广播!!"); } } }
布局文件和上面的收发标准的一样,只需修改id和文本
等级相同情况下,先注册先接收,这里是A先注册,B后注册
被拦截的效果
收发静态广播-
在代码中注册接收器,该方式被称作动态注册
-
在AndroidManifest.xml中注册接收器,该方式被称作静态注册
package .kcs.broadcast; import android.content.ComponentName; import android.content.Intent; import android.os.Bundle; import android.vie.Vie; import androidx.apppat.app.AppCompatActivity; import .kcs.broadcast.receiver.ShakeReceiver; public class BroadStaticActivity extends AppCompatActivity implements Vie.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVie(R.layout.activity_broad_static); findVieById(R.id.send_shake_broad).setOnClickListener(this); } @Override public void onClick(Vie v) { String fullName = ".kcs.broadcast.receiver.ShakeReceiver"; Intent intent = ne Intent(ShakeReceiver.SHOCK_ACTION); ComponentName ponentName = ne ComponentName(this, fullName); intent.setComponent(ponentName); sendBroadcast(intent); } }接收者
package .kcs.broadcast.receiver; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Vibrator; import android.util.Log; public class ShakeReceiver extends BroadcastReceiver { public static final String SHOCK_ACTION = ".kcs.broadcast.shake"; @Override public void onReceive(Context context, Intent intent) { if (intent!= null && intent.getAction().equals(SHOCK_ACTION)){ Log.d("kong","震动ing"); Vibrator vb = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); // 震动 1s vb.vibrate(1000); } } }
布局文件和上面的收发标准广播布局的一样,只需修改id和文本
启动类配置权限模拟震动
定时管理器 AlarmManager系统闹钟定时发送广播,常见的方法
-
set设置一次性定时器。
-
setAndAlloWhileIdle设置一次性定时器,即使设备处于空闲状态,也会保证执行定时器。
-
setRepeating设置重复定时器,但系统不保证按时发送广播。
-
cancel取消指定延迟意图的定时器。
定时管理器使用了PendingIntent,它与Intent之间的差异主要有下列三点
-
PendingIntent代表延迟的意图,它指向的组件不会马上激活;而Intent代表实时的意图,它指 向的组件会马上激活。
-
PendingIntent是一类消息的组合,不但包含目标的Intent对象,还包含请求代码、请求方式等 信息。
-
PendingIntent对象在创建之时便已知晓将要用于活动还是广播
一分钟广播一次
package .kcs.broadcast; import android.content.IntentFilter; import android.os.Bundle; import android.vie.Vie; import androidx.apppat.app.AppCompatActivity; import .kcs.broadcast.receiver.AlarmReceiver; public class AlarmActivity extends AppCompatActivity implements Vie.OnClickListener { private AlarmReceiver alarmReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVie(R.layout.activity_alarm); findVieById(R.id.btn_alarm).setOnClickListener(this); } @Override public void onClick(Vie v) { alarmReceiver.sendAlarm(); } @Override protected void onStart() { super.onStart(); alarmReceiver = ne AlarmReceiver(getApplicationContext()); IntentFilter filter = ne IntentFilter(AlarmReceiver.ALARM_ACTION); registerReceiver(alarmReceiver, filter); } @Override protected void onS() { super.onS(); unregisterReceiver(alarmReceiver); } }Alarm Receiver
package .kcs.broadcast; import android.content.IntentFilter; import android.os.Bundle; import android.vie.Vie; import androidx.apppat.app.AppCompatActivity; import .kcs.broadcast.receiver.AlarmReceiver; public class AlarmActivity extends AppCompatActivity implements Vie.OnClickListener { private AlarmReceiver alarmReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVie(R.layout.activity_alarm); findVieById(R.id.btn_alarm).setOnClickListener(this); } @Override public void onClick(Vie v) { alarmReceiver.sendAlarm(); } @Override protected void onStart() { super.onStart(); alarmReceiver = ne AlarmReceiver(getApplicationContext()); IntentFilter filter = ne IntentFilter(AlarmReceiver.ALARM_ACTION); registerReceiver(alarmReceiver, filter); } @Override protected void onS() { super.onS(); unregisterReceiver(alarmReceiver); } }
布局文件和上面的收发标准广播布局的一样,只需修改id和文本
开启画中画 回到桌面与切到任务列表
-
按下主页键会回到桌面,按下任务键会打开任务列表,这两个操作并未提供相应的按键处理方法,而是通过广播发出事件信息。
-
若想知晓是否回到桌面,以及是否打开任务列表,均需收听系统广播Intent.ACTION_CL OSE_SYSTEM_DIALOGS。
-
从收到的广播意图中获取原因reason字段,该字段值为homekey时表示回到桌面,值为r ecentapps时表示打开任务列表
-
监听回到桌面与打开任务列表的广播;
-
收到广播之后,调用 enterPictureInPictureMode 方法进入画中画模式;
-
重写活动页面的 onPictureInPictureModeChanged 方法,补充进入画中画模式或退出
package .kcs.broadcast; import android.app.PictureInPictureParams; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.util.Rational; import androidx.apppat.app.AppCompatActivity; public class RetruenDeskActivity extends AppCompatActivity { private DeskRecevier deskRecevier; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentVie(R.layout.activity_retruen_desk); //创建广播接收器 deskRecevier = ne DeskRecevier(); IntentFilter intentFilter = ne IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); registerReceiver(deskRecevier,intentFilter); } @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(deskRecevier); } @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration neConfig) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, neConfig); if (isInPictureInPictureMode){ Log.d("kong","进入画中画"); }else{ Log.d("kong","退出画中画"); } } private class DeskRecevier extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent != null && intent.getAction().equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) { String reason = intent.getStringExtra("reason"); if (!TextUtils.isEmpty(reason) && (reason.equals("homekey") || reason.equals("recentapps"))) { //8.0以后才有画中画 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isInPictureInPictureMode()){ // 创建画中画参数构造器 PictureInPictureParams.Builder builder = ne PictureInPictureParams.Builder(); //设置宽高比例 Rational rational = ne Rational(10, 5); builder.setAspectRatio(rational); //进入画中画 enterPictureInPictureMode(builder.build()); } } } } } }启动配置
android:supportsPictureInPicture="true"