第四章(广播机制Broadcast简介)

广播机制简介

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

标准广播:

标准广播是一种完全异步执行的广播,在广播发出以后,所有的广播接收器几乎都会在同一时刻接收到这条广播信息,因此它们之间没有图呢he先后顺序可言,这种广播效率会比较高,但也以为着它是无法被截断的

有序广播

有序广播是一种同步执行的广播,在广播发出以后,同一时刻只会有一个广播接收器能接收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递,所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就优先接收到广播消息,并且前面的广播接收器可以截断正在传递的广播,后面的广播接收器就不能接收到广播消息了。

接收系统广播

Android内置了很多系统级别的广播,我们可以在程序中监听这些广播来得到系统的状态信息,比如,手机开机后系统会发送一条广播,电池没电了系统也会发送一条广播。如果想接收到这些广播就需要使用广播接收器。

注册方式

广播接收器可以自由地对自己感兴趣的广播进行注册,这样当有相应的广播发出时,广播接收器就能接收到该广播,并在内部处理相应的逻辑。注册广播方式一般有两种,第一种实在代码中注册,第二种实在AndroidManifest.xml中注册,前者成为动态注册,后者成为静态注册
下面举几个例子

  • 动态注册监听网络变化,新建项目BroadcastTest1

如何建一个广播接收器?只需建一个类继承BroadcastReceiver并重写父类的onReceiver方法就行了,当有广播到来时onReceiver方法就会得到执行

   class NetWorkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "网络发生了变化", Toast.LENGTH_SHORT).show();
        }
    }

这个类可以写在Activity的内部,也可以另外建一个类

  1. 监听网络状态变化
public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetWorkChangeReceiver receiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        receiver = new NetWorkChangeReceiver();
        registerReceiver(receiver, intentFilter);
    }


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

    
    class NetWorkChangeReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "网络发生了变化", Toast.LENGTH_SHORT).show();
        }
    }
}

当系统网络状态发生变化的时候,系统就会发出一条值为android.net.conn.CONNECTIVITY_CHANGE的广播,所以我们在IntentFilter中添加相应的action,然后调用registReceiver方法进行注册,传入NetWorkChangeReceiver和IntentFilter的实例,这样就实现了监听网络变化的功能。最后记得动态注册的广播接收器一定要取消才行,即在onDestroy中通过调用unregisterReceiver方法来实现


image
  1. 监听网络是否可用
    我们创建一个SecondActivity,并创建一个NetWorkChangeReceiver继承BroadcastReceiver并重写onReceive方法
public class SecondActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetWorkChangeReceiver netWorkChangeReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        intentFilter=new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        netWorkChangeReceiver=new NetWorkChangeReceiver();
        registerReceiver(netWorkChangeReceiver,intentFilter);
    }

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

    class NetWorkChangeReceiver extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager connectivityManager=(ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            //getSystemService根据名字获取一个系统级别的服务类
            NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
            if(networkInfo!=null&&networkInfo.isAvailable()){
                Toast.makeText(context,"网络可用",Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(context,"网络不可用",Toast.LENGTH_SHORT).show();
            }

        }
    }
}

在onReceive方法中首先通过getSystemService获得ConnectivityManager的实例,这是四专门用于管理网络连接的,然后调用它的getActiveNetworkInfo方法获得一个NetworkInfo的实例,最后调用NetworkInfo的isAvailable方法判断当前是否有网络,通过Toast提示。
这里访问系统的网络状态是要声明权限的


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

我们点击NETWORK_CHANGE_DETAILS按钮,启动SecondACtivity,打开或关闭数据服务就能看到Toast提示


image
  • 静态注册实现开机启动监听(系统开机后会发送一条广播)

动态注册的广播接收器可以自由地注册和注销,很灵活,但是它有个缺点就是必须 要把程序启动之后才能实现监听,因为注册逻辑是卸载onCreate方法中的。
使用静态注册的方式能让程序在未启动的状态下实现监听广播。下面看怎么使用

  1. 新建一个广播接收器名为BootCompletReceiver并将Exported和Enabled属性勾选。Exported属性表示是否允许这个广播接收器接收本程序以外的广播,Enabled属性表示是否启用这个广播接收器


    image

public class BootCompletReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"开机完成",Toast.LENGTH_SHORT).show();
    }
}

  1. 静态注册的广播接收器一定要在AndroidManifest.xml文件中注册才能使用,但由于我们是使用AS自带的快捷方式创建的广播接收器,所以它自动帮我们将这一步完成了
     <receiver
            android:name=".BootCompletReceiver"
            android:enabled="true"
            android:exported="true">
            </receiver>
      
  1. 所有的静态广播接收器都要在<receiver>标签内进行注册,name用来制定是注册哪一个广播接收器,enabled和exported是根据我们刚才勾选的状态自动生成的。
    由于系统启动后会发送一条值为android.intent.action.BOOT_COMPLETED的广播,所以我们要在<intent-filter>标签中添加相应的action

       <receiver
            android:name=".BootCompletReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
  1. 添加相应的权限,监听系统开机广播是需要声明权限的
 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

