手把手教你-Android 广播机制

 

一、概述

广播(Broadcast)机制用于进程/线程间通信,因此在我们应用程序内发出的广播,其他的应用程序应该也是可以收到的。广播分为广播发送和广播接收两个过程,其中广播接收者BroadcastReceiver便是Android四大组件之一。

BroadcastReceiver(广播接收)分为两类:

  • 静态广播接收者:通过AndroidManifest.xml的标签来申明的BroadcastReceiver。
  • 动态广播接收者:通过AMS.registerReceiver()方式注册的BroadcastReceiver,动态注册更为灵活,可在不需要时通过unregisterReceiver()取消注册。

广播发送方式可分为三类:

  • 普通广播:通过Context.sendBroadcast()发送,可并行处理
  • 有序广播:通过Context.sendOrderedBroadcast()发送,串行处理
  • Sticky广播:通过Context.sendStickyBroadcast()发送

 

二、作用

主要用于监听(接收)应用发出的广播消息,并做出响应。

常见应用场景 

a. 不同组件之间通信(包括应用内 / 不同应用之间) 

b. Android系统在特定情况下与App之间的消息通信(当电话呼入时,网络可用时)

c. 多线程通信

 

三、注册广播

1.静态注册广播

常驻型广播,这个广播接收者会在程序运行的整个过程中一直存在,不会被注销掉,当程序被杀掉后不会再接收到广播了。它的注册方式就是在你应用程序的AndroidManifast.xml 中进行注册,这种注册方式通常又被称作静态注册。这种方式可以理解为通过清单文件注册的广播是交给操作系统去处理的。在Manifest.xml中注册广播,是一种比较推荐的方法,因为它不需要手动注销广播(如果广播未注销,程序退出时可能会出错)在配置文件中加入:

<receiver android:name=".receiver.WakeReceiver">
    <intent-filter>
        <!--   利用系统广播拉活-->
        <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- Android开机广播-->
        <!-- 系统广播,接收打电话的广播 ,这个需要配置权限 -->
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        <action android:name="android.intent.action.USER_PRESENT" /><!--锁屏解锁-->
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /><!--网络变化-->
        <action android:name="com.wake.gray" /><!-- 自定义广播 -->
    </intent-filter>
</receiver>

2.动态注册广播

动态注册广播不是常驻型广播,也就是说广播跟随程序的生命周期结束。

实现流程:

  1. 实例化自定义的广播接收者
  1. 实例化意图过滤器,并设置要过滤的广播类型(如,我们接收收到短信系统发出的广播)
  1. 使用Context的registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)方法注册广播

3.两种注册广播的区别

第一种是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行,比如静态注册实现开机启动。

第二种不是常驻型广播,也就是说广播跟随程序的生命周期。动态注册的广播的优先级高于静态注册的广播。

 

四、 使用流程介绍

  1. 自定义广播接收者BroadcastReceiver子类,并复写onRecvice()方法;
  1. 通过Binder机制向AMS(Activity Manager Service)进行注册;
  1. 广播发送者通过Binder机制向AMS发送广播;
  1. AMS查找符合相应条件(IntentFilter/Permission等)的BroadcastReceiver,将广播发送到BroadcastReceiver(一般情况下是Activity)相应的消息循环队列中;
  1. 消息循环执行拿到此广播,回调BroadcastReceiver中的onReceive()方法。

 

4.1 自定义广播接收者

  • 继承自BroadcastReceivre基类
  • 必须复写抽象方法onReceive()如下:

1、广播接收器接收到相应广播后,会自动回调onReceive()方法

2、一般情况下,onReceive方法会涉及与其他组件之间的交互,如发送Notification、启动service等

3、默认情况下,广播接收器运行在UI线程,因此,onReceive方法不能执行耗时操作,否则将导致ANR

