Android Broadcast Receiver 基础详解

Android中的广播机制十分灵活,因为Android中的每个应用程序都可以对自己感兴趣的广播进行注册。它提供了一套完整的API允许应用程序自由的发送和接受广播。

广播分为两类:1.标准广播,是一种完全异步执行的广播,在广播发出后,所有的接收器几乎在同一时间收到广播消息;2.有序广播,是一种同步执行的广播,在广播发出后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕了,广播才会继续传递,并且前面的广播接收器可以截断广播。

注册广播的方式有两种:1.动态注册即在代码中注册;2.静态注册即在AndroidManifest.xml中注册。



1.动态注册监听网络变化。

package company.testbroadcast;

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

/**
 * Created by samyang on 2016/8/29.
 */
public class MainActivity extends Activity {

    private IntentFilter mIntentFilter;
    private NetworkChangeReceiver mNetworkChangeReceiver;

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

        mIntentFilter = new IntentFilter();
        mIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        mNetworkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(mNetworkChangeReceiver, mIntentFilter);

    }

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

    private class NetworkChangeReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "network changed", Toast.LENGTH_SHORT).show();
        }
    }
}

首先建立一个NetworkChangeReceiver内部类,让它继承自BroadcastReceiver。并重写其中的onReceive方法。然后,声明并实例化mIntentFilter和mNetworkChangeReceiver,在mIntentFilter中添加一个addAction传入"android.net.conn.CONNECTIVITY_CHANGE"(当系统网络发生变化时,发出一条该值的广播),并注册接收器,传入两个参数:要动态注册的广播接收器实例,和添加了Action的IntentFilter实例。最后在onDestroy方法中取消注册

运行程序,然后按home键回到主界面,此时不能按back键,否则会调用onDestroy方法。然后在手机设置中更改网络状态,即会弹出Toast如下图所示。


此时我们只是在onReceive方法中加入了简单的逻辑。我们并不能知晓当前网络状态是变为有网络还是无网络。因此,我们更改代码,使用户准确的知晓当前网络状态。更改onReceive方法中的代码如下:

private 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, "network is available", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
        }
    }
}

借助getSystemService方法获取connectivityManager实例,然后通过调用connectivityManager的getActivityNetworkInfo方法获取networkInfo实例。这样我们就能够用network实例的isAvailable方法判断当前的网络状态,从而加入相应的逻辑。当然,我们还需要在AndroidManifest.xml中获取网络状态的权限。

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

运行程序,再次更改网络状态后如下图所示:




2.静态注册实现开机启动。

此时你可能发现,我们的广播必须在启动了app之后才会执行onCreate方法,这时写在其中的注册逻辑才能得到执行。但有的时候我们需要在开机后而app未启动前就能够收到广播。由于系统启动完成后会自动发出一条值为android.intent.action.BOOT_COMPLETED的广播,我们以此来做示例。

package company.testbroadcast;

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

/**
 * Created by samyang on 2016/8/29.
 */
public class BootCompleteReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "boot completed", Toast.LENGTH_SHORT).show();
    }
}

新建一个类,而不是内部类。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="company.testbroadcast">

    <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>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

</manifest>

在AndroidManifest中静态注册receiver,而不是在activity的onCreate中去动态注册。当然完了之后一样要拿到RECEIVE_BOOT_COMPLETED的权限。

运行程序,然后重启系统如下图所示:




3.发送标准广播

刚才我们发送的广播都是通过接收器去接收系统的广播,接下来我们打算发送自己的定义的广播然后让指定的接收器接收。

新建一个StandardBroadcastReceiver类。

package company.testbroadcast;

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

/**
 * Created by samyang on 2016/8/29.
 */
public class StandardBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received standard broadcast", Toast.LENGTH_SHORT).show();
    }
}

在布局中添加一个按钮,然后在MainActivity中添加下面一段代码:

Button sendStandard = (Button) findViewById(R.id.send_standard_broadcast);
sendStandard.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent("company.testbroadcast.MY_STANDARD_BROADCAST");
        sendBroadcast(intent);
    }
});

