Android入门(7)| 四大组件之广播接收器

广播接收器(Broadcast Receiver),是我们接触到的第二个组件。Broadcast(广播)是一种广泛应用在应用程序之间传输信息的机制,而BroadcastReceiver(广播接收器)则是用于接收来自系统和应用的广播对并对其进行响应的组件。Android提供了一套完整的API,允许应用程序自由地发送和接收广播。其中发送广播的方法就是使用Intent,而接收广播就需要使用广播接收器了。


本节目录

广播的类型

在介绍广播接收器之前,我们先来具体介绍一下广播。Android里面广播就类似于现实生活里面的广播。当我们需要传达一些信息给很多人听的时候,我们就会使用广播,而在程序里面也是同样的道理,除此以外,它不仅能够给自己的程序发送广播,还能够给其他的程序发送广播。

Android中的广播主要可以分为两种类型:标准广播和有序广播。

  • 标准广播
    标准广播是一种完全异步执行的广播,在广播发出之后,几乎所有的广播接收器都会接受到这个广播,因此标准广播的效率是很高的。
标准广播
  • 有序广播
    有序广播是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播,当这个广播接收器中的逻辑执行完毕之后,这条广播才能够被继续传递。所以此时的广播接收器是有先后顺序的。
有序广播

接收广播的方法

广播接收器就是用来接收广播,它可以对它需要的广播进行注册,这样当有相应的广播发出时,它就能够接收到该广播。注册广播的方式一般有2种:动态注册和静态注册。下面分别来看一看吧。

1.动态注册

动态注册简单来说其实就是在代码中进行使用registerReceiver()方法来为广播接收器进行注册。先创建一个空项目,然后修改主代码:

package com.example.yzbkaka.myapplication;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    IntentFilter intentFilter;  //放置广播的“容器”
    NetworkChangeReceiver networkChangeReceiver;  //广播接收器
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        networkChangeReceiver = new NetworkChangeReceiver();
        intentFilter.addAction("android.net.com.CONNECTIVITY.CHANGE");
        registerReceiver(networkChangeReceiver,intentFilter);  //注册广播
    }
    
    @Override
    protected void onDestroy(){
        super.onDestroy();
        unregisterReceiver(networkChangeReceiver);
    }
    
    class NetworkChangeReceiver extends BroadcastReceiver{  //广播接收器继承自BroadcastReceiver
        @Override
        public void onReceive(Context context, Intent intent) {  //添加逻辑
            Toast.makeText(MainActivity.this, "get a broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}

这里我们首先是要创建一个内部类NetworkChangeReceiver并让它继承BroadcastReceiver 然后我们就在它的onReceive()的方法中来添加逻辑。接着看到上面的主代码,我们先是新建一个IntentFilter的实例,这个实例是用来存放广播的,然后我们对它使用addAction()的方法来添加广播,这里添加的广播是系统自带的广播,主要是用来判断网络变化的。然后我们就使用registerReceiver()的方法来对广播进行注册,这里需要的两个参数就是我们的广播接收器和intentFilter了。

需要注意的是使用动态的方法注册的广播必须要手动取消注册才行,我们在onDestroy()的方法中使用unregisterReceiver()来进行取消注册。

2.静态注册

静态注册的主要思路就是在AndroidManifest.xml中来进行注册。我们先创造一个新的类,修改代码:

package com.example.yzbkaka.myapplication;

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


public class BootCompleteReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "this is bootcompletereceiver", Toast.LENGTH_SHORT).show();
    }
}

接着我们到AndroidManifest.xml来为接收器进行注册:

   <receiver
          android:name=".BootCompleteReceiver"
          android:enable="true"
          android:exported="true">
        </receiver>

我们在<application>的标签类添加<receiver>来进行注册,这里的android:enable属性是指是否启用这个接收器,而android:exported属性是指是否允许这个广播接收器接收本程序以外的广播。

接着我们就需要来为广播接收器添加广播了,还是在AndroidManifest.xml中修改:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yzbkaka.myapplication">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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>

        <receiver
            android:name=".BootCompleteReceiver"
            android:enable="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
    </application>
</manifest>

因为在Android系统中使用某些比较隐秘的广播时需要我们来声明权限,所以我们先在开头中声明一下权限,使用的是<uses-permission>的标签来进行添加。之后我们在<receiver>里面使用<intent-filter>标签来添加广播,这一条广播是当手机开机时系统会自动发布的广播,不需要我们来手动发送。到这里我们就可以使用我们的广播接收器了。

