美文网首页
Android四大组件之BroadCast

Android四大组件之BroadCast

作者: 南风知我咦 | 来源:发表于2023-03-28 16:48 被阅读0次

学习资料

简介

  • Broadcast是android中的四大组件之一(其他的组件分别是:Activity,Content provider,Service),是在组件之间传播数据(Intent)的一种机制。广播的发送者和接收者事先是不需要知道对方的存在的。这样带来的好处便是,系统的各个组件可以松耦合地组织在一起,这样系统就具有高度的可扩展性,容易与其它系统进行集成。
广播具有以下特性
  • 广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁
  • 广播接收者中不要做一些耗时的工作,否则会弹出Application No Response错误对话框
  • 最好也不要在广播接收者中创建子线程做耗时的工作,因为广播接收者被销毁后进程就成为了空进程,很容易被系统杀掉,耗时的较长的工作最好放在服务中完成
广播的分类
  • 广播分为系统广播和本地广播,系统广播可以分为标准和有序
  • 标准广播:一但发出所有接收者同时受到
  • 有序广播:接收者按优先级受到而且可以截断
  • 本地广播:以上都是系统全局广播,发出的广播可以被其他任何应用接收这样容易产生安全问题,所以有了本地广播只能在应用程序内部传递。

简单使用

  • 不要想的太难,举一个简单的例子吧:你如果手机要看番,那必须得上网吧,手机由没上网的状态到上网的状态,这种变化会发出的就是一种广播,我们想要接收这个广播就需要一个广播接收器,而获得广播接收器就需要自己注册,一共有2种注册方法,分别为动态注册和静态注册(如果是在没办法理解广播的定义的话,你就把它当作一个全局监听器,用来实现不同组件的信息传递)

动态注册

  • 动态注册是在代码中注册的,根据广播的一个特性广播接收者的生命周期是非常短暂的,在接收到广播的时候创建,onReceive()方法结束之后销毁
  • 我们可以知道广播接收后一定要销毁,可是动态注册并不能自动销毁,所以,动态注册后一定要自己添加销毁的程序
实现广播接收器BroadcastReceiver
  • 广播接收器主要就是重写onReceive方法,这里最好时做简单的处理,不要做任何耗时的操作。
/**
 * 简单的广播接收器
 */
public class MyFirstBroadCast extends BroadcastReceiver {
    private final String TAG = "MyFirstBroadCastTAG";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "接收到广播");
        String info = intent.getStringExtra("key");
        Log.d(TAG, "广播内容:" + info);
    }
}
  • 动态注册,代码动态注册需要记得再页面销毁的时候取消注册。
    /**
     * 动态注册广播
     * 这个需要再销毁页面的时候取消注册
     */
    MyFirstBroadCast firstBroadCast;

    private void initReceiver() {
        firstBroadCast = new MyFirstBroadCast();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("simple broadcast");
        registerReceiver(firstBroadCast, intentFilter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (null != firstBroadCast)
            unregisterReceiver(firstBroadCast);
    }
  • 发送广播

    @Override
    public void initButton() {
        super.initButton();
        initButton(R.id.btn_send, new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendBroadCast();
            }
        });
    }
    /**
     * 发送广播
     */
    private void sendBroadCast() {
        Intent intent = new Intent("simple broadcast");
        intent.putExtra("key", "这是一条简单的广播");
        sendBroadcast(intent);
    }
  • 简单运行,结果正确


    图片.png

静态注册

  • 使用流程一样,知识区别点就是广播需要再manifest文件注册,过滤器也是再里面添加;
  • 注意一个事情,高版本的API(比如我用的API29,安卓8以上就用不了了)就已经没有静态注册了
  • 关于上面的,验证了下,确实高版本再manifest中注册的接收器,在发送广播后确实没有接收到消息。
  • 针对上面的情况,你的广播瘾犯了就是想用静态注册怎么办呢,Android8.0 静态receiver接收不到隐式广播这篇文章帮你解决了,我试了下,很好用。
   <receiver
            android:name=".fourassembly.broadcast.MyFirstBroadCast"
            android:exported="true">
            <intent-filter>
                <action android:name="simple broadcast"/>
            </intent-filter>
        </receiver>
  • 高版本下使用静态注册,在发送广播的时候加上package
    /**
     * 发送广播
     */
    private void sendBroadCast() {
        Intent intent = new Intent("simple broadcast");
        intent.putExtra("key", "这是一条简单的广播");
        intent.setPackage(getPackageName());//针对高版本静态注册的广播需要添加的内容,要不然无法接收到相应的广播
        sendBroadcast(intent);
    }
  • 能正常接收到广播哈。

