android广播机制

来源:互联网 发布:易到打车软件 编辑:程序博客网 时间:2024/06/05 23:57


一:广播机制简介


BroadCastReciver:广播接收者,它的作用是用来接受系统和应用发送过来的广播的。

我们先来了解什么是广播:android系统是离不开广播的,比如手机电量改变时系统就会发送一条广播提示用户;当手机开机时系统会发送一条广播,接受到广播就能实现开机启动服务的功能;当没有网络时也会发送一条广播,提示作相应的操作。

接下来我们来了解一下广播的类型, android中的广播可以分为两种类型:标准广播和有序广播

标准广播:

是一种异步执行的广播,广播发出后,所有的广播接收器几乎会在同一时刻接收到这条广播消息,因此它们没有先后顺序可言,效率比较高。但它的缺点是接收者不能将处理结果传递给下一个接受者,并且无法终止BroadCast intent的传播。

标准广播的工作图如下所示:

有序广播:是一种同步执行的广播,这种广播发出后,同一时刻只有一个广播接收器能收到广播消息,当这个广播接收器执行完了之后,广播才会往下传递,因此它是有先后顺序的,那么可以更改它的先后顺序吗?可以 通过以下两种方法更改它的执行顺序:

1:androdManifest<intent-filter.../>元素的android:priority属性中设置它的优先级:取值范围在-1000~1000,数越大优先级越高。

2:也可以调用IntentFilter对象的setPriority()进行设置。

Ordered Broadcast接收者可以终止BroadCast Intent的传播,Broadcastt Intent的传播一旦终止,后面的接收器就无法接收到BroadCast

有序广播的工作图如下所示:



二 接收系统广播


android内置了很多系统级别的广播,我们可以在应用中监听这些广播得到各种系统的状态信息。

如果想要监听广播,就需要使用广播接收器,广播接收器可以自由地对自己感兴趣的广播进行注册。注册广播的方式有两种,

1:在代码中注册

在代码中注册页叫做动态注册

下面我们就通过动态注册来写一个监听网络变化的程序


package broadcastreceiver.csdn.com.aty;import android.app.Activity;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.content.IntentFilter;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.os.Bundle;import android.os.PersistableBundle;import android.support.annotation.Nullable;import android.widget.Toast;import org.xutils.x;import broadcastreceiver.csdn.com.R;/** * 动态注册广播监听器 *  * 监听网络变化 * Created by Administrator on 2017/5/30. */public class DynamicAty extends Activity{    private IntentFilter intentDynamic;    private NetworkChangeBR netWorkChangeBR;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.aty_dynnamic);        x.view().inject(this);        intentBR();//注册广播    }    /**     * 注册广播     */    private void intentBR() {        /**         * 创接IntentFilter实例         *IntentFilter对象负责过滤掉组件无法响应和处理的Intent,只将自己关心的Intent接收进来进行处理         */        intentDynamic=new IntentFilter();        /**         * 当网络发生改变时系统会发出一条android.net.conn.CONNECTIVITY_CHANGE广播         *         * 我们的广播想要监听什么就在这写什么         */        intentDynamic.addAction("android.net.conn.CONNECTIVITY_CHANGE");        /**         * 创建NetworkChangeReceiver实例         */        netWorkChangeBR=new NetworkChangeBR();        /**         * registerReceiver进行注册         */        registerReceiver(netWorkChangeBR,intentDynamic);    }    /**     * 监听网络变化     *     * 建立一个内部类让它继承自BroadcastReceiver     */    class NetworkChangeBR extends BroadcastReceiver{        @Override        public void onReceive(Context context, Intent intent) {            /**             * 这是一个系统服务类,专门用来管理网络的             */            ConnectivityManager connectivityManager= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);            /**             * 得到NetworkInfo的实例             */            NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();            if(networkInfo!=null && networkInfo.isAvailable()){                Toast.makeText(DynamicAty.this,"网络打开了",Toast.LENGTH_SHORT).show();            }else{                Toast.makeText(DynamicAty.this,"网络关闭了",Toast.LENGTH_SHORT).show();            }        }    }    /**     * 动态注册的广播接收器一定要取消     *      * 取消广播接收器     *     */    @Override    protected void onDestroy() {        super.onDestroy();        unregisterReceiver(netWorkChangeBR);    }}



这里有非常重要的一点要说明,如果程序涉及一些对用户敏感的操作,就必须在配置文件中声明权限。

android:Manifest中加入以下代码

允许用户访问GSM网络信息

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



2:AndroidManifest.xml中注册

在AndraoidManifest中注册也叫做静态注册

下面我们通过静态注册编写一个能够监听网络变化的应用吧。

右击创建应用的包->New->Other->Broadcast Receiver 会弹出下图所示的窗口


Class Name:输入广播的名字

Exported:是否允许这个广播接收器接收本程序以外的广播

Enabled属性是否启用这个广播接受器

构选这两个属性,点击Finish,广播接收器创建完成了,以下是自动生成的代码