这样就能实现开机程序监听开机广播了


image
  • 发送自定义广播

前面介绍了广播分为两种:标准广播和有序广播

发送自定义标准广播,新建MyBroadcastReceiver项目
  1. 我们新建一个自定义的广播接收器

public class MyBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"我自定义的广播",Toast.LENGTH_SHORT).show();
    }
}

  1. 在布局里面添加一个Button,点击这个Button就会发送我们自己定义的广播
    public void sendbroadcast(View view) {
        Intent intent = new Intent("com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver");
        sendBroadcast(intent);
    
    }
    

Intent中传入的是一条Action值,然后调用sendBroadcast方法将intent传进去,当然现在还是不能监听广播的,我们还需要在清单文件中配置一下

  1. 修改AndroidManifest.xml

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

这样我们的点击Button就会发出一条我们自定义的广播并且能接收到这条广播了

发送自定义的有序广播
  1. 发送有序广播非常简单,只需要将sendBroadcast改成sendOrderedBroadcast并传入两个参数
public class MainActivity extends AppCompatActivity {

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

    public void sendbroadcast(View view) {
        Intent intent = new Intent("com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver");
        //sendBroadcast(intent);
        sendOrderedBroadcast(intent, null);
    }
}

第一个参数是Intent不用解释,另一个参数是一个与权限相关的字符串官方解释是:String naming a permissions that a receiver must hold in order to receive your broadcast. If null, no permission is required.一般情况下传入null就可以了,除特殊情况。

  1. 成功发送有序广播后我们再试图去别的程序里面截断这条广播,使发出这条广播的程序无法接收到这条广播
    在上面动态注册监听网络变化BroadcastTest1项目里面创建一个AnotherBroadcastReceiver
public class AnotherBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"在Broadcasttest1中接收到了MyBroadcastReceiver发出的广播",Toast.LENGTH_SHORT).show();
        abortBroadcast();//截断这条广播
    }
}

截断广播非常简单,只需要在BroadcastReceiver中调用abortBroadcast()方法就行了

  1. 然后修改BroadcastTest1项目中的AndroidManifest.xml文件
     <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter>
                <action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
            </intent-filter>
        </receiver>
  1. 要想截断这条广播那么我们就必须保证BroadcastTest1程序优先于MyBroadcastReceiver程序接收到MyBroadcastReceiver程序发送的广播,并截断这样MyBroadcastReceiver程序就不会接收到它自己发送的广播了。怎样做呢?其实只需要设置一个优先级就可以了,添加android:priority="100",设置成一百就可以了
     <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
           >
            <intent-filter 
            android:priority="1000">
                <action android:name="com.example.houchongmu.mybroadcastreceiver.MyBroadcastReceiver" />
            </intent-filter>
        </receiver>
        

这样BroadcastTest1程序就能接收到MyBroadcastReceiver程序发送过来的广播了,并且能截断它。


image
  • 使用本地广播

上面讲的发送和接收的都属于全局广播,即发出的广播可以被其他任何应用程序接收到,并且也可以接受来自其他程序的广播,这样就不够安全,为了解决这个安全问题,Android引入了一套本地的广播机制,使用这个机制程序发出的广播只能在程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样安全性问题就不存在了。
主要是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法,看例子:

package com.example.houchongmu.mybroadcastreceiver;

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.Toast;

public class LocalBroadcastActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalBroadcast localBroadcast;
private LocalBroadcastManager localBroadcastManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_local_broadcast);
        intentFilter=new IntentFilter();
        localBroadcast=new LocalBroadcast();
        localBroadcastManager=LocalBroadcastManager.getInstance(this);//获取LocalBroadcastManager的实例
        intentFilter.addAction("com.example.localbroadcast");
        localBroadcastManager.registerReceiver(localBroadcast,intentFilter);
    }
    
    public void send_localbroadcast(View view){
        Intent intent=new Intent("com.example.localbroadcast");
        localBroadcastManager.sendBroadcast(intent);
    }
    
    class LocalBroadcast extends BroadcastReceiver{

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context,"接收到本地广播",Toast.LENGTH_SHORT).show();
        }
    }

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

上面的代码很容易理解就不过多解释了


image

关于广播机制就暂时讲到这里,以后学习到新的知识再进行补充。

原创文章 43 获赞 6 访问量 791

猜你喜欢

转载自blog.csdn.net/qq_34088913/article/details/105946730
今日推荐