在AndroidManifest.xml中添加注册:

<receiver android:name=".StandardBroadcastReceiver">
    <intent-filter>
        <action android:name="company.testbroadcast.MY_STANDARD_BROADCAST"/>
    </intent-filter>
</receiver>

这样当我们点击按钮时,就会发送一个传入了intent的广播,而StandardBroadcastReceiver这个接收器已经静态注册了接收值跟intent一样的广播。因此就会弹出toast提示received standard broadcast。




4.发送有序广播

在新建一个AnotherBroadcast类,在onReceive方法中写入弹出toast提示received another broadcast的逻辑。

package company.testbroadcast;

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

/**
 * Created by samyang on 2016/8/29.
 */
public class AnotherBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "received another broadcast", Toast.LENGTH_SHORT).show();
    }
}

同样为其进行动态注册。

<receiver android:name=".AnotherBroadcast">
    <intent-filter>
        <action android:name="company.testbroadcast.MY_STANDARD_BROADCAST"/>
    </intent-filter>
</receiver>

并将StandardBroadcastReceiver的优先级改为100。

<receiver android:name=".StandardBroadcastReceiver">
    <intent-filter android:priority="100">
        <action android:name="company.testbroadcast.MY_STANDARD_BROADCAST"/>
    </intent-filter>
</receiver>

此时再次点击按钮时,就会先后弹出toast:"received standard broadcast", "received another broadcast"。说明我们通过sendOrderedBroadcast实现了发送有序广播。里面传入两个值:第一个为intent,第二个参数是一个与权限相关的字符串,这里传入null即可。



5.本地广播

此时又出现了一个新的问题,到目前为止,我们发送的都是系统性的全局广播。发送的广播不仅可以被其他任何程序收到造成混乱,还有可能被其他应用程序拦截下来从而造成安全问题。Android为了解决广播的安全性问题,引入了一套本地广播机制。主要就是通过LocalBroadcastManager来对广播进行管理

接下来我们就要通过一个例子来学习本地广播的使用。在这个例子中我们首先想要发送一条"company.testbroadcast.LOCAL_BROADCAST"的广播,在testbroadcast项目中去接收到这条广播并弹出toast,同时在新建立的testforlocalbroadcast项目中也能接收到这条广播并弹出toast。这样表示我们发出的广播是能被其他应用程序接收到的。然后更改testbroadcast中代码使用本地广播,此时再观察testforlocalbroadcast是否能收到。

首先新建了testforlocalbroadcast项目,在其中实现如下代码。

package company.testlocalbroadcast;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private LocalBroadcastReceiver mLocalBroadcastReceiver;
    private IntentFilter mIntentFilter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mIntentFilter = new IntentFilter();
        mIntentFilter.addAction("company.testbroadcast.LOCAL_BROADCAST");
        mLocalBroadcastReceiver = new LocalBroadcastReceiver();
        registerReceiver(mLocalBroadcastReceiver, mIntentFilter);
    }

    private class LocalBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast in 'company.testlocalbroadcast'", Toast.LENGTH_SHORT).show();
        }
    }

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

然后修改testbroadcast项目,添加的代码后面都打了注释,我不想删除之前的功能示例可能导致代码有点乱,麻烦仔细看下定能理清。

package company.testbroadcast;

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.view.View;
import android.widget.Button;
import android.widget.Toast;

/**
 * Created by samyang on 2016/8/29.
 */
public class MainActivity extends Activity {

    private IntentFilter mIntentFilter;
    private NetworkChangeReceiver mNetworkChangeReceiver;
    private IntentFilter mlocalIntentFilter;                              //重新声明IntentFilter和LocalBroadcastReceiver
    private LocalBroadcastReceiver mLocalBroadcastReceiver;

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

        mIntentFilter = new IntentFilter();
        mIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        mNetworkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(mNetworkChangeReceiver, mIntentFilter);

