Android四大组件之BroadcastReceiver

什么是BroadcastReceiver

BroadcastReceiver是安卓中的四大组件之一。广播接收器,也被称为全局事件,或系统事件。
当Android系统中任何程序有动作时,如果想通知其他程序,采用广播的方式进行传播是非常有效的。广播从理论上说,可以将一个动作传播给任意多个程序(当然,广播接收器的数量会受到系统限制)。
在Android中,有一些操作完成以后,会发送广播,比如说发出一条短信,或打出一个电话,如果某个程序接收了这个广播,就会做相应的处理。这个广播跟我们传统意义中的电台广播有些相似之处。之所以叫做广播,就是因为它只负责“说”而不管你“听不听”,也就是不管你接收方如何处理。另外,广播可以被不只一个应用程序所接收,当然也可能不被任何应用程序所接收。
广播机制最大的特点就是发送方并不关心接收方是否接到数据,也不关心接收方是如何处理数据的。
Android中广播的是操作系统中产生的各种各样的事件。例如,收到一条短信就会产生一个收到短信息的事件。而Android操作系统一旦内部产生了这些事件,就会向所有的广播接收器对象来广播这些事件。

广播机制的三要素:

1、广播(Broadcast) - 用于发送广播;
2、广播接收器(BroadcastReceiver) - 用于接收广播;
3、意图内容(Intent)-用于保存广播相关信息的媒介。
Broadcast是一种广泛运用的在应用程序之间传输信息的机制。而BroadcastReceiver是对发送出来的Broadcast进行过滤接受并响应的一类组件

广播的生命周期:

1、广播接收器仅在它执行这个方法时处于活跃状态。当onReceive()返回后,它即为失活状态。
2、拥有一个活跃状态的广播接收器的进程被保护起来而不会被杀死,但仅拥有失活状态组件的进程则会在其它进程需要它所占有的内存的时候随时被杀掉。
3、如果响应一个广播信息需要很长的一段时间,一般会将其纳入一个衍生的线程中去完成,而不是在主线程内完成它,从而保证用户交互过程的流畅。 广播接收程序的时间限制为10秒。

BroadcastReceiver注册类型

  • 静态注册
静态注册主要是为了能让程序在未启动的时候也能接收广播。
清单文件中代码:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.broadcastreceiverdemo">
    <!--电话监听权限-->
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!--1、广播接收者的类名建议使用全名(包名.类名)
            2、意图过滤器中action是指的当前action能接受的广播类型(静态注册必须注明Action)。
            3、可以注册的时候给意图过滤器添加属性android:priority="100"来说明该广播的优先级。当接受有序广播时,优先级越高越先收到广播。-->
        <receiver
            android:name="com.broadcastreceiverdemo.MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
            android:priority="1000">
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
            <action android:name="android.intent.action.PHONE_STATE"/>
        </receiver>
    </application>

</manifest>
自定义BroadcastReceiver中的代码:
package com.broadcastreceiverdemo;

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

/**
 * Created by YK on 2016/8/30.
 */
public class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "dy";

    /**
     * 该方法内部写接收到广播之后的逻辑处理代码。
     * 此方法是在UI线程中执行的,所以不能执行耗时操作,10s内还未响应则报ANR。如果需要执行耗时操作,则可以启动子线程来执行。
     * @param context
     * @param intent  数据都封装在intent对象中,可以从此对象中取出需要的数据
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){
            String phoneNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
            Log.e(TAG, "onReceive: "+phoneNum);
            Toast.makeText(context, "拨打的电话号码是:" + phoneNum, Toast.LENGTH_SHORT).show();
        }else {
            Log.e(TAG, "onReceive: ");
        }
    }
}
此处监听的系统拨打电话,我用的是小米4C,发现并没有监听到拨打电话,程序是没问题的,后来我查了网上一些资料,我这手头上暂时没有别的手机,朋友们可以直接复制上面的代码自己来测试一下,以后我用别的手机测试没问题会截图说明。
  • 动态注册
BroadcastReceiver是四大组件中唯一支持使用java代码进行注册的组件(动态注册),所以在AndroidManifest文件中的注册也可以使用java代码注册来替换。动态注册的方式需要先开启应用才能接收到要接收的广播,仍然采用上面的例子,MainActivity中的代码:
package com.broadcastreceiverdemo;

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

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn;
    private MyBroadcastReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn= (Button) findViewById(R.id.btn);
        btn.setOnClickListener(this);
    }

    /**
     * 点击按钮注册广播接收者
     * @param v
     */
    @Override
    public void onClick(View v) {
        receiver = new MyBroadcastReceiver();
        IntentFilter filter=new IntentFilter();
        filter.addAction(Intent.ACTION_NEW_OUTGOING_CALL);//添加监听的Action
        registerReceiver(receiver,filter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(receiver!=null){
            unregisterReceiver(receiver);
        }
    }
}
MyBroadcastReceiver中的代码和前面的一样,拨打10086测试结果如下:

静态注册和动态注册的区别:

1、静态注册的广播接收者app一旦安装在系统,则可以接收到指定的广播。不管这个app有没有启动。 2、动态注册的广播接收者只有在注册完成后才能接收到广播,当注册他的组件销毁的时候,广播接收者也应该解除注册。

发送广播

广播的发送和接收是跨进程的,一个app发送的广播,其他的app只要权限和action匹配都可以接收到该广播,注: 发送广播的方法都是上下文对象中的方法
  • 发送标准广播
