四大组件之广播

四大组件之广播

用途:

  • 在安卓开发中,当我们需要接收系统发出或者别的程序发出来的消息的时候,就需要用到广播接收器。或者我们需要在应用之中传递一些数据时,我们也可以用本地广播来发送和接收这些消息;
  • 广播在Android开发中的使用十分广泛,其功能由发送者和接收者两部分组成,与现实中的广播类似,广播台通过信号塔发射广播信号(发送广播),用户通过收音机(广播接收者)来接收广播内容。

一、Android 广播机制的概述

Android广播分为两个方面:广播发送者和广播接收者,通常情况下,BroadcastReceiver指的就是广播接收者(广播接收器)。广播作为Android组件间的通信方式,可以使用的场景如下:

  • 同一app内部的同一组件内的消息通信(单个或多个线程之间);
  • 同一app内部的不同组件之间的消息通信(单个进程);
  • 同一app具有多个进程的不同组件之间的消息通信;
  • 不同app之间的组件之间消息通信;
  • Android系统在特定情况下与App之间的消息通信。

从实现原理看上,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。具体实现流程要点粗略概括如下:

  • 广播接收者BroadcastReceiver通过Binder机制向AMS(Activity Manager Service)进行注册;
  • .广播发送者通过binder机制向AMS发送广播;
  • AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中;
  • 消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。

二、监听电量变化的广播(例子)

1.创建一个新的活动,命名为Broadcast_learning

2.首先在manifest文件下添加用户权限

<!--添加状态改变的权限-->
    <uses-permission android:name="android.permission.BATTERY_STATS"
        tools:ignore="ProtectedPermissions" />

3.在.java文件下编辑代码

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

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

        //第二步:我们要收听的频道是:电量变化
        IntentFilter intentFilter = new IntentFilter();
        //第三步:然后设置频道,这里设置的频道就是电量的变化
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        //第四部:实例化对象
        BatterLevelRecever batterLevelRecever = new BatterLevelRecever();
        //第五步:注册广播
        this.registerReceiver(batterLevelRecever, intentFilter);
    }

    //第一步,首先创建一个广播接收器,继承自BroadcastReceiver,然后覆写onReceive方法
    private class BatterLevelRecever extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "收到了状态改变的广播" + action);
        }
    }
}

个人理解就是,首先创建一个类,让其继承自BroadcastReceiver,并重写父类的onReceive()方法。当广播来临时,onReceive()就会得到调用,具体的逻辑就可以在这个方法里面处理。

4.点击运行之后,在locat中就可以看到打印出的结果

D/MainActivity: 收到了状态改变的广播android.intent.action.BATTERY_CHANGED

至此,一个监听电量变化的广播就创建好了

三、通过广播接收者显示电池电量

1.代码实现:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private TextView batterLevelText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定控件
        initView();
        RegisterBatterReveiver();
    }

    //找到控件
    public void initView(){
        batterLevelText = this.findViewById(R.id.battery_level);
    }

    //注册广播的方法
    private void RegisterBatterReveiver() {
        //我们要收听的频道是:电量变化
        IntentFilter intentFilter = new IntentFilter();
        //然后设置频道,这里设置的频道就是电量的变化
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        //实例化对象
        BatterLevelRecever batterLevelRecever = new BatterLevelRecever();
        //注册广播
        this.registerReceiver(batterLevelRecever, intentFilter);
    }

    //第一步,首先创建一个广播接收器,继承自BroadcastReceiver,然后覆写onReceive方法
    private class BatterLevelRecever extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            Log.d(TAG, "收到了状态改变的广播" + action);
            //显示电池当前电量
            Log.d(TAG, "当前电量:"+intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0));
            //首先必须进行判空,因为如果注册广播的代码在准备控件的代码之前,就会出现异常
            if (batterLevelText != null) {
                batterLevelText.setText("当前电量:"+intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0));
            }
        }
    }
}

2.效果图展示:

image-20210513165509106

3.代码优化升级

1.设置两个TextView用来显示当前电量和当前电量百分比;
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/battery_level"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <TextView
        android:layout_marginLeft="30dp"
        android:id="@+id/battery_percent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/battery_level" />