静态注册的方法看起来是要比动态注册的方法操作要复杂一些,但是它却能够在程序启动之前就能够接收到广播,因为动态注册的方法实在onCreate()中进行的,所以动态注册的广播接收器必须当活动被创建起来之后才能够接收到广播。

发送广播

前面我们使用的例子中接收到的广播都是系统内置的广播,也就是说这些广播能都在某些情况下由系统自动的发送。但是我们也可以自定义广播来进行发送。

1.发送标准广播

前面说过,标准广播就是可以被所有的广播接收器接收。下面我们就来发送标准广播吧。

还是先创建一个空项目,然后新建一个广播接收器:

package com.example.yzbkaka.sendbroadcastpractice;

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


public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "get a broadcast", Toast.LENGTH_SHORT).show();
    }
}

还是比较容易理解的代码,这里就不多说了。接着是注册广播接收器:

    <receiver 
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true" >
            <intent-filter>
                <action android:name="com.example.broadcast.MY_BROADCAST"/>
            </intent-filter>
      </receiver>

在注册的时候我们是自定义了一条叫做com.example.broadcast.MY_BROADCAST的广播,到时候我们的广播接收器就会接收这样一条广播。然后我们为我们的主活动添加一个按钮,最后修改主代码:

package com.example.yzbkaka.sendbroadcastpractice;

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button send = (Button)findViewById(R.id.button1);
        final Intent intent = new Intent("com.example.broadcast.MY_BROADCAST");
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sendBroadcast(intent);  //发送广播
            }
        });
    }
}

我们这里先是将广播存放在intent当中,然后就是将intent使用sendBroadcast()方法来进行发送。

运行程序,然我们点击按钮的时候就会发送广播,而在程序的下方就会出现一跳短消息提示语句,说明我们的接收器成功接收到了广播。

2.发送有序广播

知道了如何发送标准广播,下面就来看一看如何发送有序广播吧。

我们直接使用上面的项目,前面的代码都不变,我们直接修改主代码:

package com.example.yzbkaka.sendbroadcastpractice;

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button send = (Button)findViewById(R.id.button1);
        final Intent intent = new Intent("com.example.broadcast.MY_BROADCAST");
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sendOrderedBroadcast(intent,null);  //有序发送广播的方法
            }
        });
    }
}

这里我们是直接修改发送广播的方法,改成使用sendOrderedBroadcast()方法来进行发送,这个方法需要2个参数:第一个就是存储了广播的intent;第二个就是直接使用默认的null即可。

有序广播的特点是必须要按照广播接收器的优先级来被捕获,即优先级越高的广播接收器,就能够越在前面接收广播。所以我们接下来就来修改广播接收器的优先级,打开AndroidManifest.xml,修改代码:

 <intent-filter android:priority="100">
                <action android:name="com.example.broadcast.MY_BROADCAST"/>
            </intent-filter>

使用priority的属性来设置广播接收器的优先级,这里我们设置为100。之后如果有多个广播接收器,我们就可以手动的设置它们的优先级来为它们进行排序。

当然,优先级高的广播接收器也可以执行不让广播继续传送的操作,即广播传到它这里以后就不会再传书下去了,我们直接在onCreate()里面添加abortBroadcase()方法就能够阻断广播的传输了。

使用本地广播

我们之前发送的广播(包括系统广播和自定义广播)都是在系统内全局发送的,即所有的程序都能够接收这些广播。但是有些情况下我们不想让其他的程序收到我们的广播时,我们就可以选择发送本地广播。

新建项目,添加一个按钮,然后直接修改主代码:

package com.example.yzbkaka.localbroadcasttest;

import android.content.BroadcastReceiver;
import android.content.Context;
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;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    IntentFilter intentFilter;
    LocalReceiver localReceiver;
    LocalBroadcastManager localBroadcastManager;  //创建管理器

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Button send = (Button)findViewById(R.id.button1);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcast.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);  //发送广播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcast.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);  //注册广播接收器
        
    }

    class LocalReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "get local broadcast", Toast.LENGTH_SHORT).show();
        }
    }
}

这里我们是采用动态注册的方法来实现的,因为我们想要的是发送不让其他程序接收到的广播,如果采用静态的注册方法,则在我们活动创建之前就有了广播,这和我们想要的是不同的。接着我们就是创建一个LocalBroadcastManager的实例,我们发送本地广播主要就是依靠它来完成的。然后就是调用LocalBroadcastManager实例的方法来进行发送和注册。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,928评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,748评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,282评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,065评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,101评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,855评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,521评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,414评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,931评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,053评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,191评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,873评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,529评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,074评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,188评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,491评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,173评论 2 357

推荐阅读更多精彩内容