第一行代码学习笔记第五章——详解广播机制

知识点目录

知识点回顾

在网络通信里,在一个IP网络范围中,最大的IP地址是被保留作为广播地址来使用的。例如:某个网络的IP范围是192.168.0.XXX,子网掩码是255.255.255.0,那么这个网络的广播地址就是192.168.0.255。广播数据包会被发送到同一网络上的所有端口,在该网络中的每台主机都会接收到这个广播。

为了方便进行系统级别的消息通知,Android也引入了一套类似的广播消息机制。

5.1 广播机制

Android中的广播主要分为两种类型:标准广播和有序广播。

标准广播

完全异步执行!!!在广播发出后,所有的广播接收器几乎在同一时刻接受到这条广播信息。

特点:广播效率高、没有任何先后顺序、无法被拦截

有序广播

同步执行!!!广播发出后,同一时刻只会有一个广播接收器收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。

特点:广播接收器有先后顺序,优先级高的广播接收器先收到广播消息,可以被优先级高的广播接收器拦截。

5.2 接收系统广播

Android内置了很多系统级别的广播:

  • 开机广播

  • 电池电量发生变化广播

  • 时间或时区发生改变广播

  • 等等。。。

5.2.1 动态注册监听网络变化

广播接收器可以自由注册自己感兴趣的广播进行注册。注册的方式有两种:

  • 代码中注册(也称为动态注册)

  • AndroidManifest.xml中注册(也称为静态注册)

动态注册监听网络变化的步骤如下:

  • 创建一个广播接收器,继承BroadcastReceiver,重写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, "network is availabe", Toast.LENGTH_SHORT).show();
              } else {
                  Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
              }
          }
      }
    

当接收到广播时,onReceive()方法就会执行,所以具体的逻辑就是在这个方法里处理。

  • 在代码中动态注册(一般是在Activity的onCreate方法中注册)

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

备注:访问系统的网络状态需要声明权限

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  • 取消注册

动态注册的广播接收器需要取消注册,一般是在onDestroy()中取消

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

效果图:

通过命令发送网络改变的广播:

am broadcast -a android.net.com.CONNECTIVITY_CHANGE

在有网和没有网络时的效果如下图所示:

5.2.2 静态注册实现开机广播

动态注册的广播接收器可以自由的注册和注销,但有个缺点:必须在程序启动后才能接收到广播,因为注册的逻辑是写在onCreate()方法中。

静态广播可以在程序未启动的时候就能接收到广播。

Android Studio提供了快捷方式来创建一个广播接收器:右击com.example.broadcasttest包—>New—>Other—>Broadcast Receiver,

Exported属性表示是否允许这个广播器接收本程序之外的广播。

Enabled属性表示是否启用这个广播接收器。

Source Language可以选择用Java或Kotlin。

静态注册监听开机广播的步骤如下:

  • 通过Android Studio快捷创建广播接收器,并修改onReceive()中的逻辑

      public class BootCompleteReceiver extends BroadcastReceiver {
      
          @Override
          public void onReceive(Context context, Intent intent) {
              Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show();
          }
      }
    
  • 在AndroidManifest.xml中注册

      <receiver
          android:name=".BootCompleteReceiver"
          android:enabled="true"
          android:exported="true">
          <intent-filter>
              <action android:name="android.intent.action.BOOT_COMPLETED"/>
          </intent-filter>
      </receiver>
    
  • 添加监听系统开机广播的权限

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

效果图:

通过命令发送开机广播:

am broadcast -a android.intent.action.BOOT_COMPLETED

命令发送出去后的效果如下图所示:

注意:
不要在onReceive()方法中添加过多的逻辑或者进行任何耗时操作,因为广播接收器中不允许开启线程,当onReceive()方法运行了较长的时间而没有结束时,程序就会报错。

5.3 发送自定义广播

广播主要分为标准广播和有序广播,下面分别来实践下具体实现。

5.3.1 发送标准广播

发送标准广播的一般步骤如下:

  • 定义个广播接收器

      public class MyBroadcastReceiver extends BroadcastReceiver {
      
          @Override
          public void onReceive(Context context, Intent intent) {
              Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
          }
      }
    
  • 到AndroidManifest.xml中定义广播接收器接收的action

      <manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="example.broadcasttest">
      	<application
    
      		......
    
              <receiver
                  android:name=".MyBroadcastReceiver"
                  android:enabled="true"
                  android:exported="true">
                  <intent-filter>
                      <action android:name="com.example.broadcasttest.MY_BROADCAST"/>
                  </intent-filter>
              </receiver>
    
      		......
    
          </application>
      
      </manifest>
    
  • 定义一个发送广播的触发点,并调用sendBroadcast()发送广播

      Button button = (Button) findViewById(R.id.button);
      button.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Intent intent = new Intent("com.example.broadcasttest.MY_BROADCASTT");
              sendBroadcast(intent);
          }
      });
    