package broadcastreceiver.csdn.com.aty;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;public class QuintReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        // TODO: This method is called when the BroadcastReceiver is receiving        // an Intent broadcast.        throw new UnsupportedOperationException("Not yet implemented");    }}


android Studio注册这一步也帮我们一起完成了,下面是Android Manifest里的代码


<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="broadcastreceiver.csdn.com">    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <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=".aty.MainAty">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <activity android:name=".aty.QuintAty" />        <activity android:name=".aty.DynamicAty" />        <receiver            android:name=".aty.QuintReceiver"            android:enabled="true"            android:exported="true"></receiver>    </application></manifest>



不过现在还是不能接收广播的,下面我们对代码进行修改

下面是修改后的AndroidMainifest:


<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="broadcastreceiver.csdn.com">    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <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=".aty.MainAty">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <activity android:name=".aty.QuintAty" />        <activity android:name=".aty.DynamicAty" />        <receiver            android:name=".aty.QuintReceiver"            android:enabled="true"            android:exported="true">            <intent-filter>                <action android:name="android.intent.action.BOOT_COMPLETED"></action>            </intent-filter>        </receiver>    </application></manifest>


可以看到我们在两个地方修改了

1、<intent-filter>标签里加了监听系统开机广播action

2、 加了一条开机广播的权限

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

接下来我们在QuintReceiver加了一条Toast

package broadcastreceiver.csdn.com.aty;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.widget.Toast;/** * 静态注册广播接收器 */public class QuintReceiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        // TODO: This method is called when the BroadcastReceiver is receiving        // an Intent broadcast.        Toast.makeText(context,"开机了",Toast.LENGTH_SHORT).show();    }}

好了静态注册也完成了




三 发送自定义广播


现在我们已经学会了通过广播接收系统广播,接下来我们来学习如何在应用程序中发送自定义广播。


1:发送标准广播


下面是发送广播的代码

MainAty.class

package broadcastreceiver.csdn.com.aty;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;import org.xutils.view.annotation.Event;import org.xutils.view.annotation.ViewInject;import org.xutils.x;import broadcastreceiver.csdn.com.R;public class MainAty extends AppCompatActivity {    @Event(value ={R.id.bn_standard,R.id.bn_dynamic})    private void onClick(View v){        switch (v.getId()){            case R.id.bn_dynamic:                //动态注册                Intent intentDynamic=new Intent(MainAty.this,DynamicAty.class);                startActivity(intentDynamic);                break;            case R.id.bn_standard:                //发送标准广播                Intent intentStandard=new Intent("com.csdn.broadcastreceiver.MY_RECEIVER");                sendBroadcast(intentStandard);                break;        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.aty_main);        x.view().inject(this);//xutils3初始化    }}

布局
aty_main.xml
<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:layout_editor_absoluteX="0dp"    tools:layout_editor_absoluteY="81dp">    <Button        android:id="@+id/bn_dynamic"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_marginLeft="8dp"        android:layout_marginRight="8dp"        android:layout_marginTop="8dp"        android:text="动态注册"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent"        app:layout_constraintTop_toTopOf="parent" />    <Button        android:id="@+id/bn_standard"        android:layout_width="0dp"        android:layout_height="wrap_content"        android:layout_marginLeft="8dp"        android:layout_marginRight="8dp"        android:layout_marginTop="8dp"        android:text="发送标准广播"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent"        app:layout_constraintTop_toBottomOf="@+id/bn_dynamic" /></android.support.constraint.ConstraintLayout>


接收广播的代码

package broadcastreceiver.csdn.com.Receiver;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) {        Toast.makeText(context,"标准广播收到了",Toast.LENGTH_SHORT).show();    }}

AndroidManifest.xml注册

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="broadcastreceiver.csdn.com">    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <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=".aty.MainAty">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <activity android:name=".aty.QuintAty" />        <activity android:name=".aty.DynamicAty" />        <receiver            android:name=".Receiver.QuintReceiver"            android:enabled="true"            android:exported="true">            <intent-filter>                <action android:name="android.intent.action.BOOT_COMPLETED" />            </intent-filter>        </receiver>        <receiver            android:name=".Receiver.MyReceiver"            android:enabled="true"            android:exported="true">            <intent-filter>                <action android:name="com.csdn.broadcastreceiver.MY_RECEIVER"/>            </intent-filter>        </receiver>    </application></manifest>

思考一个问题,其他程序是否也可以接收该广播呢?我们新建Demo2的项目

Demo2接收广播的代码

package broadcastreceiver.csdn.com.demo2;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.widget.Toast;public class Demo2Receiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        Toast.makeText(context,"Demo2也收到了标准广播",Toast.LENGTH_SHORT).show();    }}

AndroidManifest.xml配置代码

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="broadcastreceiver.csdn.com.demo2">    <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=".MainAty">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <receiver            android:name=".Demo2Receiver"            android:enabled="true"            android:exported="true">            <intent-filter>                <action android:name="com.csdn.broadcastreceiver.MY_RECEIVER"/>            </intent-filter>        </receiver>    </application></manifest>