广播分类

  • Android的广播主要分为2种,一种是标准广播,一种是有序广播,其中标准广播发出后,所有广播接收器几乎同时接收到这条广播消息,并且不能被截断
    而有序广播同一时刻只有一个广播接收器会收到这条广播,并且可以被截断

标准广播

  • 我们上面发送的广播就是标准广播。
  • 8.0后广播在AndroidManifest.xml中注册后发送intent是接收不到广播了,看了一下原因,好像是8.0为了管理系统和节约电量特别针对广播和服务发送intent的方式启动做出的改变,也就是说广播和服务不能随意收intent了,要对广播和服务更精确的指向,所以在创建intent的时候,我们需要指定我们的广播和服务的包名加类名,为的就是精确
  • 资料说 intent.setComponent()后可以使用静态广播。但是我尝试了下,怎么都没成功,不知道是不是现在Android相关的改了。同时我尝试了另一个方法就是设置flag
//以下设置失败了
        intent.setComponent(new ComponentName("com.southwind.androidfoundation.fourassembly.broadcast"
                ,"com.southwind.androidfoundation.fourassembly.broadcast.MyFirstBroadCast"));
//以下两种设置成功了
        intent.setPackage(getPackageName());
        int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
        intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);
  • 完整设置,静态注册的广播下面两种设置人选其一就可以完成发送和接受。但是上面的那种没成功,不知道是我哪里写的有问题,别人资料是成功了的。
    /**
     * 发送广播
     */
    @SuppressLint("WrongConstant")
    private void sendBroadCast() {
        Intent intent = new Intent("simple broadcast");
        intent.putExtra("key", "这是一条简单的广播");
//        intent.setPackage(getPackageName());//针对高版本静态注册的广播需要添加的内容,要不然无法接收到相应的广播
        //第二种解决方法,传入精确的地址,即使用精确的广播接受位置 第一个参数时包名,第二个参数是类名(需要包含包名)
//        intent.setComponent(new ComponentName("com.southwind.androidfoundation.fourassembly.broadcast"
//                ,"com.southwind.androidfoundation.fourassembly.broadcast.MyFirstBroadCast"));
        int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
        intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);

        sendBroadcast(intent);
    }
有序广播
  • 前面的步骤和标准广播一样,注意有序广播的特点:同一时刻只有一个广播接收器会收到这条广播,并且可以被截断
  • 将有序广播种的sendBoardcast改成sendOrderedBroadcast(intent,null)
  • 再写一个广播接收器
public class MySecondBroadCast extends BroadcastReceiver {


    private final String TAG = "MySecondBroadCastTAG";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "第二个广播接收器,接收到广播");
        String info = intent.getStringExtra("key");
        Log.d(TAG, "广播内容:" + info);
    }
}

  • 设置广播优先级,MyFirstBroadCast设置为100,MySecondBroadCast设置为50
   <receiver
            android:name=".fourassembly.broadcast.MyFirstBroadCast"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="simple broadcast"/>
            </intent-filter>
        </receiver>
        <receiver
            android:exported="true"
            android:name=".fourassembly.broadcast.MySecondBroadCast">
            <intent-filter android:priority="50">
                <action android:name="simple broadcast"/>
            </intent-filter>
        </receiver>
  • 首先我们设置截取广播
  private final String TAG = "MyFirstBroadCastTAG";

    @Override
    public void onReceive(Context context, Intent intent) {
        //这个方法表示将截取广播,不会继续向后传递
        abortBroadcast();
        Log.d(TAG, "第一个广播接收器,接收到广播");
        String info = intent.getStringExtra("key");
        Log.d(TAG, "广播内容:" + info);
    }
}
  • 发送广播,有序广播调用的方法不同endOrderedBroadcast(intent,null)方法

    /**
     * 发送广播
     */
    @SuppressLint("WrongConstant")
    private void sendBroadCast() {
        Intent intent = new Intent("simple broadcast");
        intent.putExtra("key", "这是一条简单的广播");
//        intent.setPackage(getPackageName());//针对高版本静态注册的广播需要添加的内容,要不然无法接收到相应的广播
        //第二种解决方法,传入精确的地址,即使用精确的广播接受位置 第一个参数时包名,第二个参数是类名(需要包含包名)
//        intent.setComponent(new ComponentName("com.southwind.androidfoundation.fourassembly.broadcast"
//                ,"com.southwind.androidfoundation.fourassembly.broadcast.MyFirstBroadCast"));
        int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
        intent.addFlags(FLAG_RECEIVER_INCLUDE_BACKGROUND);

        sendOrderedBroadcast(intent,null);
    }
  • 有截取广播的运行结果


    图片.png
  • 去掉截取广播的运行结果


    图片.png
  • 从新设置优先级后的结果,这次MyFirstBroadCast优先级为10,MySecondBroadCast优先级为20
  <receiver
            android:name=".fourassembly.broadcast.MyFirstBroadCast"
            android:exported="true">
            <intent-filter android:priority="10">
                <action android:name="simple broadcast"/>
            </intent-filter>
        </receiver>
        <receiver
            android:exported="true"
            android:name=".fourassembly.broadcast.MySecondBroadCast">
            <intent-filter android:priority="50">
                <action android:name="simple broadcast"/>
            </intent-filter>
        </receiver>