效果图:

备注:由于广播是使用Intent进行传递的,所以还可以在Intent中携带一些数据传递给广播接收器。

5.3.2 发送有序广播

发送有序广播的步骤跟上面发送标准广播的步骤一样,只是调用的方法不一样。

  • 使用sendOrderedBroadcast(intent,null)方法发送有序广播

参数一:intent的对象

参数二:与权限相关的字符串,一般传入null就行

  • 通过android.priority设置广播接收器的优先级

      <receiver
          android:name=".MyBroadcastReceiver"
          android:enabled="true"
          android:exported="true">
          <intent-filter android:priority="100">
              <action android:name="com.example.broadcasttest.MY_BROADCASTT"/>
          </intent-filter>
      </receiver>
    
  • 可以调用abortBroadcast()方法截断广播

5.4 使用本地广播

广播是可以跨进程通信的,那么携带的数据就有可能被其他程序截获,存在一定的安全性问题。因此Android引入了一套本地广播机制。主要是使用一个LocalBroadcastManager来对广播进行管理。

主要用法如下:

public class MainActivity extends AppCompatActivity {


    private LocalBroadcastManager mLocalBroadcastManager;
    private LocalReceiver mLocalReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);//获取实例
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCASTT");
                mLocalBroadcastManager.sendBroadcast(intent);//发送本地广播
            }
        });
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCASTT");
        mLocalReceiver = new LocalReceiver();
        mLocalBroadcastManager.registerReceiver(mLocalReceiver,intentFilter);//注册本地广播监听器
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLocalBroadcastManager.unregisterReceiver(mLocalReceiver);//注销本地广播监听器
    }

    class LocalReceiver extends BroadcastReceiver {

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

本地广播的使用其实跟动态注册广播是一样的,只是多了一个LocalBroadcastManager对广播的发送、注册、注销进行了管理。

本地广播无法通过静态注册的方式来接收的,因为静态注册主要就是在程序未启动时也能接收到广播,而发送本地广播时,程序肯定已经启动了。

本地广播的优势

  • 发送的广播不会离开自己的程序,所以数据不会泄露

  • 其它程序无法将广播发送到我们程序的内部,所以不会有安全漏洞隐患

  • 发送本地广播比发送系统全局广播更加高效

5.5 广播的最佳实践——实现强制下线功能

强制下线功能需求:先关闭所有的活动,然后回到登录界面。

代码已上传到我的github上,需要的朋友可以点击如下链接查看:

广播的最佳实践——实现强制下线功能

运行效果图:

5.6 Git时间——初识版本控制工具

Git是一个开源的分布式版本控制工具,开发者是Linux操作系统的作者Linus Torvalds。

5.6.1 安装Git

Ubuntu系统

安装命令如下:

sudo apt-get install git-core

Windows系统

下载地址:

点击进入Git下载地址

点击Download按钮可以开始下载,下载完成后双击安装包进行安装,之后一直点击“下一步”就可以完成安装了。

5.6.2 创建代码仓库

Git可以在图形上进行操作,但我们应该掌握Git的各种命令,因为Git命令在不同的操作系统上都是通用的。

Linux系统是打开shell界面,Windows是打开Git Bash。

配置身份

首先应该配置身份,这样在提交代码的时候Git就可以知道谁提交的,具体命令如下

git config --global user.name salmonzhang

git config --global user.email [email protected]

这样名字和邮箱就已经配置好了。

查看git用户名和邮箱的命令是

git config --global user.name

git config --global user.email

创建代码仓库的命令是:

git init

在项目的根目录下执行git init命令后会生成一个隐藏的.git文件夹,该文件夹主要用来记录本地所有的Git操作。如果要删除本地仓库,也只需要删除这个文件夹就行了。

5.6.3 提交本地代码

主要用到的是:

git add 和 git commit

add后面可以是文件名或者目录,commit后面通过-m参数来加上提交的描述信息。

5.7 小结与点评

本章主要学习了Android的广播机制,掌握了接收广播、发送自定义广播和本地广播的使用方法。还学习了一点Git的基本知识。

非常感谢您的耐心阅读,希望我的文章对您有帮助。欢迎点评、转发或分享给您的朋友或技术群。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章