2:发送有序广播


发送有序广播很简单

package broadcastreceiver.csdn.com.aty;import android.content.Intent;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import android.view.View;import android.widget.Button;import android.widget.TextView;import org.xutils.view.annotation.Event;import org.xutils.view.annotation.ViewInject;import org.xutils.x;import broadcastreceiver.csdn.com.R;public class MainAty extends AppCompatActivity {    @Event(value ={R.id.bn_standard,R.id.bn_dynamic})    private void onClick(View v){        switch (v.getId()){            case R.id.bn_dynamic:                //动态注册                Intent intentDynamic=new Intent(MainAty.this,DynamicAty.class);                startActivity(intentDynamic);                break;            case R.id.bn_standard:                //发送标准广播                Intent intentStandard=new Intent("com.csdn.broadcastreceiver.MY_RECEIVER");//                sendBroadcast(intentStandard);//发送标准广播                sendOrderedBroadcast(intentStandard,null);//发送有序广播                break;        }    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.aty_main);        x.view().inject(this);//xutils3初始化    }}

只要把

sendBroadcast(intentStandard);//发送标准广播
换成

sendOrderedBroadcast(intentStandard,null);//发送有序广播

接下来我们来修改它的优先级

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="broadcastreceiver.csdn.com.demo2">    <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=".MainAty">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>        <receiver            android:name=".Demo2Receiver"            android:enabled="true"            android:exported="true">            <intent-filter android:priority="100">                <action android:name="com.csdn.broadcastreceiver.MY_RECEIVER"/>            </intent-filter>        </receiver>    </application></manifest>

我们通过android:priority属性给广播接收器设置了优先级,优先级高的先运行


学习了接收广播的优先级,我们再学一个方法,abortBroadcast(),截断广播,优先级高德广播截断后,优先级低的广播就无法收到了。

package broadcastreceiver.csdn.com.demo2;import android.content.BroadcastReceiver;import android.content.Context;import android.content.Intent;import android.widget.Toast;public class Demo2Receiver extends BroadcastReceiver {    @Override    public void onReceive(Context context, Intent intent) {        Toast.makeText(context,"Demo2也收到了标准广播",Toast.LENGTH_SHORT).show();        abortBroadcast();//将这条广播截断    }}


四 本地广播



有的时候我们发出的广播只要求本地能够接受,这个时候就要用到本地广播,本地广播的特点是发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本地应用程序发出的广播。

下面我们看看代码:

LocalityAty.class

package broadcastreceiver.csdn.com.aty;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.support.annotation.Nullable;import android.support.v4.content.LocalBroadcastManager;import android.view.View;import android.widget.Toast;import org.xutils.view.annotation.Event;import org.xutils.x;import broadcastreceiver.csdn.com.R;/** * 本地广播 * Created by Administrator on 2017/5/30. */public class LocalityAty extends Activity{    private String LOCALITY_BROADCAST="com.csdn.broadcastreceiver.LOCALITY_BROADCAST";    private IntentFilter intentFilter;    private LocalityReceiver localityReceiver;    /**     * 本地广播需要使用LocalBroadcastManager对广播进行管理     */    private LocalBroadcastManager localBroadcastManager;    @Event(value = {R.id.bn_locality})    private void onClick(View v){        switch (v.getId()){            case R.id.bn_locality:                //发送本地广播                Intent intent=new Intent(LOCALITY_BROADCAST);                localBroadcastManager.sendBroadcast(intent);                break;        }    }    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.aty_locality);        x.view().inject(this);        localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取实例        intentFilter =new IntentFilter();        intentFilter.addAction(LOCALITY_BROADCAST);        localityReceiver=new LocalityReceiver();        localBroadcastManager.registerReceiver(localityReceiver,intentFilter);//注册本地广播监听器    }    @Override    protected void onDestroy() {        super.onDestroy();        localBroadcastManager.unregisterReceiver(localityReceiver);    }    class LocalityReceiver extends BroadcastReceiver{        @Override        public void onReceive(Context context, Intent intent) {            Toast.makeText(LocalityAty.this,"收到了本地广播",Toast.LENGTH_SHORT).show();        }    }}

aty_locality.xml

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent">    <Button        android:id="@+id/bn_locality"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginTop="260dp"        android:text="本地广播"        app:layout_constraintLeft_toLeftOf="parent"        app:layout_constraintRight_toRightOf="parent"        app:layout_constraintTop_toTopOf="parent"        app:layout_constraintHorizontal_bias="0.527" /></android.support.constraint.ConstraintLayout>

面我们来总结一下本地广播的特点吧:

1.本地广播无法通功静态注册

2.本地广播更安全,因为发出的广播不用担心被其他应用监听到,

3.本地广播比全局广播高效

还有一点要说明的是广播接收器里不能进行耗时操作,不能开启多线程


源码下载地址