Android -- 广播

家电维修 2023-07-16 19:16www.caominkang.com家电维修技术

 广播

        发送一条广播,可以被不同的广播接收者所接收,广播接收者收到广播之后,再进行逻辑处理。

 广播与活动的区别

(1)活动只能一对一通信;而广播可以一对多,一人发送广播,多人接收处理。

(2)对于发送方来说,广播不需要考虑接收方有没有在工作,接收方在工作就接收广播,不在工作就丢 弃广播。

(3)对于接收方来说,因为可能会收到各式各样的广播,所以接收方要自行过滤符合条件的广播,之后 再解包处理。

广播当中三个方法
  1. sendBroadcast发送广播。

  2. registerReceiver注册广播的接收器,可在onStart或onResume方法中注册接收器。

  3. unregisterReceiver注销广播的接收器,可在onS或onDestroy方法中注销接收器。

广播的收发过程
  1. 发送标准广播

  2. 定义广播接收器

  3. 开关广播接收器

收发标准广播
  1. 先创建意图对象,再调用sendBroadcast方法发送广播

  2. 广播发出来之后,还得有设备去接收广播,也就是需要广播接收器。接收器主要规定两个事情,一个是 接收什么样的广播,另一个是收到广播以后要做什么。由于接收器的处理逻辑大同小异,Android 提供了抽象之后的接收器基类BroadcastReceiver,开发者自定义的接收器都从BroadcastReceiver派生 而来。新定义的接收器需要重写onReceive方法,方法内部先判断当前广播是否符合待接收的广播名 称,校验通过再开展后续的业务逻辑

  3. 通过意图过滤器挑选动作名称一致的广播

收发标准广播是无序的广播

主程序实现
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之间的差异主要有下列三点

  1. PendingIntent代表延迟的意图,它指向的组件不会马上激活;而Intent代表实时的意图,它指 向的组件会马上激活。

  2. PendingIntent是一类消息的组合,不但包含目标的Intent对象,还包含请求代码、请求方式等 信息。

  3. 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"

Copyright © 2016-2025 www.jianfeikang.com 建飞家电维修 版权所有 Power by