Android开发之一起来学BroadcastReceiver

业精于勤,荒于嬉;行成于思,毁于随。---韩愈

在Android开发中BroadcastReceiver的使用是非常广泛的它也是Android的四大组件之一,翻译成汉语就是:"广播接收者",那么什么是广播呢?举个日常生活的例子,在农村大队里村干部这里会有一个大喇叭,用来发送广播通知各种事情,假如由于小花超生通知小花和小明来开会村干部就会通过大喇叭说:”喂,咱庄上的人注意了,小花和小明请以最快的速度来开会"。这个广播发出之后,首先这个庄上的所有人都听到了广播,村民们根据广播的内容选择去还是不去,小花和小明听到广播后开始分析:"小花和小明去开会,我是小花,我应该去开会"小明也是如此,村民们虽然听到了广播,但是分析后发现跟我没关系啊,于是继续干自己的事情。这是我们生活中的广播的形式,那么在android中广播是怎么一回事呢?一起来揭开它的面纱吧。

Android中的BroadcastReceiver的设计不得不让人拍案叫绝,它大大减少了开发者的工作量,假如现在要实现功能检测电池的电量少于10%进入省电模式,如果没有广播,我们要设监听,注册监听器,然后处理。这样是不是很麻烦?用广播就很爽啊,当电池的电量改变时系统会发出一条广播我们只需要接收这条广播然后判断它是否低于10%就行了。这样工作量大大的减少了!这只是广播的一个小的应用,除此之外当手机的网络变化、手机开机时等系统也会发出一条广播,我们可以收到此广播做自己想要的处理

下面我们结合实例来对BroadcastReceiver做详细的阐述,如有疑问欢迎提问,如有谬误欢迎批评指正,谢谢

一、 广播分类

1.普通广播

普通广播是完全异步的,所谓异步就是说这个广播可以在同一时刻(逻辑上)被所有广播接收者接收到,消息传递的效率比较高,但缺点是:接收者不能将接收到的数据处理后将处理结果传递给下一个接收者,并且无法终止广播Intent的传播;

这种广播的发送方式是:Context.SendBroadcast();

2.有序广播

然而有序广播是按照接收者声明的优先级别声明方式如下

<receiver 
       android:name=".broadcastreceiver.FirstBroadcastReceiver">
            <intent-filter android:priority="Integer" >
                <action android:name="com.example.BroadcastReceiver" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

在intent-filter元素的android:priority属性中配置优先级,数越大优先级别越高,取值范围:-1000到1000。也可以调
用IntentFilter对象的setPriority()进行设置,配置好优先级后当广播过来时被接收者依次接收广播。假如现在现在有三个接收者Receiver1、Receiver2、Receiver3

如:Receiver1的级别高于Receiver2,Receiver2的级别高于Receiver3,那么当发送一个有序广播的时候,广播会先发给Receiver1,然后再发给Receiver2,最后传给Receiver3。Receiver1收到广播后可以对广播进行处理:

(1)可以往广播里存入数据,当广播传给Receiver2时,Receiver2可以从广播中得到Receiver1存入的数据。

(2)中断广播调用BroadcastReceiver.abortBroadcast()这个方法进行广播的中断,中断后Receiver2、Receiver3将收不到此条广播

这种广播的发送的方式是:Context.sendOrderedBroadcast();

按来源分(这是我自己的想的,哈哈)

1.自己定义的广播

2.系统广播就是系统里面自带的广播

二、广播的注册方式

广播的注册方式可以分为两种

1.静态注册

这种方式是在AndroidManifest.xml清单文件中注册的注册方式如下

   <receiver 
      android:name = ".broadcastreceiver.FirstBroadcastReceiver">
            <intent-filter>
               < action android:name ="com.example.BroadcastReceiver" />
               < category android:name ="android.intent.category.DEFAULT" />
            </intent-filter>
    </receiver>

配置了以上信息之后,只要是com.example.BroadcastReceiver这个地址的广播,广播接收者都能够接收的到。注意,这种方式的注册是常驻型的,也就是说当应用关闭后,如果有广播信息传来,广播接受者也会被系统调用而自动运行。

2.动态注册

动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service(在服务中监听网络的状态,电量的变化,然后在服务中发出一个广播)注册一个广播,