</RelativeLayout>
2.编辑代码
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private TextView batterLevelText;
    private TextView batterPercentText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定控件
        initView();
        RegisterBatterReveiver();
    }

    //找到控件
    public void initView() {
        batterLevelText = this.findViewById(R.id.battery_level);
        batterPercentText = findViewById(R.id.battery_percent);
    }

    //注册广播的方法
    private void RegisterBatterReveiver() {
        //我们要收听的频道是:电量变化
        IntentFilter intentFilter = new IntentFilter();
        //然后设置频道,这里设置的频道就是电量的变化
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        //实例化对象
        BatterLevelRecever batterLevelRecever = new BatterLevelRecever();
        //注册广播
        this.registerReceiver(batterLevelRecever, intentFilter);
    }

    //第一步,首先创建一个广播接收器,继承自BroadcastReceiver,然后覆写onReceive方法
    private class BatterLevelRecever extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
                Log.d(TAG, "收到了状态改变的广播" + action);
                //显示电池当前电量
                Log.d(TAG, "当前电量:" + intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0));
                int currentlevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
                //首先必须进行判空,因为如果注册广播的代码在准备控件的代码之前,就会出现异常
                if (batterLevelText != null) {
                    batterLevelText.setText("当前电量:" + intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0));
                }

                int maxlevel = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
                //拿到当前电量后再除以最大值
                float percent = currentlevel * 1.0f / maxlevel * 100;
                Log.d(TAG, "当前电量百分比是:" + percent + "%");
                if (batterPercentText != null) {
                    batterPercentText.setText("百分比:" + percent + "%");
                }
            }
        }
    }
}

四、监听USB线拔出及插入

1.设置频道(USB连接成功和连接失败两个频道)

 //这个频道为连接USB
        intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
        //这个频道为顿开USB
        intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);

2.USB连接或者断开,将结果打印出来

else if(Intent.ACTION_POWER_CONNECTED.equals(action)){
                Log.d(TAG, "usb连接成功");
            }else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)){
                Log.d(TAG, "usb断开");
            }

3.全部代码

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";
    private TextView batterLevelText;
    private TextView batterPercentText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //绑定控件
        initView();
        RegisterBatterReveiver();
    }

    //找到控件
    public void initView() {
        batterLevelText = this.findViewById(R.id.battery_level);
        batterPercentText = findViewById(R.id.battery_percent);
    }

    //注册广播的方法
    private void RegisterBatterReveiver() {
        //我们要收听的频道是:电量变化
        IntentFilter intentFilter = new IntentFilter();
        //然后设置频道,这里设置的频道就是电量的变化
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        //这个频道为连接USB
        intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
        //这个频道为顿开USB
        intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
        //实例化对象
        BatterLevelRecever batterLevelRecever = new BatterLevelRecever();
        //注册广播
        this.registerReceiver(batterLevelRecever, intentFilter);
    }

    //第一步,首先创建一个广播接收器,继承自BroadcastReceiver,然后覆写onReceive方法
    private class BatterLevelRecever extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
                Log.d(TAG, "收到了状态改变的广播" + action);
                //显示电池当前电量
                Log.d(TAG, "当前电量:" + intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0));
                int currentlevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
                //首先必须进行判空,因为如果注册广播的代码在准备控件的代码之前,就会出现异常
                if (batterLevelText != null) {
                    batterLevelText.setText("当前电量:" + intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0));
                }

                int maxlevel = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
                //拿到当前电量后再除以最大值
                float percent = currentlevel * 1.0f / maxlevel * 100;
                Log.d(TAG, "当前电量百分比是:" + percent + "%");
                if (batterPercentText != null) {
                    batterPercentText.setText("百分比:" + percent + "%");
                }
            }else if(Intent.ACTION_POWER_CONNECTED.equals(action)){
                Log.d(TAG, "usb连接成功");
            }else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)){
                Log.d(TAG, "usb断开");
            }
        }
    }
}

五、广播的动态注册

1.首先创建一个广播接收器类,继承自BroadcastReceiver,然后重写父类中onReceive()方法

2.实例化IntentFilter类;

