从零开始水安卓——安卓四大组件BroadcastReceiver

BroadcastReceiver

概述

BroadcastReceiver翻译过来是"广播接收者”的意思,与字面意思相同,它的功能就是用来接收来自系统和应用中的广播。

下面是API中对其的一些描述:

  • 广播接收器是一种用于响应系统范围广播通知的组件。
  • 许多广播都是由系统发起的 — 例如,通知屏幕已关闭、电池电量不足或已拍摄照片的广播。
  • 应用也可以发起广播 — 例如,通知其他应用某些数据已下载至设备,并且可供其使用。
  • 尽管广播接收器不会显示用户界面,但它们可以创建状态栏通知,在发生广播事件时提醒用户。
  • 但广播接收器更常见的用途只是作为通向其他组件的“通道”,设计用于执行极少量的工作。 例如,它可能会基于事件发起一项服务来执行某项工作。
  • 广播接收器作为 BroadcastReceiver 的子类实现,并且每条广播都作为 Intent 对象进行传递。

在Android系统中,广播体现在方方面面,例如:

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

Android中的广播机制设计的非常出色。

很多事情原本需要开发者亲自操作的,现在只需等待广播告知自己就可以了,大大减少了开发的工作量和开发周期。

而作为应用开发者,只需要数练掌握Android系统提供的这个开发利器——BroadcastReceiver。

类型

广播接收器通常分如下三个类型:

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

 创建一个广播接收器

准备工作:准备一个Button

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/normal"
        android:onClick="normal"
        android:text="发送一个普通的广播"
        app:layout_constraintTop_toTopOf="parent"/>

除此之外,还需要准备一个Broadcast receiver

创建完毕后 配置清单文件会我们注册这个receiver

package com.example.a4_5broadcastreceiver;

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

//自定义的广播接收器
public class MyReceiver extends BroadcastReceiver {

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

接着书写onClick事件:在学习intent的时候,我们已经知道,activity、service、broadcast receiver组件的交互都是依靠intent的,所以我们在这里需要构建一个Intent(参数为action,需要对应的在配置清单文件加上这个action,并嵌套一个intent-filter)

由于发送的是普通(默认)的广播,所以最后需要使用sendBroadcast()方法。

package com.example.a4_5broadcastreceiver;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

    //发送一个普通的广播
    public void normal(View view){
        Intent intent=new Intent("com.example.action.MY_BROADCAST");
        intent.putExtra("info","发送了一个普通的广播");
        this.sendBroadcast(intent);
    }
}

在8.0及以上版本,上面的方法(静态注册)是不能正常实现的,请换用更低版本的模拟器进行测试,或者跳过这个案例继续看文章。

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

 

  1. 静态注册:在AndroidManifest.xml文件中配置。(即上面演示的案例)
  2. 动态注册:需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service注册一个广播

注意:
动态注册的优先级高于静态注册

 

下面给出一个动态注册的案例

依旧需要需要一个Broadcast receiver,之前提到配置清单文件会自动注册,由于选择了动态注册,所以把配置清单文件里的注册的部分去掉(或注释掉)

我们简单的写一下:

package com.example.a4_5broadcastreceiver;

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_LONG).show();
    }
}

重点是MainActivity如何注册Broadcast receiver:

先new一个Broadcast receiver对象

在onResume中广播注册(通过IntentFilter过滤动作,通过registerReceiver注册)

在onPause中解除广播注册

package com.example.a4_5broadcastreceiver;

import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private MyReceiver2 myReceiver2 = new MyReceiver2();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    //发送一个普通的广播
    public void normal(View view){
        Intent intent=new Intent("com.example.action.MY_BROADCAST");
        intent.putExtra("info","发送了一个普通的广播");
        this.sendBroadcast(intent);
    }
    //该方法中进行广播注册(动态)
    @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.example.action.MY_BROADCAST");
        registerReceiver(myReceiver2, filter);
    }
    //在该方法中解除广播注册
    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(myReceiver2);
    }
}

 

有序广播

