《第一行代码》5 广播接收器BroadcastReceiver

个人笔记,仅供参考

《第一行代码》5 广播接收器BroadcastReceiver_第1张图片
目录

1 广播简介

  • Android提供了一整套完整的API,允许应用程序自由地接收和发送广播

Android中的广播类型主要分两种:
(1)标准广播:
异步、效率高、无先后顺序之分、无法被截取,同一时刻所有的广播接收器会同时收到这条广播
(2)有序广播:
同步、有先后顺序之分、优先级高的先收到,同一时刻只有一个广播接收器收到,且需要执行完逻辑后,再传递给下一个广播接收器,允许截断,那么下一个接收器将无法收到广播

2 接收系统广播

以监听网络为例,新建项目BroadcastDemo

public class MainActivity extends AppCompatActivity {

    private IntentFilter intentFilter;
    private NetWorkChangeReceiver netWorkChangeReceiver;

    @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(MainActivity.this, "网络有变化", Toast.LENGTH_SHORT).show();
        }
    }
}
  • 新建内部类NetWorkChangeReceiver 继承自BroadcastReceiver,并重写onReceive方法,当收到广播后,我们让它弹出一个Toast
  • 新建一个IntentFilter实例,并制定它要监听的ACTION为"android.net.conn.CONNECTIVITY_CHANGE",因为当网络条件发生变化的时候,系统会内置发出这一条广播
  • 新建NetWorkChangeReceiver实例
  • 最后调用registerReceiver方法注册广播接收器,当网络发生变化的时候,我们的接收器会收到广播,并执行onReceive方法

广播接收器的注册方式分为动态注册静态注册,动态注册是在代码中注册,静态注册是在配置文件AndroidManifest中注册。

  • 而动态注册的广播接收器都需要记得在销毁界面的时候取消注册,因此我们在onDestroy方法里调用了unregisterReceiver方法。

当我们切换网络开关的时候,运行效果:


《第一行代码》5 广播接收器BroadcastReceiver_第2张图片

当然,我们可以再进一步优化一下,明确地显示当前是否有网络

  • 我们修改一下onReceive方法里的代码
    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, "网络已开启", Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(context, "网络已关闭", Toast.LENGTH_SHORT).show();
            }
        }
    }

  • 通过getSystemService拿到ConnectivityManager ,这是一个系统服务类,专门用来管理网络
  • 调用getActiveNetworkInfo拿到NetworkInfo实例,并通过isAvailable方法来判断当前网络的具体状态

当我们再次切换网络开关的时候,会弹出对应Toast提示,运行效果:


《第一行代码》5 广播接收器BroadcastReceiver_第3张图片

由于我们使用到了网络,因此记得在配置文件AndroidManifest中加入权限


注意:

我们之前的广播接收器中onReceive方法都只是简单的弹出Toast,当真正在项目中用到的时候,我们可以编写自己需要的逻辑
需要注意的是:
不要在onReceive方法中添加过多的逻辑和耗时操作
不允许开启线程
广播接收器更多扮演的是一种打开程序其他组件的角色,如创建一条通知栏、启动一个服务等等。

3 发送自定义广播

3-1 发送标准广播

  • 首先新建一个广播接收器,用于接收我们等下要发送的广播
public class MyBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "收到来自MyBroadcastReceiver的广播", Toast.LENGTH_SHORT).show();
    }
}
  • 然后注册广播接收器,上一节我们用的是动态注册,这里我们用静态注册的方式,打开配置文件AndroidManifest,在 内声明我们的BroadcastReceiver;里面指定intentFilter的Action,这个值可以自定义,这里我们就用包名和一个大写字符。代表这个接收器只接受含有这条信息的广播。
        
            
                
            
  • 接着,我们在主界面MainActivity里加入一个button作为发送广播的触发点,点击后利用intent指定我们要发送的广播的值,最后调用sendBroadcast方法,就发送了一条标准的广播
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button1 = findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcastdemo.MY_BROADCAST");
                sendBroadcast(intent);
            }
        });

    }
}