        mlocalIntentFilter = new IntentFilter();                         //添加发送"company.testbroadcast.LOCAL_BROADCAST"的Action并动态注册接收器
        mlocalIntentFilter.addAction("company.testbroadcast.LOCAL_BROADCAST");
        mLocalBroadcastReceiver = new LocalBroadcastReceiver();
        registerReceiver(mLocalBroadcastReceiver, mlocalIntentFilter);


        Button sendStandard = (Button) findViewById(R.id.send_standard_broadcast);
        sendStandard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("company.testbroadcast.MY_STANDARD_BROADCAST");
                sendOrderedBroadcast(intent, null);
            }
        });

        Button sendLocal = (Button) findViewById(R.id.send_local_broadcast);        //添加按钮,实现点击逻辑
        sendLocal.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("company.testbroadcast.LOCAL_BROADCAST");
                sendBroadcast(intent);
            }
        });

    }

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

    private 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, "network is available", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
            }
        }



    }

    private class LocalBroadcastReceiver extends BroadcastReceiver {         //新建LocalBroadcastReceiver内部类

        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast in 'company.testbroadcast'", Toast.LENGTH_SHORT).show();
        }
    }
}

先后运行两个项目,然后切换到testbroadcast项目点击SEND LOCAL BROADCAST按钮可以得到如下图结果。


此时已经证明了我们发送的广播是能够被其他应用程序接收到的。然后我们修改testbroadcast项目,使用本地广播机制,来检验testlocalbroadcast是否还能接收到广播。

package company.testbroadcast;

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.support.v4.content.LocalBroadcastManager;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

/**
 * Created by samyang on 2016/8/29.
 */
public class MainActivity extends Activity {

    private IntentFilter mIntentFilter;
    private NetworkChangeReceiver mNetworkChangeReceiver;
    private IntentFilter mlocalIntentFilter;
    private LocalBroadcastReceiver mLocalBroadcastReceiver;
    private LocalBroadcastManager localBroadcastManager;                //声明localBroadcastManager


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

        localBroadcastManager = LocalBroadcastManager.getInstance(this); //获取实例

        mIntentFilter = new IntentFilter();
        mIntentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        mNetworkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(mNetworkChangeReceiver, mIntentFilter);


        Button sendStandard = (Button) findViewById(R.id.send_standard_broadcast);
        sendStandard.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("company.testbroadcast.MY_STANDARD_BROADCAST");
                sendOrderedBroadcast(intent, null);
            }
        });


        Button sendLocal = (Button) findViewById(R.id.send_local_broadcast);
        sendLocal.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("company.testbroadcast.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);            //通过Manager来发送广播

            }
        });

        mlocalIntentFilter = new IntentFilter();
        mlocalIntentFilter.addAction("company.testbroadcast.LOCAL_BROADCAST");
        mLocalBroadcastReceiver = new LocalBroadcastReceiver();
        localBroadcastManager.registerReceiver(mLocalBroadcastReceiver,mlocalIntentFilter);    //通过Manager来注册广播


    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mNetworkChangeReceiver);                                            //通过Manager来取消注册广播
        localBroadcastManager.unregisterReceiver(mLocalBroadcastReceiver);
    }

    private 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, "network is available", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
            }
        }



    }

    private class LocalBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received local broadcast in 'company.testbroadcast'", Toast.LENGTH_SHORT).show();
        }
    }
}

本地广播主要是通过获取到一个localBroadcastManager实例然后通过该实例来进行发送广播、注册、取消注册等操作。(实现处已在上述代码中打了注释)

注意一点:刚才我在写好代码运行testbroadcast项目后,testlocalbroadcast仍能接收到我在testbroadcast中发出的本地广播。然后我将两个程序都卸载了重装,就正常了。无论如何点击SEND LOCAL BROADCAST按钮,都只会弹出"received local broadcast in 'company.testbroadcast'"这个toast。从而确认了本地广播的使用。



至此,Android四大组件中的Broadcast Receiver的常见用法已经介绍完毕了。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值