Android -- 广播

简介: Android -- 广播

广播

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



广播与活动的区别


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


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


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



广播当中三个方法


  1. sendBroadcast:发送广播。
  2. registerReceiver:注册广播的接收器,可在onStart或onResume方法中注册接收器。
  3. unregisterReceiver:注销广播的接收器,可在onStop或onDestroy方法中注销接收器。


广播的收发过程

  1. 发送标准广播
  2. 定义广播接收器
  3. 开关广播接收器



收发标准广播

先创建意图对象,再调用sendBroadcast方法发送广播


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


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


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


主程序实现

package com.kcs.broadcast;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.kcs.broadcast.receiver.StandardReceiver;
public class BroadcastStrandActivity extends AppCompatActivity implements View.OnClickListener {
    private StandardReceiver standardReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broadcast_strand);
        findViewById(R.id.send_standbroad).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        //发送标准广播
        Intent intent = new Intent(StandardReceiver.STANDARD_ACTION);
        sendBroadcast(intent);
    }
    @Override
    protected void onStart() {
        super.onStart();
        standardReceiver = new StandardReceiver();
        //创建意图过滤器,处理STANDARD_ACTION的广播
        IntentFilter filter = new IntentFilter(StandardReceiver.STANDARD_ACTION);
        registerReceiver(standardReceiver,filter);
    }
    @Override
    protected void onStop() {
        super.onStop();
        //注销接收器
        unregisterReceiver(standardReceiver);
    }
}


接受者

package com.kcs.broadcast.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
/**
 * @author Kcs
 */
public class StandardReceiver extends BroadcastReceiver {
    public static final String STANDARD_ACTION = "com.kcs.broadcast.standard";
    /**
     * 接收到标准广播,触发onReceiver方法
     * @param context
     * @param intent
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(STANDARD_ACTION)){
            Log.d("kong","收到广播!!");
        }
    }
}


布局文件

<?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"
    android:orientation="vertical"
    android:padding="10dp">
    <Button
        android:id="@+id/send_standbroad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="发送标准广播"
        android:textColor="@color/black"
        android:textSize="20dp"
        />
</LinearLayout>


收发有序广播


(1)一个广播存在多个接收器,这些接收器需要排队收听广播,这意味着该广播是条有序广播。(2)先收到广播的接收器A,既可以让其他接收器继续收听广播,也可以中断广播不让其他接收器收听。

  • 优先级,级别越大,数字越大
  • 优先级大截断了优先级小的广播

以震动为例



主程序

package com.kcs.broadcast;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.kcs.broadcast.receiver.OrderReceiver;
import com.kcs.broadcast.receiver.OrderReceiverB;
public class BroadOrderActivity extends AppCompatActivity implements View.OnClickListener {
    public static final String ORDER_ACTION = "com.kcs.broadcast.order";
    private OrderReceiver orderReceiverA;
    private OrderReceiverB orderReceiverB;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broad_order);
        findViewById(R.id.send_orderbroad).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        //动作意图
        Intent intent = new Intent(ORDER_ACTION);
        sendOrderedBroadcast(intent,null);
    }
    /**
     * 处理广播规则
     *  1. 优先级越大的接收器,越早收到有序广播
     *  2. 优先级相同,越早注册的接收器越早收到有序广播
     */
    @Override
    protected void onStart() {
        super.onStart();
        orderReceiverA = new OrderReceiver();
        //创建意图过滤器,处理STANDARD_ACTION的广播
        IntentFilter filterA = new IntentFilter(ORDER_ACTION);
        //设置优先级
        filterA.setPriority(8);
        registerReceiver(orderReceiverA,filterA);
        orderReceiverB = new OrderReceiverB();
        //创建意图过滤器,处理STANDARD_ACTION的广播
        IntentFilter filterB = new IntentFilter(ORDER_ACTION);
        //设置优先级
        filterB.setPriority(10);
        //因为B的优先级比A的高,优先收到广播
        registerReceiver(orderReceiverB,filterB);
    }
    @Override
    protected void onStop() {
        super.onStop();
        //注销接收器
        unregisterReceiver(orderReceiverA);
        unregisterReceiver(orderReceiverB);
    }
}



接收方

两个接收者, 来比较优先级,下面的优先级是B的比A大,所以A被拦截了,没有接收到广播

package com.kcs.broadcast.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.kcs.broadcast.BroadOrderActivity;
/**
 * @author Kcs
 */
public class OrderReceiverB extends BroadcastReceiver {
    /**
     * 接收到有序广播,触发onReceiver方法
     * @param context
     * @param intent
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent != null && intent.getAction().equals(BroadOrderActivity.ORDER_ACTION)){
            Log.d("kong","B===》收到广播!!");
            abortBroadcast();//中断广播,比B低的接收器就无法接收到信息
        }
    }
}


package com.kcs.broadcast.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.kcs.broadcast.BroadOrderActivity;
/**
 * @author Kcs
 */
public class OrderReceiver extends BroadcastReceiver {
    /**
     * 接收到有序广播,触发onReceiver方法
     * @param context
     * @param intent
     */
    @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 com.kcs.broadcast;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.kcs.broadcast.receiver.ShakeReceiver;
public class BroadStaticActivity extends AppCompatActivity implements View.OnClickListener {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broad_static);
        findViewById(R.id.send_shake_broad).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        String fullName = "com.kcs.broadcast.receiver.ShakeReceiver";
        Intent intent = new Intent(ShakeReceiver.SHOCK_ACTION);
        ComponentName componentName = new ComponentName(this, fullName);
        intent.setComponent(componentName);
        sendBroadcast(intent);
    }
}


