Android学习——四大核心组件(BroadcastReceiver)

四大核心组件之BroadcastReceiver

1.BroadcastReceiver简介

BroadcastReceiver也就是"广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播。

在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服务的功能:当网络状态改变时系统会产生一条广播,接收到这条广播就能及时地做出提示和保存数据等操作;当电池电量改变时,系统会产生一条广播,接收到这条广播就能在电量低时告知用户及时保存进度,等等。

Android中的广擂机制设计的非常出色。很多事情原本需要开发者亲自操作的,现在只需等待广播告知自己就可以了,大大减少了开发的工作量和开发周期。而作为应用开发者,就需要数练掌握Android系统提供的一个开发利器,那就是BroadcastReceiver。

2.广播接收器的类型

(1)Normal broadcasts:默认广播
发送一个默认广播使用Context.sendBroadcast()方法,普通广播对于多个接受者来说是完全异步的,通常每个接收者都无需等待就可以接收到广播,接受者相互之间不会有影响。对于这种广播,接受者无法终止广播,即无法阻止其他接受者的接收动作。
(2)Ordered broadcasts:有序广播
发送一个有序广播使用Context.sendOrderedBroadcast()方法,有序广播比较特殊,它每次只发送到优先级较高的接收者那边,然后由优先级高的接受者再传播到优先级低的接受者那里,优先级高的接受者有能力终止这个广播。
(3)Sticky broadcasts:粘性广播
处理完之后的Intent,依然存在,直到你把它去掉。

3.广播接收器的创建步骤

构建一个Intent,使用sendBroadcast方法发送广播

//发送一个普通的广播
    public void sendNormalClick(View v){
        Intent intent=new Intent("com.action.MY_BROADCASTS");//设置action当做广播频道
        intent.putExtra("info","这是一个普通广播频道");//发送数据
        this.sendBroadcast(intent);
    }

定义一个广播接收器,该广播接收器继承BroadcastReceiver,并且覆盖onReceive()方法来响应事件

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

/*
* 自定义的广播接收器
* */
public class MyNormalReceiver extends BroadcastReceiver {
    public MyNormalReceiver(){

    }

    //接收
    @Override
    public void onReceive(Context context, Intent intent) {
        String info=intent.getStringExtra("info");//接收信息
        Toast.makeText(context, info, Toast.LENGTH_SHORT).show();
    }
}

注册该广播接收器,我们可以在代码中注册,也可以在AndroidManifest.xml配置文件中注册

<receiver
            android:name=".MyNormalReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.action.MY_BROADCASTS"></action>
            </intent-filter>
        </receiver>

在这里插入图片描述

4.注册广播接收器的两种方式

静态注册:静态注册是在AndroidManifest.xml配置文件中注册

动态注册:需要在代码中动态指定广播地址并注册,通常我们是在Activity或Service注册一个广播。

//在该方法中进行广播注册
    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.action.MY_BROADCASTS");
        registerReceiver(myReceiver, filter);
    }
    //在该方法中解除广播
    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(myReceiver);
    }
    //发送一个广播
    public void sendNormalClick(View v){
        Intent intent=new Intent("com.action.MY_BROADCASTS");
        this.sendBroadcast(intent);
    }

广播接收器

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
/*
* 动态注册的广播接收器
* */
public class MyReceiver extends BroadcastReceiver {

    public MyReceiver(){

    }
    @Override
    public void onReceive(Context context, Intent intent) {
    	String info=intent.getStringExtra("info");//接收信息
        Toast.makeText(context, "动态注册的广播接收器", Toast.LENGTH_SHORT).show();
    }
}

在这里插入图片描述
注意:
在这个方法发来的广播中,代码注册方式中,收到法广播的先后和著名优先级最高的他们的先后是随机的。如果没有优先级,代码接收会优先接收。

5.有序广播

发送有序广播: sendOrderedBroadcast()

在注册广播中的中使用android:priority属性。这个属性的范围在-1000到1000,数值越大, 优先级越高。

在广播接收器中使用setResultExtras方法将一个Bundle对象设置为结果集对象。传递到下一个接收者那里,这样优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。

使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数,如果为null则表示不要 求接收者声明指定的权限,如果不为null,则表示接收者若要接收此广播,需声明指定权限。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有栏截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。

终止广播传递:abortBroadcast();

同级别接收先后是随机的,再到级别低的接收广播;如果衔接受到的把广播截断了,同级别以外的接受者是无法收到该广播的。

在这个方法发来的广播中(代码注册方式),收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为优先

构建一个Intent,发送广播

//发送一个有序广播
    public void sendOrderClick(View v){
        Intent intent=new Intent("com.action.MY_BROADCASTS2");
        //参数:intent,接收权限
        this.sendOrderedBroadcast(intent,null);
    }

定义两个个广播接收器,分别为1,2

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

/*
* 有序广播接收器
* */
public class MyOrderedReceiver extends BroadcastReceiver {
    public MyOrderedReceiver(){

    }
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "有序广播-1", Toast.LENGTH_SHORT).show();
    }
}

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyOrderedReceiver2 extends BroadcastReceiver {
    public MyOrderedReceiver2(){

    }
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "有序广播-2", Toast.LENGTH_SHORT).show();
    }
}

注册该广播接收器,设置优先级