注:动态注册的广播是非常驻型广播,当应用程序结束了,广播自然就没有了,比如你在activity中的onCreate或者onResume中注册广播,同时你必须在onDestory或者onPause中取消广播订阅。不然会报异常。

注册广播的代码如下

    FirstBroadcastReceiver firstBroadcastReceiver= new FirstBroadcastReceiver();
    IntentFilter intentFilter= new IntentFilter();
    intentFilter.addAction( "com.example.BroadcastReceiver" );
    registerReceiver(firstBroadcastReceiver,intentFilter);

可能有的朋友会问,为什么registerReceiver和SendBroadcastReceiver在Activity和Service中可以直接用,我们看看它们的继承关系图:

 

通过这四张图看明白了吧,registerReceiver和sendBroadcast是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,所以可以直接调用,但是如果我们在其它的类中的话是不可以直接调用的可以通过Conext.sendBroadcast的方式进行调用。

还有一点需要注意,当我们的在Activity或Service中执行了销毁操作但是没有解除注册的话会抛异常,虽然不影响程序的运行,但是作为一名有经验的开发人员,我们要保证代码的严谨性(说这话没别的意思,就是装个B,哈哈)抛出的异常提示是否忘记调用unregisterReceiver()方法了,异常如下

所以我们要根据需要在合适的地方解除注册假如我们在onDestroy中解除注册代码如下

 @Override
      protected void onDestroy() {
            super.onDestroy();
           unregisterReceiver( firstBroadcastReceiver );
     }

下面我们通过实例来对上面的理论进行测试,来进一步的加深印象,看看广播是怎么发出的,是怎么被接收的

三、BroadCastReceiver实例详解

1.关于静态和动态注册广播的讨论

首先创建BroadcastReceiver

在创建BroadcastReceiver时需要声明一个类来继承android.content.BroadcastReceiver包下的BroadcastReceiver并且复写其中的onReceive方法示例代码

package com.example.broadcastreceiverpractice.broadcastreceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class FirstBroadcastReceiver extends BroadcastReceiver {

     private static final String TAG = "FirstBroadcastReceiver" ;
      @Override
      public void onReceive(Context context, Intent intent) {
           String getFromBroadcast = intent.getStringExtra("key" );
           Log. i( TAG,getFromBroadcast);
     }
}

在onReceive方法中我们通过获得广播传过来的数据来进行测试是否收到了我们所需要的广播,进行到这儿还有更重要的一步,那就是注册广播假如我们不注册广播的话,我们想向这个广播接收者发消息的话就无法发送,因为找不到和这个广播对应的东西,注册广播可以分为两种上面已经提到了我们再来通过实例说一遍

<receiver 
   android:name =".broadcastreceiver.FirstBroadcastReceiver" >
            <intent-filter>
               <action android:name ="com.example.BroadcastReceiver" />
               <category android:name ="android.intent.category.DEFAULT" />
            </intent-filter>
  </receiver>

配置以上内容的作用就是说从当前Receiver只接收从com.example.BroadcastReceiver发过来的广播,这样广播发送者和接收者就建立了联系了。当从com.example.BroadcastReceiver发出广播时系统就会自动调用这个广播接收者来进行相关的操作

说了这么多我们在Activity中测试一下吧

package com.example.broadcastreceiverpractice;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

      private Button btn_send;

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

            btn_send=(Button) findViewById(R.id. btn_send);
            btn_send.setOnClickListener( new OnClickListener() {

                 public void onClick(View v) {
                      //发送一条广播com.example.BroadcastReceiver要和广播接收者在清单文件中配置的相同
                     Intent intent = new Intent("com.example.BroadcastReceiver" );
                     intent.putExtra( "key", "MainActivity中发了一条广播" );
                     sendBroadcast(intent);
                }
           });
     }
}

我们点击几次发送按钮在广播接收者中打印内容如下

说明我们已经接收到了广播

(2)动态注册

在原来的基础上我们把AndroidManifest.xml清单文件中的静态的注册的代码去掉

只去掉<intent-filter></intent-filter>之间的内容即可,广播接收者是四大组件我们必须注册,大家要把广播接收者是四大组件之一的注册和为了接收自己设定的地址发过来的广播而进行的注册区分开。

package com.example.broadcastreceiverpractice;

import com.example.broadcastreceiverpractice.broadcastreceiver.FirstBroadcastReceiver;

