`
XiangdongLee
  • 浏览: 92000 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

【攻克Android (33)】四大组件之 BroadcastReceiver

 
阅读更多
本文围绕以下三个部分展开:

一、广播
案例一:系统广播(属于普通广播):手机电池电量小于15%时进行提醒
案例二:自定义普通广播






一、广播

        1. 概念:

        广播(broadcasting)是多点投递的最普遍的形式,它向每一个目的站投递一个分组的拷贝。它可以通过多个单次分组的投递完成,也可以通过单独的连接传递分组的拷贝,直到每个接收方均收到一个拷贝为止。

        每个广播电台播放的内容都不相同。接受广播时广播(发送方)并不在意我们(接收方)接收到广播时如何处理。好比我们收听交通电台的广播,电台中告诉我们现在在交通状况如何,但它并不关心我们接收到广播时做如何做出处理,这不是广播应该关心的问题。

        2. Android 广播的优势:

        (1)扩展了Android中的事件模型,提高了应用程序的可扩展性。

        (2)方便了不同应用程序共享数据。

        (3)提高了应用程序的运行效率。

        3. BroadcastReceiver:

        BroadcastReceiver是Android整个系统中通用的发布/订阅机制(更确切地说,Observer模式)的实现。意思是接收者(Receiver)订阅一些事件,在事件发生时做出一定响应。

        系统自身时时刻刻广播着一些事件。比如收到短信、来了一个电话、电量不足或者系统启动等事件发生的时候,它们都是通过广播传递给每个接收者。

        广播可以在不同的应用之间传递;也可以在同一应用的不同Activity之间传递;还可以在应用与服务之间传递。

        Broadcast Receriver并无任何可见的界面(不同于Activity),也并非常驻于内存中执行(不同于Service)。它只会在事件发生时执行一段代码,做些启动一个Activity/Service之类的操作。

        每次广播消息到来时都会创建BroadcastReceiver实例并执行onReceive() 方法。

        广播接收者(BroadcastReceiver)用于接收广播Intent,通常一个广播Intent可以被订阅了此Intent的多个广播接收者所接收。



        4. 广播的分类。

        (1)系统广播、自定义广播。

        A. 系统内部已经定义了很多广播消息类型,例如电池电量低、屏幕开启或者关闭、系统引导完成等。

        系统内部广播这些消息使用的是 sendBroadcast()。

        当系统发送这些广播后,同样经过 Intent 匹配找到相应的 Receiver 对象并启动。这与 Activity 或者 Service 一样。

        Receiver对象接收的消息本质上是Intent。

        多数应用中,Receiver接收的是系统发出的消息。

        附:系统广播可以捕捉系统发出的行为有:



        B. 自定义广播包括自定义普通广播、自定义有序广播。

        自定义广播无非是给Intent对象的Action字段赋予自定义的值而已,不能与系统内部的消息名称重复,并在Receiver对象的intent-filter中使用相同的Action值进行匹配。一般自定义广播命名时,可以使用本程序包名作为前缀,以免与其它程序定义的广播发生命名冲突。

        (2)普通广播(Normal broadcasts)、有序广播(Ordered broadcasts)。

            A. 前者是完全异步的,所有接收者(逻辑上)都在同一时刻运行,对消息传递的效率而言这是很好的做法。
            但缺点是:接收者不能将处理结果传递给下一个接收者,并且无法终止广播Intent的传播。
            然而后者是逐个执行接收者:系统会按照接收者声明的优先级别
(声明在intent-filter元素的android:priority属性中,数越大优先级别越高,取值范围:-1000到1000。也可以调用IntentFilter对象的setPriority()进行设置),按顺序逐次执行。


            B. 发送广播:

            Context.sendBroadcast()

            发送的是普通广播,所有订阅者都有机会获得并进行处理。

            Context.sendOrderedBroadcast()

            发送的是有序广播,系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast())。如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将处理结果存放进广播Intent,然后传给下一个接收者。

        (3)静态广播、动态广播。

            静态广播:使用静态注册方式注册的广播。

            动态广播:使用动态注册方式注册的广播。

        5. 广播的实现。

        (1)继承BroadcastReceiver,并重写onReceive()方法。

        (2)注册BroadcastReceiver。

        注册的方法有两种:

            1)静态注册(在功能清单文件中的<application>节点里进行注册)。

<receiver android:name=".IncomingSMSReceiver">
    <intent-filter>
         <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
    </intent-filter>
</receiver>


            2)动态注册(使用代码进行进行注册)。

IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
IncomingSMSReceiver receiver = new IncomingSMSReceiver();
registerReceiver(receiver, filter);


            3)两种注册方式的比较:

            A. 动态注册的广播 永远要快于 静态注册的广播。不管静态注册的优先级设置的多高,不管动态注册的优先级有多低。

            B. 动态注册广播不是 常驻型广播 ,也就是说广播跟随activity的生命周期。注意: 在activity结束前,移除广播接收器。
            静态注册是常驻型 ,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

            C. 在同一个优先级下,谁先启动的快,谁将先接收到广播。

        6. 处理耗时任务。

            在Android中,程序的响应(Responsive)被活动管理器(Activity Manager)和窗口管理器(Window Manager)这两个系统服务所监视。当BroadcastReceiver在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框。

            如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成,而不是使用子线程的方法来解决。因为BroadcastReceiver的生命周期很短(在onReceive() 执行后BroadcastReceiver 的实例就会被销毁),子线程可能还没有结束它就先结束了。当然如果BroadcastReceiver结束了,它的宿主进程还在运行,子线程还会继续执行。但宿主进程此时很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。

public class IncomingSMSReceiver extends BroadcastReceiver {
	@Override 
	public void onReceive(Context context, Intent intent) {
        //发送Intent启动服务,由服务来完成比较耗时的操作
        Intent service = new Intent(context, XxxService.class);
        context.startService(service);
	}
}



案例一:系统广播(属于普通广播):手机电池电量小于15%时进行提醒







        1. activity_main.xml。写一个 TextView,用于显示当前电池电量。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tvBatteryChanged"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        android:textSize="30sp" />

</RelativeLayout>


        2. MainActivity。声明和在onCreate()中初始化 TextView。

    // 1.1 声明变量(显示电池电量的文本)
    private TextView tvBatteryChanged;


        // 1.2 初始化变量(显示电池电量的文本)
        tvBatteryChanged = (TextView) findViewById(R.id.tvBatteryChanged);


        3. MainActivity。【一、定义广播】定义匿名的广播接收者(接收手机电量不足的通知)。

    // 2. 定义匿名的广播接收者(接收手机电量不足的通知)
    private BroadcastReceiver batteryChangedReceiver = new BroadcastReceiver() {
        /**
         * 在 BroadcastReceiver 接收到与之匹配的广播消息后,onReceive()方法会被调用
         *
         *  onReceive()方法必须要在5秒钟执行完毕,
         * 否则 Android 系统会认为该组件失去响应,并提示用户强行关闭该组件
         *
         * @param context  设置BroadcastReceiver实例
         * @param intent   Receiver对象接收的消息
         */
        @Override
        public void onReceive(Context context, Intent intent) {

        }
    };


        4. MainActivity。【二、注册广播】在onCreate()中注册电量不足的广播接收者。

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

        // 1.2 初始化变量(显示电池电量的文本)
        tvBatteryChanged = (TextView) findViewById(R.id.tvBatteryChanged);

        // 3. 注册电量不足的广播接收者
        // 参数一:指定广播接收者
        // 参数二:新建意图过滤器,在过滤器中写入 广播的 action(动作)
        //        Receiver对象接收的消息本质上是Intent
        this.registerReceiver(batteryChangedReceiver,
                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    }


        5. MainActivity。【三、处理操作】在onReceive() 方法中。

// 4. 处理操作

            // 经过 Intent 匹配找到相应的 Receiver 对象并启动。
            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                /**
                 * getIntExtra (String name, int defaultValue)
                 * Retrieve(再次获得,取回) extended data from the intent.
                 * 获得指定参数的值,若值为 null,则返回默认值 0
                 *
                 */

                // level:当前电池电量
                int level = intent.getIntExtra("level", 0);
                // 电池总电量
                int scale = intent.getIntExtra("scale", 100);
                // 电量文本
                String text = "电池电量:" + (level * 100 / scale) + " %";
                // 在 TextView 中显示出当前电池电量
                tvBatteryChanged.setText(text);

                // 判断:当电量小于等于15%时触发:通过 Toast 输出通知
                if (level <= 15) {
                    // 因为这是在内部类中,而 Toast 输出是在 MainActivity 中,
                    // 因此写为 MainActivity.this
                    Toast.makeText(MainActivity.this, "当前电量已小于15%",
                            Toast.LENGTH_LONG).show();
                }
            }



        代码补充:

        MainActivity。

package com.android.mybroadcast;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;

/*
    系统内部定义的广播消息,可以查阅官方文档:
    C:\android\android-sdk-windows\docs\reference\android\content\Intent.html
 */
public class MainActivity extends Activity {
    // 1.1 声明变量(显示电池电量的文本)
    private TextView tvBatteryChanged;

    // 2. 定义匿名的广播接收者(接收手机电量不足的通知)
    private BroadcastReceiver batteryChangedReceiver = new BroadcastReceiver() {
        /**
         * 在 BroadcastReceiver 接收到与之匹配的广播消息后,onReceive()方法会被调用
         *
         *  onReceive()方法必须要在5秒钟执行完毕,
         * 否则 Android 系统会认为该组件失去响应,并提示用户强行关闭该组件
         *
         * @param context  设置BroadcastReceiver实例
         * @param intent   Receiver对象接收的消息
         */
        @Override
        public void onReceive(Context context, Intent intent) {
            // 4. 处理操作

            // 经过 Intent 匹配找到相应的 Receiver 对象并启动。
            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
                /**
                 * getIntExtra (String name, int defaultValue)
                 * Retrieve(再次获得,取回) extended data from the intent.
                 * 获得指定参数的值,若值为 null,则返回默认值 0
                 *
                 */

                // level:当前电池电量
                int level = intent.getIntExtra("level", 0);
                // 电池总电量
                int scale = intent.getIntExtra("scale", 100);
                // 电量文本
                String text = "电池电量:" + (level * 100 / scale) + " %";
                // 在 TextView 中显示出当前电池电量
                tvBatteryChanged.setText(text);

                // 判断:当电量小于等于15%时触发:通过 Toast 输出通知
                if (level <= 15) {
                    // 因为这是在内部类中,而 Toast 输出是在 MainActivity 中,
                    // 因此写为 MainActivity.this
                    Toast.makeText(MainActivity.this, "当前电量已小于15%",
                            Toast.LENGTH_LONG).show();
                }
            }
        }
    };

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

        // 1.2 初始化变量(显示电池电量的文本)
        tvBatteryChanged = (TextView) findViewById(R.id.tvBatteryChanged);

        // 3. 注册电量不足的广播接收者
        // 参数一:指定广播接收者
        // 参数二:新建意图过滤器,在过滤器中写入 广播的 action(动作)
        //        Receiver对象接收的消息本质上是Intent
        this.registerReceiver(batteryChangedReceiver,
                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
    }

    // -------------------------------------------------------------------
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}



案例二:自定义普通广播







        1. 创建 BroadcastReceiver:NewsReceiver。【一、创建 BroadcastReceiver】

        2. 在功能清单中注册自定义 BroadcastReceiver。(创建的时候,自动注册好了)【二、注册自定义 BroadcastReceiver】

        3. activity_main.xml。写一个按钮。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnSendBroadcast"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="@string/sendBroadcast" />

</RelativeLayout>


        4. MainActivity。在按钮点击事件中发送广播。(要有 intent意图、附件信息 等)

    /**
     * 按钮点击事件
     * @param view
     */
    public void onClick(View view){
        // (4)发送普通广播

        // (4.1)新建 intent
        Intent intent = new Intent();
        // (4.2)设置 intent 的 action 动作 (设置发送的广播频道)
        intent.setAction("android.intent.action.NEWS");
        // (4.3)在功能清单文件中,注册 意图过滤器(广播接收者 这一端 设置 接收的广播频道)
        // (4.4)附加信息
        intent.putExtra("msg", "今天大部分地区将迎来强降雨天气");
        // (4.5)发送 广播
        sendBroadcast(intent);
    }


        其中,(4.3)如下:

        <!-- (2) 注册自定义 BroadcastReceiver (在功能清单中) -->
        <receiver android:name=".NewsReceiver" >
            <!--
            (4.3)注册 意图过滤器(广播接收者 这一端 设置 接收的广播频道)
            -->
            <intent-filter>
                <action android:name="android.intent.action.NEWS" />
            </intent-filter>
        </receiver>


        如果 注册中的 intent 和 发送的广播中的 intent 是一样的(相当于观众把频道调到了电台广播频道),就可以接收到广播。

        5. NewsReceiver。接收广播。

package com.android.mybroadcast;

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

/**
 * 新闻联播的观众
 */
public class NewsReceiver extends BroadcastReceiver {
    public NewsReceiver() {
    }

    /**
     * 重写 onReceive() 方法
     * @param context
     * @param intent
     */
    @Override
    public void onReceive(Context context, Intent intent) {
        // (5)获得 Intent意图 中的附加信息
        String msg = intent.getStringExtra("msg");
        // (6)Toast显示广播
        Toast.makeText(context, "收到新闻联播的广播:" + msg,
                Toast.LENGTH_LONG).show();
    }
}
  • 大小: 18.7 KB
0
1
分享到:
评论

相关推荐

    Android 四大组件之BroadcastReceiver

    在Android系统中,四大组件是应用程序的核心组成部分,包括Activity、Service、Content Provider和BroadcastReceiver。本篇文章将聚焦于BroadcastReceiver,讲解如何在Android应用中使用它,特别是静态注册和动态...

    11.四大组件之BroadcastReceiver.pptx

    BroadcastReceiver是Android系统四大组件之一,它主要用于在应用程序的不同组件或者不同应用程序之间进行异步通信。在Android系统中,BroadcastReceiver扮演着消息分发者的角色,它可以接收并响应系统或应用自行发送...

    Android四大组件——BroadcastReceiver普通广播、有序广播、拦截广播、本地广播、Sticky广播、系统广播

    在Android应用开发中,BroadcastReceiver(广播接收器)是四大组件之一,它是系统用来传递消息和事件的重要机制。BroadcastReceiver可以监听系统或应用程序发送的广播Intent,并在接收到广播时执行相应的操作。以下...

    Android四大组件之BroadcastReceiver详解

    Android四大组件之BroadcastReceiver详解 在 Android 开发中,BroadcastReceiver 是四大组件之一,扮演着监听和响应应用发出的广播消息的角色。今天,我们将深入探讨 BroadcastReceiver 的作用、实现原理、注册方式...

    Android四大组件简述

    Android系统的核心架构主要由四大组件构成:Activity、Service、BroadcastReceiver和ContentProvider。这四大组件是构建Android应用程序的基础,理解并熟练运用它们是每个Android开发者必须掌握的关键技能。 首先,...

    Android开发的四大组件

    在Android应用开发中,四大组件是构建应用程序的基础,它们分别是Activity、Service、BroadcastReceiver和ContentProvider,还有Intent作为组件间通信的重要桥梁。下面我们将逐一详细解释这些组件。 **Activity详解...

    安卓四大组件——BroadcastReceiver(广播)

    在Android系统中,四大组件是应用开发的核心组成部分,它们分别是:Activity、Service、Content Provider以及我们今天要讨论的BroadcastReceiver(广播接收器)。BroadcastReceiver是一种轻量级组件,用于接收并响应...

    android四大组件详解

    在Android系统中,四大组件是构建应用程序的核心元素,它们分别是Activity、Service、BroadcastReceiver和Content Provider。这四个组件各自承担着不同的职责,共同构成了Android应用的骨架。 **Activity**是用户与...

    Android编程四大组件之BroadcastReceiver(广播接收者)用法实例

    在Android开发中,BroadcastReceiver(广播接收者)是四大组件之一,它负责监听系统或应用程序发送的广播消息,并在接收到匹配的广播时执行相应的操作。BroadcastReceiver的主要功能在于实现跨组件通信,允许应用...

    Android核心基础-9.Android四大组件之BroadcastReceiver-附件资源

    Android核心基础-9.Android四大组件之BroadcastReceiver-附件资源

Global site tag (gtag.js) - Google Analytics