android广播机制


一:广播机制简介


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.本地广播比全局广播高效

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


源码下载地址



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值