import android.app.Activity;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {

      private Button btn_send;
      private FirstBroadcastReceiver firstBroadcastReceiver;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
           setContentView(R.layout. activity_main);
            firstBroadcastReceiver = new FirstBroadcastReceiver();
            //声明过滤器
           IntentFilter intentFilter= new IntentFilter();
          intentFilter.addAction( "com.example.BroadcastReceiver" );
            //将添加的动作和声明的广播接收者绑定到一起,和我们在清单文件中配置的作用是一样的
          registerReceiver( firstBroadcastReceiver,intentFilter);

            btn_send=(Button) findViewById(R.id. btn_send);
            btn_send.setOnClickListener( new OnClickListener() {

                 public void onClick(View v) {
                      //发送一条广播com.example.BroadcastReceiver要和广播接收者在清单文件中配置的相同
                     Intent intent = new Intent("com.example.BroadcastReceiver" );
                     intent.putExtra( "key", "MainActivity中发了一条广播" );
                     sendBroadcast(intent);
                }
           });
     }

      @Override
      protected void onDestroy() {
            super.onDestroy();
            //解除注册
           unregisterReceiver( firstBroadcastReceiver);
     }
}

我们点击几次按钮发送广播打印内容如下

关于动态注册广播的特点以及注意事项在"二"中已经说了,这里就不再重复说了唯一要提的一点就是别忘了解除注册。

但是问题来了,上面只是一个广播,假如我们我们有多个广播呢,谁先接收呢,能同时接收吗等等问题,要想弄清这个问题必须掌握普通广播和有序广播

2.有序广播和普通广播

(1)普通广播

要讨论这个问题你我们首先新建三个广播

分别如下

package com.example.broadcastreceiverpractice.broadcastreceiver;

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

public class FirstBroadcastReceiver extends BroadcastReceiver {

      private static final String TAG = "FirstBroadcastReceiver" ;

      @Override
      public void onReceive(Context context, Intent intent) {
            String getFromBroadcast = intent.getStringExtra("key" );
           Log. i( TAG,getFromBroadcast);
     }
}
package com.example.broadcastreceiverpractice.broadcastreceiver;

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

public class SecondBroadcastReceiver extends BroadcastReceiver {

      private static final String TAG = "SecondBroadcastReceiver" ;

      @Override
      public void onReceive(Context context, Intent intent) {
           String getFromBroadcast = intent.getStringExtra("key" );
           Log. i( TAG,getFromBroadcast);
     }
}
package com.example.broadcastreceiverpractice.broadcastreceiver;

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

public class ThirdBroadcastReceiver extends BroadcastReceiver {

      private static final String TAG = "ThirdBroadcastReceiver" ;

      @Override
      public void onReceive(Context context, Intent intent) {
           String getFromBroadcast = intent.getStringExtra("key" );
           Log. i( TAG,getFromBroadcast);
     }
}

以上三个广播接收者都采用的是静态注册在清单文件中进行注册,然后在MainActivity中点击发送广播按钮打印日志如下

我们看到都收到了,我们再看下时间差那么几毫秒,这个接收顺序跟我们在清单文件中配置的顺序是一致的,假如我们把SecondBroadcastReceiver方法最上面FirstBroadcastReceiver放在第二那么打印日志如下

说明这三个接收者都接收到了广播。

接着我们试着来中断这个广播在每个接收者的的onReceive()方法中来中断广播添加如下代码

abortBroadcast();

然后点击发送按钮发现每个接收者都能接收到广播,说明这种广播是不能被终止的

(2)有序广播

有序广播比较特殊当我们调用Context.sendOrderedBroadcast()发送有序广播时它只发给优先级最高的那个,然后由优先级高的接收者传到优先级低的那里,并且优先级高的接收者有能力中断广播,广播被中断后优先级低的广播将收不到广播。

修改清单文件增加android:priority属性

<receiver
     android:name =".broadcastreceiver.FirstBroadcastReceiver" >
      <intent-filter android:priority ="10" >
          <action android:name ="com.example.BroadcastReceiver" />
          <category android:name ="android.intent.category.DEFAULT" />
       </intent-filter>
        </receiver>
         <receiver
            android:name =".broadcastreceiver.SecondBroadcastReceiver" >
            <intent-filter android:priority ="9" >
              <action android:name ="com.example.BroadcastReceiver" />
              <category android:name ="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

        <receiver
           android:name =".broadcastreceiver.ThirdBroadcastReceiver" >
            <intent-filter android:priority ="8" >
               <action android:name ="com.example.BroadcastReceiver" />
               <category android:name ="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>