3.设置频道,使用intentFilter.addAction()方法;

4.实例化广播接收器类;

5.注册广播,使用this.registerReceiver();

6.必须要销毁该广播接收器

 //取消广播注册
    @Override
    protected void onDestroy() {
        super.onDestroy();
        //取消广播注册,否则会导致内存泄露
        if (batterLevelRecever != null) {
            this.unregisterReceiver(batterLevelRecever);
        }
    }

六、以实现开机监听的例子实现静态注册广播

1.新建一个类,继承BroadcastReceiver类

public class BootCompleteReceiver extends BroadcastReceiver {
    private static final String TAG = "BootCompleteReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "action is == " + action);
        Log.d(TAG, "开机完成");
        Toast.makeText(context, "收到开机完成的广播", Toast.LENGTH_LONG).show();
    }
}

2.在manifest文件下添加一个

<!--第二步,跟动态设置action是一样的-->
        <receiver android:name=".BootCompleteReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>
    </application>

在标签下面要添加一个i标签,在标签里面在添加一个标签。

相当于动态注册时的这两部分

IntentFilter intentFilter = new IntentFilter();
//然后设置频道,这里设置的频道就是电量的变化
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);

3.在manifest文件下添加用户权限

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

静态和动态最大的区别就是,静态注册一旦完成不可终止,会一直保持监听状态。但是动态可以随时注册,随时销毁,可以和activity保持相同的生命周期

七、发送自定义广播和接收

1.新建一个活动,用来当做广播发射器

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SendBroadcastActivity"
    android:orientation="vertical">

    <EditText
        android:id="@+id/be_sent_message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入发送内容"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送一条广播通知"
        android:onClick="SendBroadCast"
        tools:ignore="OnClick" />

</LinearLayout>

一个输入框用来输入发送的广播内容,一个按钮用来发送广播

2.在.java文件中进行广播的发送

package com.example.broadcast_learning;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

public class SendBroadcastActivity extends AppCompatActivity {

    private EditText inputBox;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_send_broadcast);
        inputBox = findViewById(R.id.be_sent_message);
    }

    //点击按钮,此方法会被调用
    public void SendBroadCast(View view){
        //被调用之后发送广播
        String content = inputBox.getText().toString();
        Intent intent = new Intent();
        //设置频道
        intent.setAction(Constants.ACTION_SEND_MSG);
        //设置数据
        intent.putExtra(Constants.ACTION_CONTENT,content);
        //发送广播
        sendBroadcast(intent);
    }
}

3.创建一个工具类

用来封装自定义广播的频道和数据内容

package com.example.broadcast_learning;

public class Constants {
    public static final String ACTION_SEND_MSG = "com.example.broadcast_learning.SEND_MSG";
    public static final String ACTION_CONTENT = "content";
}

特别注意!!!

  • ACTION_SEND_MSG 这个常量的内容就是 广播发射器类的包名
  • ACTION_CONTENT 这个内容呢 就是我们从输入框中输入的值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H247wg7M-1620915208308)(C:\Users\23737\Desktop\QQ图片20210513210555.png)]

4.创建一个类,用作广播接收器

public class MessageReceiver extends BroadcastReceiver {
    private static final String TAG = "MessageReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Log.d(TAG, "action is == "+action);
        String stringExtra = intent.getStringExtra(Constants.ACTION_CONTENT);
        Log.d(TAG, "自定义广播内容是:"+stringExtra);
        Toast.makeText(context,"自定义广播内容是:"+stringExtra,Toast.LENGTH_LONG).show();
    }
}

5.因为是静态注册广播,所以在manifest文件下添加标签

<!--自定义广播-->
        <receiver android:name=".MessageReceiver">
            <intent-filter >
                <action android:name="android.intent.action.PACKAGE_ADDED"></action>
            </intent-filter>
        </receiver>

八、有序广播的发送

1.有序广播:

有序广播类似于单位的通知,由上级到下级一级一级的传达。特点是:

  • 有序;
  • 可以终止向下传达;
  • 可以修改广播的内容;

无序广播就像是上学时的学校广播,谁都能听到。有序广播就像是校长的通知,一级一级向下传达

2.有序广播的实现:

