Android 组件BroadcastReceiver(一)


1.广播机制简介

Android中每个应用程序可以注册自己感兴趣的广播,以便接收来自系统或其他应用程序发出的广播。
广播接收器(BroadcastReceiver)没有可见的用户界面,它可以启动一个Activity或Service来响应它们收到的信息,或者使用NotificationManager来通知用户。作出响应的形式有闪动背灯、振动、播放声音,或在状态栏上显示图标。
android中Broadcast是应用程序之间传输信息的机制,过程是将发送的信息和过滤信息装入一个Intent对象,调用sendBroadcast()、sendOrderBroadcast()或者sendStickyBroadcast()方法,将Intent对象以广播的形式发送出去,已注册的BroadcastReceiver会进行IntentFilter检查匹配,若匹配则调用重写的onReceive()方法。

2.广播接收器应用

广播接收器的注册有两种方式:1. 动态注册(在代码中注册),2. 静态注册(在AndroidManifest.xml中注册)。

  1. 动态注册
    只需要新建一个广播接收器类,让它继承自BroadcastReceiver,并重写父类的onReceive()方法 就可以了。创建一个IntentFilter实例,并通过addAction()方法添加广播,最后通过registerReceiver()广播接收器实例IntentFilter实例注册其中,这样当有广播到来时,onReceive()方法就会得到执行,具体的逻辑就可以在这个方法中处理。
    最后要记得,动态注册的广播接收器一定都要取消注册才行,这里我们是在onDestroy()方法中通过调用unregisterReceiver()方法来实现的。(有说是为了释放内存)
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);
    }

//自定义的广播接收器
public class NetworkChangeReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("Broadcast", "network changes!!!!!~");
        Toast.makeText(context, "network changes", Toast.LENGTH_LONG).show();

    }
}
//必要时要在AndroidManifest.xml添加权限uses-permission

要在AndroidManifest.xml添加权限。

  1. 静态注册
    上述的动态注册的广播接收器可以自由地控制注册与注销,很灵活,但是必须在程序启动后才能接收到广播,因为注册的逻辑是写在onCreate()方法中的。
    静态注册实现了在程序未启动的情况下就能接收到广播。
    在AndroidManifest.xml 文件中 将广播接收器的类名注册进去,在标签内出现了一个新的标签 ,所有的静态注册的广播接收器都是注册在这里的,在标签过滤想要接受的广播就可以了。
<!-- 将BootReceiver接收器注册其中并加入过滤器过滤广播 -->
       <receiver
            android:name=".BootReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

3.发送自定义广播

广播分为两种类型:1. 标准广播;2. 有序广播。
1. 标准广播(Normal broadcasts)
标准广播时一种完全异步执行的,广播消息发出后所有的广播接收器几乎同时接收到,没有先后顺序。

//发送标准广播
        btnSendBroadcast.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcasttest.NORMAL_BROADCAST");
                //发送广播
                sendBroadcast(intent);
            }
//创建广播接收器 NormalBroadcastReceiver
public class NormalBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receiver in NormalBroadcastReceiver.", Toast.LENGTH_LONG).show();
        abortBroadcast();
    }

}
//本项目中创建广播接收器NormalBroadcastReceiver的AndroidManifest.xml文件中
       <receiver
            android:name=".NormalBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcasttest.NORMAL_BROADCAST"/>
            </intent-filter>
        </receiver>

2.有序广播
这是一种同步执行的广播,广播发出之后,同一刻只会有一个广播接收器能够接收到,当这广播接收器接收到信息并执行完毕后,广播才会继续传递。这时广播接收器接收是有先后顺序的,可以设置优先级。存在接收顺序也存在着广播会被截断。

btnSendOrderBroadcast = (Button) findViewById(R.id.btnSendOrderBroadcast);
        //发送有序广播
        btnSendOrderBroadcast.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcasttest.NORMAL_BROADCAST");
                sendOrderedBroadcast(intent, null);
            }
        });

    }
//另外创建一个Module并创建AnotherBroadcastReceiver接收器
public class AnotherBroadcastReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "receive in AnotherBroadcastReceiver!",Toast.LENGTH_LONG).show();
        abortBroadcast();
    }
}

广播是一种可以跨进程的通信方式。在这隐式Intent 其他包中的intent-filter 中的action 也会得到响应,也证明程序发出的广播时可以被其他的应用程序接收到的。<intent-filter android:priority="100">此设置广播接收器的优先级

有序广播中 在onReceive()方法中调用了abortBroadcast()方法,就表示将这条广播截断,后面的广播接收器将无法再接收到这条广播。

本地广播

以上发送和接收 的广播全部都是属于系统全局广播,即发出的广播可以被其他的任何应用程序接收到,并且我们也可以接收来自其他任何应用程序的广播,安全性不高,可能会被截获。也会受到垃圾广播的侵扰。
所以本地广播即只能接收到广播只能在应用程序内部传递,并且广播接收器只能接收来自本应用程序发出的广播。
本地广播的用法主要就是使用了一个LocalBroadcastManager 来对广播进行管理,并提供了发送广播和注册广播接收器的方法。(和动态注册广播方式很像)本地广播是无法通过静态注册的方式来接收的。

public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private LocalReceiver localReceiver;
    private LocalBroadcastManager localBroadcastManager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //获取实例
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        Button btn = (Button) findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                Intent intent = new Intent("com.example.broadcastreceivertest.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);
            }
        });

        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastreceivertest.LOCAL_BROADCAST");
        localReceiver = new LocalReceiver();
        localBroadcastManager.registerReceiver(localReceiver, intentFilter);
    }
    @Override
    protected void onDestroy(){
        super.onDestroy();
        localBroadcastManager.unregisterReceiver(localReceiver);
    }
    class LocalReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context , "received local broadcast", Toast.LENGTH_LONG).show();
        }
    }
}

和动态广播注册的方式很像,只不过调用了localBroadcastManager。

本地广播的优势:
1. 明确的知道正在发送的广播不会离开我们的程序,因此不会担心数据泄漏的问题
2. 其他应用程序的无法将广播发送到此应用程序的内部,不必担心有安全的漏洞的问题
3. 发送本地广播比系统全局广播将会更有效