<receiver
            android:name=".MyOrderedReceiver2"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.action.MY_BROADCASTS2" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".MyOrderedReceiver"
            android:enabled="true"
            android:exported="true" >
            <intent-filter android:priority="200">
                <action android:name="com.action.MY_BROADCASTS2" />
            </intent-filter>
        </receiver>

在这里插入图片描述在这里插入图片描述
在广播接收器中使用setResultExtras方法将一个Bundle对象设置为结果集对象,传递到下一个接收者。

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

/*
* 有序广播接收器
* */
public class MyOrderedReceiver extends BroadcastReceiver {
    public MyOrderedReceiver(){

    }
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "有序广播-1", Toast.LENGTH_SHORT).show();

        Bundle data=new Bundle();
        data.putString("info","广播-1");
        this.setResultExtras(data);

    }
}

在这里插入图片描述
中断有序广播

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.widget.Toast;

/*
* 有序广播接收器
* */
public class MyOrderedReceiver extends BroadcastReceiver {
    public MyOrderedReceiver(){

    }
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "有序广播-1", Toast.LENGTH_SHORT).show();

        Bundle data=new Bundle();
        data.putString("info","广播-1");
        this.setResultExtras(data);
        //中断有序广播
        this.abortBroadcast();
    }
}

广播中断,便不会在出现广播下一个广播

6.粘性广播

发送粘性广播使用:sendStickyBroadcast(intent);
发这个广播需要权限

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

去掉使用removeStickyBroadcast(intent);方法

sendStickyOrderedBroadcast():这个方法有有序广播的特性也有粘性广播的特性;在这个方法发来的广播中,代码注册方式中,收到广播先后次序为:注明优先级的、代码注册的、没有优先级的;如果都没有优先级,代码注册收到为最先。

创建Intent

//发送一个粘性的广播
    public void sendStickyClick(View v){
        Intent intent=new Intent("com.action.MY_BROADCASTS3");
        this.sendStickyBroadcast(intent);
    }

    //启动接收粘性广播Activity
    public void openStickyActivityClick(View v){
        Intent intent=new Intent(this,Main2Activity.class);
        startActivity(intent);
    }

定义接收器

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

public class MyStickyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "接受一个粘性广播", Toast.LENGTH_SHORT).show();
    }
}

创建一个新的activity,并注册接收器

package com.example.broadcastreceiver;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;

public class Main2Activity extends AppCompatActivity {
    private MyStickyReceiver myStickyReceiver=new MyStickyReceiver();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);

    }

    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter=new IntentFilter("com.action.MY_BROADCASTS3");
        registerReceiver(myStickyReceiver,filter);
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(myStickyReceiver);
    }
}

注意:
需要在清单文件中设置权限

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

在这里插入图片描述在这里插入图片描述
注意:
在重写onResume()方法时,不要执行长时间的操作,不能超过10秒,否则会抛出异常,若要执行长时间操作需要用service组件去完成。

7.接收系统广播

1.开机启动服务
我们经常会有这样的应用场合,比如消息推送服务,需要实现开机启动的功能。要实现这个功能,我们就可以订阅系统“启动完成”这条广播,接收到这条广播后我们可以启动自己的服务了。

定义广播接收器

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;

/*
* 开机启动的广播接收器
* */
public class MyReceiver2 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "开机啦", Toast.LENGTH_SHORT).show();
    }
}

注册开机广播地址

<receiver
            android:name=".MyReceiver2"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>

设置权限

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

2.网络状态变化
比如用户浏览网络信息时,网络突然断开,我们要及时地提醒用户网络已断开。要实现这个功能,我们可以接收网络状态改变这样一条广播,当由连接状态变为断开状态时,系统就会发送一条广播,我们接收到之后,再通过网络的状态做出相应的操作。

定义广播接收器

package com.example.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.widget.Toast;

public class MyReceiver3 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        ConnectivityManager cm= (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info=cm.getActiveNetworkInfo();
        if (info!=null){
            String name=info.getTypeName()+"";
            Toast.makeText(context, name, Toast.LENGTH_LONG).show();
        }
    }
}

注册

<receiver
            android:name=".MyReceiver3"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.CONFIGURATION_CHANGED"></action>
            </intent-filter>
        </receiver>

访问网络状态权限

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

3.电量变化
如果我们在使用阅读软件,可能是全屏阅读,这个时候用户看不到剩余的电量,我们可以为他们提供电量信息。要想做到这一点,我们需要接受一条电量变化的广播,然后获取百分比信息。

定义广播接收器

/*
* 监测电量变化
* */
public class MyReceiver4 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        int curr=intent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);//当前电量
        int total=intent.getIntExtra(BatteryManager.EXTRA_SCALE,1);//从电量
        int percent=curr*100/total;
        Toast.makeText(context, "当前电量为"+percent, Toast.LENGTH_SHORT).show();
    }
}

注册广播接收器

<receiver
            android:name=".MyReceiver4"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BATTERY_CHANGED"></action>
            </intent-filter>
        </receiver>

要立即获取电量的,而不是等电量变化的广播,可以使用以下代码获取:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //立即获取电量信息的方法
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("android.intent.action.BATTERY_CHANGED");
        Intent batteryIntent=getApplicationContext().registerReceiver(null,intentFilter);
        int curr=batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL,0);//当前电量
        int total=batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE,1);//从电量
        int percent=curr*100/total;
        Toast.makeText(this, "当前电量为"+percent, Toast.LENGTH_SHORT).show();
    }

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/UUUUUltraman/article/details/88988736