//创建意图对象,并指明action,那么意图过滤器与这个action匹配的广播接受者会
//接收到这个广播
Intent intent = new Intent("com.qianfeng.MY_BROADCAST");  
//发送出去广播
sendBroadcast(intent);
  • 发送有序广播
Intent intent = new Intent("com.qianfeng.MY_BROADCAST");  
 
//发送有序广播。  参数一:意图对象  参数二:权限。是否需要接受者需要选取才可以收到广播
sendOrderedBroadcast(intent, null);
或者:
//由于发送有序广播的时候,中间会有可能被拦截掉,参数三则指定了一个这个广播
//的最终接受者,也就说即使中间有人拦截了广播,则参数三指定的接
//受者也会最终接收到这个广播。
//其余的参数给null或0即可
/**参数一:意图对象,发送什么样的广播
 * 参数二:权限  一般不需要
 * 参数三:是最后一个收到广播的接受者,他可以不用注册,也能收到
 * 参数四:指明最终的接受者执行的线程(如果Handler对象时在子线程创建则handMessage方法是在子线程执行)。传null,怎默认是在主线程执行
 * 参数五:初始化的code
 * 参数六:初始化的数据
 * 参数七:传递比较复杂的数据可以使用Bundle对象
 * 
 * 最终的接收者收到的数据是有可能被中间的接收者篡改
 */
sendOrderedBroadcast(intent, null, receiver, null, 0, null, null);
注意:
1、发送有序广播的时候,先接到广播的可以通过下面的方法来取消广播,导致后面的优先级低的广播接收者收不到广播。
abortBroadcast(); //放弃当前的广播,则优先级低的无法收到当前广播
2、如果优先级高的广播接收者想给优先级低的广播接收者传递数据可以通过下面的方法:
setResult()
setResultData()
setResultCode()
setResultExtra()
对方用getResultData()获得数据

上述两种广播的图解说明:

  • 标准广播
标准广播(Normal broadcasts)是一种完全 异步执行的广播,在广播发出之后,所有的广播接收器几乎都会在同一时刻接收到这条广播消息,因此它们之间没有任何先后顺序可言。这种广播的效率会比较高,但同时也意味着它是无法被截断的。

  • 有序广播
有序广播(Ordered broadcasts)则是一种 同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了,甚至前面的广播可以修改广播内容再传递给下一个广播。

本地广播LocalBroadcastReceiver

LocalBroadcastManager是Android Support包提供了一个工具, 是用来在同一个应用内的不同组件间发送Broadcast的
使用LocalBroadcastManager有如下好处:
发送的广播只会在自己App内传播,不会泄露给其他App,确保隐私数据不会泄露;其他App也无法向你的App发送该广播,不用担心其他App会来搞破坏;比系统全局广播更加高效;和系统广播使用方式类似:
MainActivity中代码:
package com.broadcastreceiverdemo;

import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private Button btn,btn2;
    private MyBroadcastReceiver receiver;
    private LocalBroadcastManager localBroadcastManager;
    public static String BROAD_CAST="my broadcast";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        btn= (Button) findViewById(R.id.btn);
        btn2= (Button) findViewById(R.id.btn2);
        btn.setOnClickListener(this);
        btn2.setOnClickListener(this);
    }

    /**
     * 点击按钮注册广播接收者/发送广播
     * @param v
     */
    @Override
    public void onClick(View v) {
        if(v.getId()==R.id.btn){
            receiver=new MyBroadcastReceiver();
            IntentFilter filter=new IntentFilter();
            filter.addAction(BROAD_CAST);//只接收该Action的广播
            localBroadcastManager.registerReceiver(receiver,filter);
        }else if(v.getId()==R.id.btn2){//发送自定义Action的广播
            Intent intent=new Intent(BROAD_CAST);
            intent.putExtra("kaka","哈哈");
            localBroadcastManager.sendBroadcast(intent);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(receiver!=null){
            localBroadcastManager.unregisterReceiver(receiver);
        }
    }
}
MyBroadcastReceiver中代码:
package com.broadcastreceiverdemo;

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

/**
 * Created by YK on 2016/8/30.
 */
public class MyBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "dy";

    /**
     * 该方法内部写接收到广播之后的逻辑处理代码。
     * 此方法是在UI线程中执行的,所以不能执行耗时操作,10s内还未响应则报ANR。如果需要执行耗时操作,则可以启动子线程来执行。
     * @param context
     * @param intent  数据都封装在intent对象中,可以从此对象中取出需要的数据
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        if(intent.getAction().equals(MainActivity.BROAD_CAST)){
            Log.e(TAG, "onReceive: "+intent.getStringExtra("kaka"));
        }
    }
}
先点击Register BroadcastReceiver按钮,再点击send Broadcast按钮,打印的log信息:


LocalBroadcastReceiver代码下载: 源码

广播接收案例(接收一些系统广播)

系统在合适的时间发送广播,我们的app通过接收这些广播可以实现一些比较实用的功能。如:系统启动完成、用户外拨电话、短信来到等等,系统都会发出相应的广播。
ACTION_TIME_CHANGED :系统时间被改变;
ACTION_DATE_CHANGED : 系统日期被改变;
ACTION_TIMEZONE_CHANGED :系统时区被改变;
ACTION_BOOT_COMPLETED :系统启动完成;
ACTION_BATTERY_CHANGED : 电池电量改变;
ACTION_SHUTDOWN : 系统被关闭;
Action_BATTRY_LOW : 电池电量低;

广播接收者的一些简单应用:

1.软件自启
2.拦截外拨电话
3.短信拦截
4.网络、Wifi状态的访问等等。
参考资料:

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值