Android广播

文章目录

1.收发应用广播

1.标准广播

广播的收发过程分为三个步骤:

  1. 发送标准广播
  2. 定义广播接收器
  3. 开关广播接收器
java 复制代码
public class BroadStandardActivity extends AppCompatActivity implements View.OnClickListener {

    private StandardReceiver standardReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broad_standard);
        findViewById(R.id.btn_send_standard).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        Intent intent = new Intent("com.zzzjian.demo7.standard");
        sendBroadcast(intent);
    }


    @Override
    protected void onStart() {
        super.onStart();
        standardReceiver = new StandardReceiver();
        // 创建意图过滤器 只处理 com.zzzjian.demo7.action.standard 这个动作
        IntentFilter filter = new IntentFilter(StandardReceiver.STANDARD_ACTION);
        // 注册接收器 注册之后才能正常接受广播
        registerReceiver(standardReceiver, filter);
    }

    @Override
    protected void onStop() {
        super.onStop();
        // 注销接收器 注销之后就不再接受广播
        unregisterReceiver(standardReceiver);
    }
}
java 复制代码
public class StandardReceiver extends BroadcastReceiver {

    private static final String TAG = "StandardReceiver";

    public   static final String STANDARD_ACTION = "com.zzzjian.demo7.standard";
    /**
     * 一旦收到标准广播,马上触发接收器的onReceive方法
     * @param context
     * @param intent
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null && intent.getAction().equals(STANDARD_ACTION)){
            Log.d(TAG, "收到一个标准广播");
        }

    }
}

2.有序广播

  • 一个广播存在多个接收器,这些接收器需要排队收听广播,这意味着该广播是条有序广播。
  • 先收到广播的接收器,既可以让其他接收器继续收听广播,也可以中断广播不让其他接收器收听。
java 复制代码
public class BroadOrderActivity extends AppCompatActivity implements View.OnClickListener {

    public static final String ORDER_ACTION = "com.zzzjian.demo7.order";


    private OrderAReceiver orderAReceiver;


    private OrderBReceiver orderBReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_broad_order);
        findViewById(R.id.btn_send_order).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        Intent intent = new Intent(ORDER_ACTION);
        sendOrderedBroadcast(intent,null);
    }

    @Override
    protected void onStart() {
        super.onStart();
        // 多个接收器处理有序广播的顺序规则
        // 1. 先处理优先级最高的接收器
        // 2. 优先级相同的接收器,先注册先处理
        orderAReceiver = new OrderAReceiver();
        IntentFilter filterA = new IntentFilter(ORDER_ACTION);
        filterA.setPriority(8);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            registerReceiver(orderAReceiver, filterA, Context.RECEIVER_EXPORTED);
        }

        orderBReceiver = new OrderBReceiver();
        IntentFilter filterB = new IntentFilter(ORDER_ACTION);
        filterB.setPriority(10);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            registerReceiver(orderBReceiver, filterB, Context.RECEIVER_EXPORTED);
        }
    }


    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(orderAReceiver);
        unregisterReceiver(orderBReceiver);
    }
}
java 复制代码
public class OrderAReceiver extends BroadcastReceiver {

    private static final String TAG = "OrderReceiver";


    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null && intent.getAction().equals(BroadOrderActivity.ORDER_ACTION)){
            Log.d(TAG, "收到一个有序广播A");
        }
    }
}
java 复制代码
public class OrderBReceiver extends BroadcastReceiver {


    private static final String TAG = "OrderReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null && intent.getAction().equals(BroadOrderActivity.ORDER_ACTION)){
            Log.d(TAG, "收到一个有序广播B");
            // 中断广播
            abortBroadcast();
        }
    }
}

3.广播的静态注册

java 复制代码
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.btn_send_shock).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
    	// 8.0之后必须指定完整类名
        String fullName = "com.zzzjian.demo7.receiver.ShockReceiver";
        Intent intent = new Intent(ShockReceiver.SHOCK_ACTION);
        // 创建一个ComponentName对象,指定当前上下文和接收器全名
        ComponentName componentName = new ComponentName(this, fullName);
        intent.setComponent(componentName);
        sendBroadcast(intent);
    }
}
java 复制代码
public class ShockReceiver extends BroadcastReceiver {

    public static final String SHOCK_ACTION = "com.zzzjian.demo7.shock";

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null && intent.getAction().equals(SHOCK_ACTION)){
            Log.d("ShockReceiver", "震动");
            // 从系统服务获取震动管理器
            Vibrator vb = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
            // 震动 500ms
            vb.vibrate(500);
        }
    }
}
xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.VIBRATE"/>


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">
        <receiver
            android:name=".receiver.ShockReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.zzzjian.demo7.shock" />
            </intent-filter>
        </receiver>
        <activity
            android:name=".BroadStaticActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

2.监听系统广播

1.接受分钟到达广播

  • Intent.ACTION_TIME_TICK
java 复制代码
public class SystemMinteActivity extends AppCompatActivity {

    private TimeReceiver timeReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_system_minte);
    }

    @Override
    protected void onStart() {
        super.onStart();
        timeReceiver = new TimeReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_TIME_TICK);
        registerReceiver(timeReceiver,filter);
    }


    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(timeReceiver);
    }
}
java 复制代码
public class TimeReceiver extends BroadcastReceiver {

    private static final String TAG = "TimeReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null){
            Log.d(TAG,"收到一个分钟到达的广播");
        }
    }
}

2.接受网络变更广播

  • android.net.conn.CONNECTIVITY_CHANGE

getType:获取网络类型

网络类型 说明
TYPE_WIFI 无线热点WIFI
TYPE_MOBILE 数据连接
TYPE_WIMAX WiMAX
TYPE_ETHERNET 以太网
TYPE_BLUETOOTH 蓝牙
TYPE_VPN 虚拟专用网络VPN

getTypeName:获取网络类型名称

getSubtype:获取网络的子类型。如果为数据连接时,子类型为2G/3G/4G等细分。

3.定时管理器AlarmManager

Android提供了专门的定时管理器AlarmManager,它利用系统闹钟定时发送广播,常见方法有:

  • set:设置一次性定时器。
  • setAndAllowWhileIdle:设置一次性定时器,即使设备处于空闲状态,也会保证执行定时器。
  • setRepeating:设置重复定时器,但系统不保证按时发送广播。
  • cancel:取消延迟意图的定时器。
java 复制代码
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();
    }

    protected void onStart() {
        // 调用父类的onStart方法
        super.onStart();

        // 创建AlarmReceiver实例,并传入当前应用的上下文
        // 这里假设AlarmReceiver是一个自定义的BroadcastReceiver子类
        alarmReceiver = new AlarmReceiver(getApplicationContext());

        // 创建IntentFilter对象,用于过滤接收到的广播
        // 指定接收的广播动作为AlarmReceiver.ALARM_ACTION
        IntentFilter filter = new IntentFilter(AlarmReceiver.ALARM_ACTION);

        // 检查Android SDK版本是否大于等于Oreo(8.0)
        // Android Oreo引入了一些新的API和行为变化
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // 注册BroadcastReceiver
            // 参数分别为:要注册的BroadcastReceiver实例、IntentFilter对象、注册标志
            // Context.RECEIVER_EXPORTED表示此BroadcastReceiver可以被其他应用访问
            registerReceiver(alarmReceiver, filter, Context.RECEIVER_EXPORTED);
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        unregisterReceiver(alarmReceiver);
    }
}
java 复制代码
public class AlarmReceiver extends BroadcastReceiver {

    public static final String ALARM_ACTION = "com.zzzjian.demo7.alarm";

    private final Context mContext;


    public AlarmReceiver(Context context){
        super();
        this.mContext = context;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent != null && intent.getAction().equals(ALARM_ACTION)){
            Log.d("AlarmReceiver","收到一个闹钟的广播");
        }
    }

    public void sendAlarm(){
        // 创建一个Intent对象,指定动作类型为ALARM_ACTION
        Intent intent = new Intent(ALARM_ACTION);

        // 创建一个PendingIntent对象,用于稍后触发Intent
        // 第二个参数为请求码,在此设置为0;第三个参数为Intent对象;第四个参数为标志位,设置为FLAG_IMMUTABLE表示PendingIntent不可变
        PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);

        // 获取系统服务AlarmManager,用于管理定时任务
        AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);

        // 设置定时任务,当设备空闲时也可以唤醒设备执行任务
        // 参数分别为:AlarmManager设置类型、触发时间(从1970年1月1日00:00:00 GMT开始计算的毫秒数)、待执行的PendingIntent
        // 注释掉的代码为另一种设置方式,不支持设备空闲时唤醒
        // alarmManager.set(AlarmManager.RTC_WAKEUP, 1000, pendingIntent);
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, 1000, pendingIntent);
        }else{
            alarmManager.set(AlarmManager.RTC_WAKEUP, 1000, pendingIntent);
        }
    }

}

3.捕捉屏幕的变更事件

1.竖屏和横屏切换

为了避免横竖屏切换时重新加载界面的情况,Android设计了一种配置变更机制,在指定的环境配置发生变更之时,无需重启活动页面,只需执行特定的变更行为。该机制分为两步:

  1. 修改AndroidManifest.xml,给activity节点增加android:configChange属性
  2. 修改活动页面的Java代码,重写活动的onCinfigurationChanged方法,补充对应的代码处理逻辑。
onfigChanges属性的取值 说明
orientation 屏幕方向发生变化
screenLayout 屏幕的显示发生改变,例如在全屏和分屏之间切换
screenSize 屏幕大小发生改变,例如在竖屏和横屏之间切换
keyboard 键盘发生改变,例如使用了外部键盘
keyboardHidden 软键盘弹出或隐藏
navigation 导航方式发生改变,例如采用了轨迹球导航
fontSize 字体比例发生改变
locale 设备本地位置发生改变,例如切换了系统语言
uiMode 用户界面的模式发生改变,例如开启了夜间模式
xml 复制代码
<activity
            android:name=".ChangeDirectionActivity"
            android:exported="true"
            android:theme="@style/Theme.MyApplication"
            android:configChanges="orientation|screenLayout|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
java 复制代码
public class ChangeDirectionActivity extends AppCompatActivity {

    private static final String TAG = "ChangeDirectionActivity";

    private TextView tv_monitor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_change_direction);
        tv_monitor = findViewById(R.id.tv_monitor);
        Log.d(TAG, "onCreate");
    }

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        switch (newConfig.orientation){
            case Configuration.ORIENTATION_PORTRAIT:
                tv_monitor.setText("竖屏");
                break;
            case Configuration.ORIENTATION_LANDSCAPE:
                tv_monitor.setText("横屏");
                break;
            default:
                break;
        }
    }
}

2.回到桌面与切换到任务列表

  • 按下主页键会回到桌面,按下任务键会打开任务列表,这两个操作并未提供相应的按键处理方法,而是通过广播发出事件信息。
  • 如果想知道是否回到桌面,以及是否打开任务列表,均需收听系统广播Intent.ACTION_CLOSE_SYSTEM_DIALOGS。
  • 从收到广播意图中获取原因reason字段,该字段值为homekey时表示回到桌面,值为recentapps时表示打开任务列表。
java 复制代码
public class ReturnDesktopActivity extends AppCompatActivity {

    private DesktopReceiver desktopReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_return_desktop);

        desktopReceiver = new DesktopReceiver();
        IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            registerReceiver(desktopReceiver,filter, Context.RECEIVER_EXPORTED);
        }

    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(desktopReceiver);
    }

    @Override
    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
        super.onPictureInPictureModeChanged(isInPictureInPictureMode);
        if(isInPictureInPictureMode){
            Log.d("ReturnDesktopActivity", "进入小窗模式");
        }else{
            Log.d("ReturnDesktopActivity", "退出小窗模式");
        }
    }

    private class DesktopReceiver 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("home") || reason.equals("recentapps"))){
                    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !isInPictureInPictureMode()){
                        PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder();
                        Rational aspectRatio = new Rational(10, 5);
                        builder.setAspectRatio(aspectRatio);
                        enterPictureInPictureMode(builder.build());

                    }
                }
            }
        }
    }
}
xml 复制代码
        <activity
            android:name=".ReturnDesktopActivity"
            android:configChanges="orientation|screenLayout|screenSize"
            android:exported="true"
            android:screenOrientation="portrait"
            android:supportsPictureInPicture="true"
            android:theme="@style/Theme.MyApplication">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
相关推荐
数据小爬虫@2 分钟前
如何高效利用Python爬虫按关键字搜索苏宁商品
开发语言·爬虫·python
ZJ_.4 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
Narutolxy10 分钟前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
Hello.Reader17 分钟前
全面解析 Golang Gin 框架
开发语言·golang·gin
禁默28 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood34 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Code哈哈笑37 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
gb421528740 分钟前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
程序猿进阶40 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_4336184443 分钟前
shell 编程(二)
开发语言·bash·shell