在上面一中的2提到当优先级高的广播收到广播后一般做两种处理:(1)是把广播中断。(2)接收广播中的数据并按照需求对此数据做更改首先我们来测一下中断广播,我们修改MainActivity的发送广播的方式

      //发送一条广播com.example.BroadcastReceiver要和广播接收者在清单文件中配置的相同
      Intent intent =new Intent("com.example.BroadcastReceiver" );
      intent.putExtra("key", "MainActivity中发了一条广播" );
      sendOrderedBroadcast(intent,null);

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

所以我们在AndroidMainfest.xml中定义一个权限:

<permission android:protectionLevel="normal"
           android:name="com.tsingda.broadcast_permission"/> 

然后添加此权限

<uses-permission android:name="com.tsingda.broadcast_permission" /> 

然后在SecondBroadcastReceiver 中调用

abortBroadcast();

这个方法然后点击发送按钮打印日志如下

发现ThirdBroadcastReceiver没有接收到广播,说明中断广播成功。

然后再来看更改广播中的数据,在讲解更改之前我们需要了解setResultExtras(Bundle)这个方法,在进行广播的传输时优先接收到Broadcast的接收者可以通过setResultExtras(Bundle)方法将处理结果存入Broadcast中,然后传给下一个接收者,下一个接收者通过Bundle
bundle = new getResultExtras(true)可以获取上一个接收者存入的数据。

setResultExtras(Bundle)方法的详细介绍如下图

我们把三个接收者做如下更改

package com.example.broadcastreceiverpractice.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class FirstBroadcastReceiver extends BroadcastReceiver {

      private static final String TAG = "FirstBroadcastReceiver" ;

      @Override
      public void onReceive(Context context, Intent intent) {
           String getFromBroadcast = intent.getStringExtra("key" );
           Log. i( TAG,getFromBroadcast);

           Bundle bundle = new Bundle();
        bundle.putString( "key", getFromBroadcast+ "@First");
        setResultExtras(bundle);
     }
}
package com.example.broadcastreceiverpractice.broadcastreceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

public class SecondBroadcastReceiver extends BroadcastReceiver {

      private static final String TAG = "SecondBroadcastReceiver" ;

      @Override
      public void onReceive(Context context, Intent intent) {
           String getFromBroadcast = getResultExtras(true ).getString("key" );
           Log. i( TAG,getFromBroadcast);

           Bundle bundle = new Bundle();
        bundle.putString( "key", getFromBroadcast+ "@Second");
        setResultExtras(bundle);
     }
}
package com.example.broadcastreceiverpractice.broadcastreceiver;

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

public class ThirdBroadcastReceiver extends BroadcastReceiver {

      private static final String TAG = "ThirdBroadcastReceiver" ;

      @Override
      public void onReceive(Context context, Intent intent) {
           String getFromBroadcast = getResultExtras(true ).getString("key" );
           Log. i( TAG,getFromBroadcast);
     }
}

点击发送广播按钮打印日志如下

说明我们接收到了广播并进行了修改然后传到了下一级。好了关于广播接收者的讨论就到这了,如果错误欢迎批评指正,谢谢

时间: 2024-10-12 04:14:10

Android开发之一起来学BroadcastReceiver的相关文章

其实Android开发应该这样学

我不懂java,但是懂C#和C++,所以我没主张去单独学习java语言,如果你是个最最初的新手,没啥语言基础,那你必须先看看java语言,不要很详细看,因为学习Android中,你也是在学习java. 明确目标 没有目标的学习,会感觉到后面没什么成果,在1年前,我也打算学习android开发的,但是目的就是学习,到网上去下载很多学习的视频,但没有系统的网上教学,没有能做得很好,只能把开发环境搭建起来,把Helloworld运行起来,能打些log,Activity之间也能互相切换了,但是后面也就不

醒醒,Android开发居然只有cv最顺手,你还会什么?