之前两个案例都是关于默认广播的,现在给出有序广播的案例,下面是一些注意事项和补充说明。

  • 需要用到android:priority属性:这个属性可以控制优先级,范围在-1000到1000,数值越大, 优先级越高。
  • 如果是同级别接收先后将是随机的。
  • 使用sendOrderedBroadcast方法发送有序广播时,需要一个权限参数。这样做是从安全角度考虑的,例如系统的短信就是有序广播的形式,一个应用可能是具有栏截垃圾短信的功能,当短信到来时它可以先接受到短信广播,必要时终止广播传递,这样的软件就必须声明接收短信的权限。

参数如下:

null——不要求接收者声明指定的权限。

不为null——接收者若要接收此广播,需声明指定权限。

 

为了更好的体现有序广播的特性,我们建立两个接收器,并重写onReceive方法....

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "低优先级的Receive", Toast.LENGTH_LONG).show();
    }
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"高优先级的Receive",Toast.LENGTH_LONG).show();
    }

同样准备一个按钮,并完成对应的点击事件 

    //发送一个有序的广播
    public void order(View view){
        Intent intent=new Intent("com.example.action.MY_BROADCAST2");
        //参数:intent ,接收权限具体细节见上面的补充说明
        this.sendOrderedBroadcast(intent,null);
    }

 再对它们配置清单文件的android:priority属性进行设置。

效果会是,先出现高优先级的广播,再出现低优先级的广播。

当然这样子还不能完全体现出有序广播的全部特殊之处。我们进一步研究下去。

说明:

  • 终止广播传递:abortBroadcast(),高优先级的接收者可以终止广播传递。这个就不测试了,效果就是如果被终止,后面的广播就不显示了。
  • 在广播接收器中使用setResultExtras方法将一个Bundle对象设置为结果集对象。传递到下一个接收者那里,这样优先级低的接收者可以用getResultExtras获取到最新的经过处理的信息集合。

修改两个接收器

package com.example.a4_5broadcastreceiver;

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

public class MyReceiver4 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"高优先级的Receive",Toast.LENGTH_LONG).show();
        Bundle data=new Bundle();
        data.putString("info","放入了一段内容");
        this.setResultExtras(data);
    }
}
package com.example.a4_5broadcastreceiver;

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

public class MyReceiver3 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle data= getResultExtras(false);
        String info= data.getString("info");
        Toast.makeText(context, "低优先级的Receive/"+info, Toast.LENGTH_LONG).show();

    }
}

可以看到,低优先级的Receive收到了经过处理之后的最新广播。

 

粘性广播

下面是关于粘性广播的案例。

注意事项:

  • 使用sendStickyBroadcast()来发送粘性广播

  • 使用sendStickyOrderedBroadcast()来发送兼具有序广播和粘性广播的特性的广播(优先级情况和之前类似)

  • 粘性广播需要在配置清单提供<uses-permission android:name="android.permission.BROADCAST_STICKY" />的权限

  • 使用removeStickyBroadcast()来解除粘性广播

在配置清单加入权限

一个按钮?及其点击事件方法

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/sticky"
        android:onClick="sticky"
        android:text="发送一个粘性广播"
        app:layout_constraintTop_toBottomOf="@id/order"/>
    //发送一个粘性广播
    public void sticky(View view) {
        Intent intent = new Intent("com.example.action.MY_BROADCAST3");
        this.sendStickyBroadcast(intent);
    }

一个广播接收器 (并进行动态注册)

package com.example.a4_5broadcastreceiver;

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

public class MyReceiver5 extends BroadcastReceiver {

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

为了测试粘性广播特性,额外加一个Activity并额外加一个按钮启动这个Activity

package com.example.a4_5broadcastreceiver;

import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class Main2Activity extends AppCompatActivity {

    private MyReceiver5 myReceiver5 = new MyReceiver5();
    @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.example.action.MY_BROADCAST3");
        registerReceiver(myReceiver5,filter);
    }

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

效果如下: 

显然接收器注册在发送广播之后,但是依然收到了广播。

系统广播

安卓内置了不少系统级的广播,使用步骤与前面的案例无异,下面简单的提供一些案例。

开机启动服务

一个接收器

package com.example.a4_5broadcastreceiver;

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

//开机启动服务
public class MyReceiver6 extends BroadcastReceiver {

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

还需要设置权限

配置action

如此一来就可以在开机启动的时候推送广播了。

然后模拟器上可能看不出来效果...orz

网络状态变化

准备一个接收器

package com.example.a4_5broadcastreceiver;

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 MyReceiver7 extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //系统级服务,网络管理服务
        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        //网络活动信息,可以从info中拿到网络类型名
        NetworkInfo info = cm.getActiveNetworkInfo();
        if (info != null) {
            String name = info.getTypeName() + "";
            Toast.makeText(context, name, Toast.LENGTH_LONG).show();
        }
    }
}