图片.png
  • 上图说明了,有序广播的发送顺序是按照设置的有限级返送的,优先级高的优先发送,如果不截取广播,继续向后发送。
本地广播
  • 以上的广播都是全局的,可以被任何程序接受,就不辣么安全,这位开发者,你也不想自己的广播被别人接受是吧!!!而本地广播,只能在自己的app内发送和接收。
  • 本地广播只能动态注册不能静态注册
  • 注册本地广播
   /**
     * 注册本地广播接收器
     */
    private void initLocalReceiver() {
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        MySecondBroadCast broadCast = new MySecondBroadCast();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("simple broadcast");
        manager.registerReceiver(broadCast,intentFilter);
    }
  • 发送本地广播
    /**
     * 发送本地广播
     */
    private void sendLocalBroadCast(){
        LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
        Intent intent = new Intent("simple broadcast");
        intent.putExtra("key", "这是一条本地广播");
        manager.sendBroadcast(intent);
    }
  • 运行结果


    图片.png

常用的系统广播

  • 这些广播是手机系统发送的我们只需要接收就行
  • 即在广播接收器添加响应的action即可
监听网络变化 android.net.conn.CONNECTIVITY_CHANGE
关闭或打开飞行模式 Intent.ACTION_AIRPLANE_MODE_CHANGED
充电时或电量发生变化 Intent.ACTION_BATTERY_CHANGED
电池电量低 Intent.ACTION_BATTERY_LOW
电池电量充足(即从电量低变化到饱满时会发出广播) Intent.ACTION_BATTERY_OKAY
系统启动完成后(仅广播一次) Intent.ACTION_BOOT_COMPLETED
按下照相时的拍照按键(硬件按键)时 Intent.ACTION_CAMERA_BUTTON
屏幕锁屏 Intent.ACTION_CLOSE_SYSTEM_DIALOGS
插入耳机时 Intent.ACTION_HEADSET_PLUG
未正确移除SD卡但已取出来时(正确移除方法:设置-SD卡和设备内存-卸载SD卡) Intent.ACTION_MEDIA_BAD_REMOVAL
成功安装apk Intent.ACTION_PACKAGE_ADDED
成功删除apk Intent.ACTION_PACKAGE_REMOVED
重启设备 Intnet.ACTION_REBOOT
屏幕被关闭 Intent.ACTION_SCREEN_OFF
屏幕被打开 Intent.ACTION_SCREEN_ON
  • 我在我的接收器中添加一个屏幕关闭的广播action
         <receiver
            android:name=".fourassembly.broadcast.MyFirstBroadCast"
            android:exported="true">
            <intent-filter android:priority="10">
                <action android:name="simple broadcast" />
                <action android:name="android.intent.action.SCREEN_OFF" />
            </intent-filter>
        </receiver>
  • 上面的示例大失败,好像这种系统的广播无法通过静态注册来监听哈。
  • 转头就动态注册了下
private void initReceiver() {
        firstBroadCast = new MyFirstBroadCast();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("simple broadcast");
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);//屏幕开启
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);//屏幕关闭
        registerReceiver(firstBroadCast, intentFilter);
    }
  • 运行结果如下,在开关屏幕的时候确实接收到了广播,但是不知道具体内容


    图片.png
  • 我反手就是要给调试,让我康康intent的内容~~啊,没什么特别的内容,就一个action比较清晰,所以真要监听不同的系统广播还是分别写广播接收器分别监听吧。


    图片.png
完结撒花

相关文章

网友评论

      本文标题:Android四大组件之BroadCast

      本文链接:https://www.haomeiwen.com/subject/metxddtx.html