/**
 *  步骤一:继承BroadcastReceiver基类
 *  自定义接受网络变化的广播接收器
 *  该广播接收器可以单独写一个外部类
 * */
   class NetworkChangeReceiver extends BroadcastReceiver {
         // 接收到广播后自动调用该方法
         @Override
   public void onReceive(Context context, Intent intent) {
             //写入接收广播后的操作
             ConnectivityManager connectionManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
             NetworkInfo networkInfo = connectionManager.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();
             }
         }
     }

 

4.2 广播接收器注册

  1. 注册的方式分为两种:静态注册、动态注册

静态注册:

  • 在AndroidManifest.xml里通过标签声明
  • 属性说明:
<receiver
    android:name=".MyBroadcastReciver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <!--<action android:name="android.intent.action.BOOT_COMPLETED"/>-->
        <action android:name="com.example.broadcassttest.MY_BROADCAST"/>
    </intent-filter>
    </receiver>

当此App首次启动时,系统会自动实例化mBroadcastReceiver类,并注册到系统中。

动态注册:

在代码中通过调用Context的registerReceiver()方法进行动态注册BroadcastReceiver

registerReceiver(networkChangeReceiver, intentFilter); // 动态注册

注意:动态注册最好在onResume()注册、onPause()注销,是因为onPause()在App死亡前一定会被执行,从而保证广播在App死亡前一定会被注销,从而防止内存泄露。

  1. 两种注册方式对比

 

4.3 广播发送者向AMS发送广播

  • 广播发送:广播发送者将此广播的”意图“通过sendBroadcast()方法发送出去
//动态接受网络变化的广播接收器
intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");

 

五、程序实现

MyBroadcastReciver.java

public class MyBroadcastReciver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context,"自定义广播接收者",Toast.LENGTH_LONG).show();
    }
}

Mainactivity.java

/**
 * 动态注册案例
 */
public class MainActivity extends AppCompatActivity {
    private IntentFilter intentFilter;
    private NetworkChangeReceiver networkChangeReceiver;
    private Button noticebtn;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        noticebtn = (Button)findViewById(R.id.notice_btn);
 
        //动态接受网络变化的广播接收器
        intentFilter = new IntentFilter();
        intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        networkChangeReceiver = new NetworkChangeReceiver();
        registerReceiver(networkChangeReceiver, intentFilter); // 动态注册
 
        setOnclick();
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        //取消动态网络变化广播接收器的注册
        unregisterReceiver(networkChangeReceiver);
    }
 
    // 创建广播
//    class NetworkChangeReciver extends BroadcastReceiver{
//        @Override
//        public void onReceive(Context context, Intent intent) {
//            Toast.makeText(context,"网络改变",Toast.LENGTH_LONG);
//        }
//    }
 
    /**
     *  步骤一:继承BroadcastReceiver基类
     *  自定义接受网络变化的广播接收器
     *  该广播接收器可以单独写一个外部类
     * */
         class NetworkChangeReceiver extends BroadcastReceiver {
             // 一般情况下,onReceive方法会涉及与其他组件之间的交互,如发送Notification、启动service等
             // 默认情况下,广播接收器运行在UI线程,因此,onReceive方法不能执行耗时操作,否则将导致ANR
             // 接收到广播后自动调用该方法
             @Override
             public void onReceive(Context context, Intent intent) {
                 //写入接收广播后的操作
                 ConnectivityManager connectionManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
                 NetworkInfo networkInfo = connectionManager.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 void setOnclick(){
             noticebtn.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View view) {
                     //  传入需要发送的广播
                     Intent intent = new Intent("com.example.broadcassttest.MY_BROADCAST");
                     sendBroadcast(intent);  // 将广播发送出去
                 }
             });
         }
}

参考学习:

https://blog.csdn.net/yangzhaomuma/article/details/49817337

https://blog.csdn.net/carson_ho/article/details/52973504

猜你喜欢

转载自blog.csdn.net/m0_37218227/article/details/82888990