1.首先创建一个广播发射器 的活动
1.添加按钮,用来发射guangb
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SendOrderBroadcastActivity"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送一个有序广播"
        android:onClick="sendOrderBroadcast"
        tools:ignore="OnClick" />
</LinearLayout>
2.在.java 文件内编辑代码发送广播
public class SendOrderBroadcastActivity extends AppCompatActivity {

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

    public void sendOrderBroadcast(View view){
        Intent intent = new Intent();
        intent.setAction(Constants.ACTION_ORDER_BROADVAST_TEST);
        sendOrderedBroadcast(intent,null);
    }
}
2.创建一个高等级广播接收器
1.编辑代码
public class HighLevelReceiver extends BroadcastReceiver {
    private static final String TAG = "HighLevelReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "high action is "+intent.getAction());
    }
}

把高等级的广播接受到的信息打印出来

2.在manifest文件中注册,添加标签
<!--有序广播高等级-->
        <receiver android:name=".HighLevelReceiver">
            <!--priority表示等级,值是-10001000,默认为0-->
            <intent-filter android:priority="1000">
                <action android:name="com.example.broadcast_learning.ORDER_BROADCAST" />
            </intent-filter>
        </receiver>
3.创建一个低等级的广播接收器
1.编辑代码
public class HighLevelReceiver extends BroadcastReceiver {
    private static final String TAG = "HighLevelReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "high action is "+intent.getAction());
    }
}
2.在manifest中添加标签
<!--有序广播低等级-->
        <receiver android:name=".LowLevelReceiver">
            <!--priority表示等级,值是-1000到1000,默认为0-->
            <intent-filter android:priority="0">
                <action android:name="com.example.broadcast_learning.ORDER_BROADCAST" />
            </intent-filter>
        </receiver>
4.然后一个有序广播就可以了,创建两个等级不同的接收器是想看看有序广播有序在哪里。

3.高等级广播接收器终止广播

public class HighLevelReceiver extends BroadcastReceiver {
    private static final String TAG = "HighLevelReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "high action is "+intent.getAction());

        //终止向下传达
        abortBroadcast();
    }
}

4.修改广播内容

1.在广播发射器中准备广播内容
public class SendOrderBroadcastActivity extends AppCompatActivity {

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

    public void sendOrderBroadcast(View view){
        Intent intent = new Intent();
        intent.setAction(Constants.ACTION_ORDER_BROADVAST_TEST);

        //准备广播数据
        Bundle bundle = new Bundle();
        bundle.putCharSequence("content","我是要被发送的广播内容");

        sendOrderedBroadcast(intent,null,null,null, Activity.RESULT_OK,null,bundle);
    }
}
2.在广播接收器中修改广播内容
public class HighLevelReceiver extends BroadcastReceiver {
    private static final String TAG = "HighLevelReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d(TAG, "high action is "+intent.getAction());

        //终止向下传达
        abortBroadcast();
        //修改广播内容
        Bundle resultExtras = getResultExtras(true);
        String content = resultExtras.getCharSequence("content").toString();
        Log.d(TAG, "content-->"+content);
    }
}

5.修改广播的权限

1.在manifest文件中 设置权限(注意不是用户权限):
 <!--首先定义权限-->
    <permission android:name="com.example.broadcast_learning.ORDER_PERMISSION"/>
2.在广播发射器发送广播时候,添加上这个权限
 public void sendOrderBroadcast(View view){
        Intent intent = new Intent();
        intent.setAction(Constants.ACTION_ORDER_BROADVAST_TEST);

        //准备广播数据
        Bundle bundle = new Bundle();
        bundle.putCharSequence("content","我是要被发送的广播内容");

        sendOrderedBroadcast(intent,Manifest.permission.ORDER_PERMISSION,null,null, Activity.RESULT_OK,null,bundle);
    }
3.新建一个广播接收活动
4.在广播接收活动中manifest文件 设置同样的权限
<!--首先定义权限-->
    <permission android:name="com.example.broadcast_learning.ORDER_PERMISSION"/>

这一步很重要,不然接收不到

5.然后在广播接收活动中设置一个接收类就好了
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值