接收者

package com.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 = "com.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和文本

启动类配置权限

    <!-- 震动系统权限 -->
    <uses-permission android:name="android.permission.VIBRATE" />
        <receiver
            android:name=".receiver.ShakeReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="com.kcs.broadcast.shake" />
            </intent-filter>
        </receiver>


模拟震动

定时管理器 AlarmManager


系统闹钟定时发送广播,常见的方法:


set:设置一次性定时器。


setAndAllowWhileIdle:设置一次性定时器,即使设备处于空闲状态,也会保证执行定时器。


setRepeating:设置重复定时器,但系统不保证按时发送广播。


cancel:取消指定延迟意图的定时器。

延迟意图


定时管理器使用了PendingIntent,它与Intent之间的差异主要有下列三点:


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


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


PendingIntent对象在创建之时便已知晓将要用于活动还是广播

主程序

一分钟广播一次

package com.kcs.broadcast;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.kcs.broadcast.receiver.AlarmReceiver;
public class AlarmActivity extends AppCompatActivity implements View.OnClickListener {
    private AlarmReceiver alarmReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm);
        findViewById(R.id.btn_alarm).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        alarmReceiver.sendAlarm();
    }
    @Override
    protected void onStart() {
        super.onStart();
        alarmReceiver = new AlarmReceiver(getApplicationContext());
        IntentFilter filter = new IntentFilter(AlarmReceiver.ALARM_ACTION);
        registerReceiver(alarmReceiver, filter);
    }
    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(alarmReceiver);
    }
}



Alarm Receiver

package com.kcs.broadcast;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import com.kcs.broadcast.receiver.AlarmReceiver;
public class AlarmActivity extends AppCompatActivity implements View.OnClickListener {
    private AlarmReceiver alarmReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alarm);
        findViewById(R.id.btn_alarm).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        alarmReceiver.sendAlarm();
    }
    @Override
    protected void onStart() {
        super.onStart();
        alarmReceiver = new AlarmReceiver(getApplicationContext());
        IntentFilter filter = new IntentFilter(AlarmReceiver.ALARM_ACTION);
        registerReceiver(alarmReceiver, filter);
    }
    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(alarmReceiver);
    }
}


布局文件和上面的收发标准广播布局的一样,只需修改id和文本

 

开启画中画

回到桌面与切到任务列表


按下主页键会回到桌面,按下任务键会打开任务列表,这两个操作并未提供相应的按键处理方法,而是通过广播发出事件信息。


若想知晓是否回到桌面,以及是否打开任务列表,均需收听系统广播Intent.ACTION_CL OSE_SYSTEM_DIALOGS。


从收到的广播意图中获取原因reason字段,该字段值为homekey时表示回到桌面,值为r ecentapps时表示打开任务列表

应用的画中画

  • 监听回到桌面与打开任务列表的广播;
  • 收到广播之后,调用 enterPictureInPictureMode 方法进入画中画模式;
  • 重写活动页面的 onPictureInPictureModeChanged 方法,补充进入画中画模式或退出

主程序

package com.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.appcompat.app.AppCompatActivity;
public class RetruenDesktopActivity extends AppCompatActivity {
    private DesktopRecevier desktopRecevier;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_retruen_desktop);
        //创建广播接收器
        desktopRecevier = new DesktopRecevier();
        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        registerReceiver(desktopRecevier,intentFilter);
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(desktopRecevier);
    }
    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
        if (isInPictureInPictureMode){
            Log.d("kong","进入画中画");
        }else{
            Log.d("kong","退出画中画");
        }
    }
    /**
     * 创建广播接收者
     */
    private class DesktopRecevier 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 = new PictureInPictureParams.Builder();
                        //设置宽高比例
                        Rational rational = new Rational(10, 5);
                        builder.setAspectRatio(rational);
                        //进入画中画
                        enterPictureInPictureMode(builder.build());
                    }
                }
            }
        }
    }
}

启动配置

android:supportsPictureInPicture="true"
目录
相关文章
|
6月前
|
XML Android开发 数据格式
Android -- Fragment动态注册
Android -- Fragment动态注册
31 0
|
10月前
|
Android开发
Android:四大组件之 Broadcast(广播)
Broadcast 是一种广泛运用的、在应用程序之间传输信息的机制,Android 中的广播与传统意义上的电台广播类似,一个广播可以有任意个接收者,当然也可能不被任何应用程序所接收。广播机制是一个典型的发布-订阅模式,也就是观察者模式。
70 0
Android:四大组件之 Broadcast(广播)
|
Shell Android开发
android 系统受保护广播
android 系统受保护广播
361 0
|
Java Android开发 数据格式