【android笔记】广播

广播机制简介

Android中的广播机制更加灵活是因为android中的每个应用程序都可以对自己感兴趣的广播就行注册,该程序就只会接收到自己所关系的广播,这些广播可以是来自系统的,也可以是来自其他应用程序的.android有一套完整的API允许应用程序接收和发送广播.
Android中的广播可以分为有序广播和标准广播.
标准广播是一种完全异步执行的广播,在广播发出后所有的广播接收器几乎在同一时刻接收到这条广播,他们之间没有任何的先后顺序.这种广播效率较高但是同时也无法被截断.
有序广播则是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器接收该广播,当这个广播接收器中的逻辑执行完毕后广播才会继续向下传播.因此该广播是有先后顺序的,优先级高的广播接收器可以优先接收该广播,且前面的广播接收器是可以讲广播截断的,这样后面的广播接收器就不能再接收该广播信息了.

接收系统广播

动态注册监听网络变化

Android内置了很多系统级的广播,可以再应用程序中通过监听这些广播来得到系统的状态信息.接收广播需要使用广播接收器.广播接收器可以自由的对自己感兴趣的广播进行注册,当系统有这样的广播发出时,广播接收器就可以接收该广播,并进行内部的逻辑处理.
注册广播的方式方式一般有两种,在代码中注册和在AndroidManifest.xml中注册,前者又称为动态注册,后者又称为静态注册.
创建广播接收其实就是定义一个类并继承自BroadcastReceiver,并重写父类的onReceive方法.

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter =null;
    private  NetworkChangeReceiver  networkChangeReceiver=null;

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

        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) {
            Toast.makeText(context,"net work change",Toast.LENGTH_SHORT).show();
        }
    }

}

如上代码中在MainActivity中定义了一个内部类NetworkChangeReceiver继承自BroadcastReceiver,并重写了onReceive方法这就是我们的广播接收器.在onCreate方法中首先创建了一个IntentFilter实例,并将其action设置为“android.net.conn.CONNECTIVITY_CHANGE”,当网络状态发生变化时发出的就是这样一条广播,也就是说我们想要接收什么样的广播就在这里添加对应的action就可以了。接下来就是创建了一个networkChangeReceiver实例,并调用registerReceiver方法来注册广播接收器。

最后需要注意动态注册的广播接收器一定要取消注册才行,在activity的onDestroy方法中调用unregisterReceiver方法。

以上代码仅是演示了网络发生了变化,那么如何知道网络是否可用呢?修改MainActivity的代码如下:

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter =null;
    private  NetworkChangeReceiver  networkChangeReceiver=null;

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

        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);
            NetworkInfo networkInfo =connectivityManager.getActiveNetworkInfo();
            if(networkInfo!=null&& networkInfo.isAvailable()) {
                Toast.makeText(context,"net work is available",Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context,"net work is not available",Toast.LENGTH_SHORT).show();
            }
        }
    }

}

在onReceiver方法中首先通过getSystemService方法得到了ConnectivityManager的实例,它是一个系统服务类,专门用于管理网络连接的,然后调用它的getActiveNetworkInfo方法得到NetworkInfo实例,接着调用它的isAvailable方法判断当前网络是否可用。
需要主要,android系统为了保证应用程序的安全性做了规定,如果程序要访问一些系统的关键信息,必须在配置文件中声明权限才可以,否则程序就会直接崩溃,这里在查询网络状态时是需要权限的。修改AndroidManifest.xml文件如下:添加红色部分的权限声明

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test.broadcasttest">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <application
        android:allowBackup="true"

静态注册实现开机启动

动态注册的广播接收器必须要在程序启动之后才能接收到广播,因为注册的逻辑是写在activity的onCreate方法中的。静态注册方法可以实现在系统没有启动时就能接收广播。
新建广播接收的类BootCompleteReceiver

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,"启动完成",Toast.LENGTH_SHORT).show();
    }
}

然后再AndroidManifest.xml文件中静态注册,修改如下:

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    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" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>>
</application>

如上红色部分,添加了新的标签receiver,其中
android:name属性指明了具体是注册哪一个广播接收器,
intent-filter标签则指明了想要接收哪条广播

监听开机广播也是需要权限的,添加如下的权限代码:

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

以上的实例代码在onReceiver方法简单的使用Toast进行提示,实际开发中添加自己的逻辑。需要注意不要在onReceiver方法中添过多的逻辑或者比较耗时的操作,因为在广播接收器中是不允许开启线程的,当onReceiver方法运行了较长时间而没有结束时程序就会报错,广播接收器更多的是扮演一种打开程序其他组件的角色,例如创建一条通知栏通知或者启动一个服务等。

发送自定义广播

发送标准广播

发送广播前还是先定义一个广播接收器来准备接受要发送的广播。新建类MyBroadcastRceiver,重写onReceiver方法。

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,"received my message",Toast.LENGTH_SHORT).show();
    }
}