设置权限

对应的action

然后模拟器上可能同样看不出来....

电量变化

同样一个接收器

package com.example.a4_5broadcastreceiver;

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

//电池电量变化
public class MyReceiver8 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();
    }
}

设action(这个不用额外设置权限)

然后模拟器上还是可能看不出来

不过这个可以抢救一下

改成动态注册(不监测电量变化,而是直接输出当前电量)

无视第三第四行...(是之前的遗留产物)

   @Override
    protected void onResume() {
        super.onResume();
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.example.action.MY_BROADCAST");
        registerReceiver(myReceiver2, filter);

        //立即获取电量信息的方法
        IntentFilter intentFilter=new IntentFilter();
        intentFilter.addAction("android.intent.action.BATTERY_CHANGED");
        Intent intent=getApplicationContext().registerReceiver(null,intentFilter);
        //当前电量
        int curr = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
        //总电量
        int total = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
        //计算百分比
        int percent = curr * 100 / total;
        Toast.makeText(this, "当前电量为" + percent, Toast.LENGTH_SHORT).show();
    }

效果如?

收发短信

安卓的收发短信其实也是通过广播(有序广播)来实现的,下面带来一组收发短信的案例。

发送短信

安卓中已经自带发送短信的应用,所以我们只需要进行集成调用即可。

  • 获取默认的消息管理器:SmsManager manager=SmsManager.getDefault()
  • 拆分长短信:ArrayList list=manager.divideMessage(String txt)
  • 发送短信:manager.sendTextMessage(String phone,null,String content,null,null)
  • 发送短信还需要设置权限  <uses-permission android:name="android.permission.SEND_SMS"/>

准备一个按钮

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/send"
        android:onClick="send"
        app:layout_constraintTop_toTopOf="parent"
        android:text="发送短信"/>

书写点击事件

package com.example.a4_5message;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

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

    public void send(View view) {
        //获取短信管理器
        SmsManager smsManager = SmsManager.getDefault();
        String message = "你好,这是一条测试短信";
        //拆分长短信
        ArrayList<String> list = smsManager.divideMessage(message);
        int size = list.size();
        for (int i = 0; i < size; i++) {
            //第一个参数为电话号码
            smsManager.sendTextMessage("10086", null, list.get(i), null, null);
        }
    }
}

 

接收短信

之前提到了,安卓的短信也是靠广播(有序广播)来实现的,主要指的就是接收广播。

  • 接收该广播的Action:android.provider.Telephony.SMS_RECEIVED
  • 接收短信也需要设置权限  <uses-permission android:name="android.permission.RECEIVE_SMS"/>

创建接收器并在配置清单设置对应的权限及Action,见?(过程不表)

package com.example.a4_5message;

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

public class MyReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle=intent.getExtras();
        if (bundle!=null){
            //通过pdus获得接收到的所有短信消息,获取短信内容
            Object[] objs= (Object[]) bundle.get("pdus");
            //构建短信对象数组
            SmsMessage[] smsMessages=new SmsMessage[objs.length];
            for (int i=0;i<objs.length;i++){
                //获取单挑短信内容,以pdu格式存储,并生成短信对象
                smsMessages[i]=SmsMessage.createFromPdu((byte[])objs[i]);
                //发送方的号码
                String number=smsMessages[i].getDisplayOriginatingAddress();
                System.out.println(number);
                //获取短信的内容
                String content=smsMessages[i].getDisplayMessageBody();
                System.out.println(content);
                Toast.makeText(context, number+"---"+content, Toast.LENGTH_LONG).show();
            }
            //黑名单...
            abortBroadcast();
        }
    }
}

注意:亲测上述方案只支持API23及以下

效果如下: 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云无心鸟知还

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值