作为一个Android开发,现在的你已经开发多少年了? 你的代码质量有没有随着经验的增加而提高?没有的话就需要反思了. 现在来分享一个有六年经验Android开发,都学到了什么? 一,学习能力想要成长,学习能力尤为重要 我们一直有句老话,学如逆水行舟,不进则退.就像我们Android进阶,需要学习的高级内容比较多 1)Java语言进阶与Android相关技术内核像 泛型,多线程,反射,JVM,Java IO,注解,序列化等 2)App开发框架知识体系(app亦对象)Android 2013~20

android开发难学吗? Android开发学习方法

Android开发难学吗?新手应该如何怎样学好android开发?现在学习android开发晚了吗?这些都是想学android开发(http://www.maiziedu.com/course/android-px/)的新手提出的疑惑,其中有些问题不是我们应该担心,既然喜欢了,那就去做,不做怎么知道学了android开发会不会给自己带来变化,那么新手应该如何学好android开发呢?现在就随着小编一起来看看. 1.Java基础 很多朋友一上手就开始学习Android,似乎太着急了一些.Andro

【Android开发那点破事】消息推送BroadcastReceiver,点击通知打开两次Activity问题

Android开发中,通常会使用BroadcastReceiver来接受Push推送消息.当APP收到推送通知时,我们需要在通知的点击事件中加入自己的逻辑.比如跳转到MainActivity.比如下面的代码(注意红色部分): public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); if (JPushInterface.ACTION_REGISTRATION_ID.equ

Android开发学习之路-该怎么学Android(Service和Activity通信为例)

在大部分地方,比如书本或者学校和培训机构,教学Android的方式都基本类似,就是告诉先上原理方法,然后对着代码讲一下. 但是,这往往不是一个很好的方法,为什么? ① 学生要掌握这个方法的用途,只能通过记忆而不是理解 ② 当某些原理稍微复杂的时候,通过讲解是不能直接理解的,有时候下课回去了再看也不一定看得明白 ③ 对英语文档不够重视,有问题先百度 本鸟自学Android一年,慢慢也学习到了很多的方法,如果你也是一个入门不久但是觉得很多东西都不明白的新手,希望本文对你有帮助. 我觉得要想学好And

Android开发之使用BroadcastReceiver实时监听电量(源代码分享)

Android系统中实时的监听手机电量以及开机启动功能都是通过BroadcastReceiver组件实现的.我们可以动态注册这个类的一个实例通过Context.registerReceiver()方法或者静态注册,通过<Receiver>标记在androidmanifest . xml.注意:如果我们注册一个接收器在Activity.onResume()实现,我们应该注销Activity在Activity生命周期的onPause方法中.(这将减少不必要的系统开销).切记不能注销Activity

【视频】零基础学Android开发:蓝牙聊天室APP(一)

零基础学Android开发:蓝牙聊天室APP第一讲 1. Android介绍与环境搭建:史上最高效Android入门学习 1.1 Google的大小战略 1.2 物联网与云计算 1.3 智能XX设备 1.4 Android发展前景 1.5 Android企业需求与就业薪资 1.6 Android框架介绍 1.7 搭建Android开发环境 1.8 Android SDK文件夹具体解释 1.9 开发第一个App:HelloWorld 1.10 App应用程序文件夹具体解释 在线收看:http://

学Android开发 这19个开发工具助你顺风顺水

学Android开发 这19个开发工具助你顺风顺水 要想快速开发一个Android应用,通常会用到很多工具,巧妙利用这些工具,能让我们的开发工作事半功倍,节省大量时间,下面大连Android开发培训小编就为大家介绍下这19个开发工具都有神马用途. 1.XAppDbg XAppDbg是一个可以在运行中改变代码中参数的一个应用开发工具.这个工具可以为你省下大量的时间,因为你不用为应用的每次小改变而重新编译运行你的程序. 2.ChkBugReport 这个工具可以快速地检查输出的Android错误报告

【视频】零基础学Android开发:蓝牙聊天室APP(三)

零基础学Android开发:蓝牙聊天室APP第三讲 3.1 ImageView.ImageButton控件详解 3.2 GridView控件详解 3.3 SimpleAdapter适配器详解 3.4 事件监听器:OnItemClickListener 3.5 输入和显示表情图像 在线收看:http://www.3g-edu.org/news/video023.htm 视频下载:http://pan.baidu.com/s/1kTmiNqf