静态注册广播接收器

   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=".MyBroadcastReceiver" >
        <intent-filter>
            <action android:name="com.example.test.broadcastreceiver2.MY_BROADCAST"/>
        </intent-filter>
    </receiver>
</application>

这里接的广播为com.example.test.broadcastreceiver2.MY_BROADCAST
修改activity_main.xml,添加发送广播按钮


<Button
    android:id="@+id/send"
    android:text="发送广播"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

修改MainActivity的代码:

public class MainActivity extends AppCompatActivity {
    private Button send =null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        send = (Button )findViewById(R.id.send);
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.test.broadcastreceiver2.MY_BROADCAST");
                sendBroadcast(intent);
            }
        });
    }
}

首先构建intent对象,传入要发送的广播值,然后调用sendBroadcast方法将广播发送出去。运行程序即可。

发送有序广播

广播室一种可以跨进程的通信方式,因此我们在程序内部发送的广播也可以在其他的应用程序中接收到。该如何验证呢?
新建项目BroadcastTest2,在该项目中新建广播接收器AnotherBroadcastReceiver继承自BroadcastReceiver代码如下:

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

public class AnotherBroadcastReceiver  extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"received in AnotherBroadcastReceiver",Toast.LENGTH_SHORT).show();
    }
}

静态注册广播接收器

<receiver android:name=".AnotherBroadcastReceiver" >
    <intent-filter>
        <action android:name="com.example.test.broadcastreceiver2.MY_BROADCAST"/>
    </intent-filter>
</receiver>

这里要监听的广播依然是上一个实例代码中的com.example.test.broadcastreceiver2.MY_BROADCAST这个广播,然后我们运行BroadcastTest2,然后再来运行之前的一个按钮发送广播的项目,就会在提示界面出现两次接收到广播的提示。
从而证明我们发送的广播是可以被其他的应用程序接收到的。

以上还都是发送标准广播,现在来修改代码来发送有序广播。
修改MainActivity中的代码如下:

public class MainActivity extends AppCompatActivity {
    private Button send =null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        send = (Button )findViewById(R.id.send);
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.test.broadcastreceiver2.MY_BROADCAST");
                sendOrderedBroadcast(intent,null);
            }
        });
    }
}

只需要将sendBroadcast方法改为sendOrderedBroadcast方法即可,该方法第二个参数是一个与权限相关的字符串,这里传入bull即可。

广播的接收顺序又如何设定呢?修改AndroidManifest.xml的代码如下:

<receiver android:name=".MyBroadcastReceiver" >
    <intent-filter android:priority="100">
        <action android:name="com.example.test.broadcastreceiver2.MY_BROADCAST"/>
    </intent-filter>
</receiver>

通过android:priority属性给广播设置了优先级,优先级高的广播接收器就可以先收到广播,这里设置为100可以保证MyBroadcastReceiver先于AnotherBroadcastReceiver收到广播。

如何截断广播呢?修改广播接收器代码如下:

public class MyBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"received my message",Toast.LENGTH_SHORT).show();
        abortBroadcast();
    }
}

在onReceiver方法中调用了abortBroatcast方法表示来截断广播后面的广播接收器就无法再接收广播了。

使用本地广播

前面介绍的广播全部属于系统全局广播,即发出的广播可以被其他应用程序接收,而且我们也可以接收来自于其他应用程序的广播,这样很容易安全问题,例如我们发出的一条携带关键信息的广播可能被其他应用程序截获等等。
使用本地广播发送的广播只能在程序内部进行传递,且广播接收器也只能接收来自本应用程序发出的广播,安全性问题不再存在。
本地广播的使用并不复杂主要是用LocalBroadcastManager来对广播进行管理,并提供了发送和接收广播的方法。

public class MainActivity extends AppCompatActivity {
    private Button send = null;

    private IntentFilter intentFilter =null;
    private LocalBroadcastManager localBroadcastManager=null;
    private  LocalReceiver localReceiver =null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        send =(Button)findViewById(R.id.send);
        send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.test.localbroadcastreceiver.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);
            }
        });
        intentFilter =new IntentFilter();
        intentFilter.addAction("com.example.test.localbroadcastreceiver.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver,intentFilter);
    }

    @Override
    protected void onDestroy() {
        localBroadcastManager.unregisterReceiver(localReceiver);
    }

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

本地广播的优势:
(1) 可以明确的知道正在发送的广播不会离开我们的应用程序,因此不要需要担心机密数据的泄露问题
(2) 其他的应用程序无法将广播发送到我们程序内部,因此不需要担心会有安全漏洞的隐患
(3) 发送本地广播比发送系统全局广播更加高效。

猜你喜欢

转载自blog.csdn.net/yuewen2008/article/details/81358628