可以看到此时我们的广播接收器已经接收到了发出的广播,运行效果:


《第一行代码》5 广播接收器BroadcastReceiver_第4张图片

3-2 发送有序广播

广播可以跨进程,也就是说应用程序发出的广播,其他应用程序可以收到

我们再新建一个BroadcastDemo2项目,并同样新建另一个广播接收器AnotherBroadcastReceiver

public class AnotherBroadcastReceiver extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "收到来自AnotherBroadcastReceiver的广播", Toast.LENGTH_SHORT).show();
    }
}
  • 而且同样指定它监听的action为"com.example.broadcastdemo.MY_BROADCAST"
        
            
                
            
  • 当我们点击第一个Demo中的按钮时,此时第二个Demo中的广播接收器AnotherBroadcastReceiver同样能够接收到广播(此处图略)
    这足以说明广播可以跨进程。

我们再来看一下怎么发送有序广播?

  • 很简单,只需要更改一行代码即可,sendOrderedBroadcast第二个字符是与权限相关的,这里设置成null即可
                Intent intent = new Intent("com.example.broadcastdemo.MY_BROADCAST");
//                sendBroadcast(intent);
                sendOrderedBroadcast(intent,null);

既然是有序的广播,那么怎么知道谁先收到广播呢?

  • 我们可以给广播接收器设置优先级,比如给AnotherBroadcastReceiver设置
    android:priority="100",以保证它优先收到广播
        
            
                
            
        

那么优先收到后,又如何截断呢?

  • 只需要在AnotherBroadcastReceiver的onReceive方法里调用abortBroadcast即可
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "收到来自MyBroadcastReceiver的广播", Toast.LENGTH_SHORT).show();\
        abortBroadcast();
    }
  • 此时,若再次点击发送广播,AnotherBroadcastReceiver会优先收到,并采取截断,广播则不会再继续传递下去,MyBroadcastReceiver将收不到

4 本地广播

前面使用的广播都属于全局广播,也就是说发出的广播可以被其他任何应用程序收到,也同样可以接收到任何应用程序的广播,这样就容易引起安全性问题。我们发出的广播可能会被截取,又或者收到各种垃圾广播。

为了解决这个问题,Android拥有一套自带的本地广播机制。
发出的广播,只能在本程序内部进行传递
而广播接收器,只能接收来自本程序的广播。

直接看代码:

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        localBroadcastManager = LocalBroadcastManager.getInstance(this);
        Button button1 = findViewById(R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent("com.example.broadcastdemo.LOCAL_BROADCAST");
                localBroadcastManager.sendBroadcast(intent);//发送本地广播
            }
        });
        intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcastdemo.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, "收到本地广播", Toast.LENGTH_SHORT).show();
        }
    }
}
  • 本地广播主要使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送和接收的方法,我们需要首先获取它的实例localBroadcastManager
  • 首先新建广播接收器LocalReceiver,用于接收本地广播
  • 使用intentFilter指定其Action,而此时动态注册,采用的是localBroadcastManager调用registerReceiver,代表注册为本地广播接收器
  • 发送本地广播,只需要由localBroadcastManager调用sendBroadcast即可
  • 最后别忘了取消注册

运行效果:


《第一行代码》5 广播接收器BroadcastReceiver_第5张图片

5 广播实践

这里简单讲讲目前我工作中遇到过的常见使用情况:
一般发送广播可以用于不那么紧急的UI更新操作

比如:
活动A——> 活动B ——> 活动C

  • 我在C界面给某个用户点了赞

活动A<—— 活动B <—— 活动C

  • 当我一路回退到活动A的时候,此时活动A中此用户的状态肯定需要变为已赞对吧?
  • 而每次回退都刷新发请求是不合适的
  • 因此可以在C界面的时候,就简单发送一个广播,当活动A的onResume接收到的时候,改变该用户的状态

你可能感兴趣的:(《第一行代码》5 广播接收器BroadcastReceiver)