2021SC@SDUSC Zxing开源代码(十五)辅助功能代码分析


前言

在前面的博客中,我们已经分析完了 Zxing 项目的扫码、编码、分享、历史记录等主要功能所涉及的代码。本次博客将分析剩余的一些辅助功能


一、活动计时器 InactivityTimer

在 Zxing 项目中,因为涉及到了调用摄像头等操作,如果程序一直处于运行状态,则是对手机电量的一种耗费。因此设置了机制,如果一段时间不进行操作,会关闭程序,其主要实现逻辑就在类 InactivityTimer

活动计时器 InactitityTimer 的逻辑与主活动 CaptureActivity 的生命周期函数息息相关,如下图:
在这里插入图片描述

InactivityTimer 构造方法

在 CaptureActivity 启动后,就创建了 InactivityTimer 的实例对象,并将此时的 CaptureActivity 对象作为参数传入,首先看一下 InactivityTimer 的构造方法

  InactivityTimer(Activity activity) {
    this.activity = activity;
    powerStatusReceiver = new PowerStatusReceiver();
    registered = false;
    onActivity();
  }

这里涉及到了一个 InactivityTimer 的内部类 PowerStatusReceiver ,继承了 BroadcastReceiver 类

BroadcastReceiver,也就是广播接收者,用来接收来自系统和应用的广播。其可以接收到系统开机完成的广播、系统电量不足的广播、系统收到短信的广播等等。在接收到广播后程序就可以进行相应的处理操作

当收到注册的广播时,onReceive方法就会被调用,其中参数context是上下文,Intent 就是广播携带的数据

  private final class PowerStatusReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      // 如果系统发出电池变化广播
      if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
        // 判断是否在充电(0表示正在充电)
        boolean onBatteryNow = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) <= 0;
        if (onBatteryNow) { // 未在充电,则开启监听任务
          InactivityTimer.this.onActivity();
        } else { // 如果在充电,则取消任务
          InactivityTimer.this.cancel();
        }
      }
    }
  }

InactivityTimer 的作用就是为了防止程序一直处于运行状态,耗费电量,因此这里就通过获取系统广播,来判断此时设备是否处于充电状态。如果设备此时在充电,那么就不必担心电量的耗费,可以直接取消 InactivityTimer ,否则的话就需要开启 InactivityTimer 的计时监听任务。

在 InactivityTimer 的构造方法中,在创建了一个电量状态接收者类 PowerStatusReceiver 后(此时尚未对其进行注册),调用了 onActivity 方法,下面看一下这个方法的代码

InactivityTimer.onActivity

onActivity 方法中,创建了一个 InactivityTimer 的内部类 InactivityAsyncTask 的实例对象

InactivityAsyncTask 继承了 AsyncTask 类,我们在博客(九)中对其有过介绍,AsyncTask 是由 Android 封装的一个轻量级异步类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程
而 doInBackground 就是该类的一个核心方法,用以处理子线程的后台任务

  private final class InactivityAsyncTask extends AsyncTask<Object,Object,Object> {
    @Override
    protected Object doInBackground(Object... objects) {
      try {
        // 线程陷入睡眠
        Thread.sleep(INACTIVITY_DELAY_MS);
        Log.i(TAG, "Finishing activity due to inactivity");
        // 因为一直没有进行操作结束活动(注意这里的 activity 是传递进来的 CaptureActivity 实例对象)
        activity.finish();
      } catch (InterruptedException e) {
        // continue without killing
      }
      return null;
    }
  }

由此便可以得出,在 InactivityTimer 中,专门有一个子线程来一直执行着后台任务,在休眠指定时间后,如果一直没有对程序进行操作,则直接结束主活动。

下面看一下 onActivity 的代码:

  synchronized void onActivity() {
    // 终止现存的 inactivityTask
    cancel();
    // 创建一个新的 inactivityTask 对象
    inactivityTask = new InactivityAsyncTask();
    try {
      // 使 inactivityTask 开始执行任务
      inactivityTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    } catch (RejectedExecutionException ree) {
      Log.w(TAG, "Couldn't schedule inactivity task; ignoring"); 
    }
  }

这里需要注意的是,在 onActivity 的一开始调用了 cancel() 方法,首先终止了现存的 inactivityTask,而后再对其创建新的实例对象,也就是说,每次调用 onActivity 方法,都会重新开启计时任务,重新进行计时

InactivityTimer 的其他方法

  • onResume:我们注意到,在前面 InactivityTimer 的构造方法中,只是创建了广播接收者对象,并没有对其进行注册。那么 powerStatusReceiver 的注册接收就放到了 onResume 方法: activity.registerReceiver(powerStatusReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED))。在注册完广播接收器后,调用 onActivity 函数,开启计时任务
  • onPause:若主活动 CaptureActivity 被其他 Activity 覆盖或者锁屏,就会执行CaptureActivity.onPause,其中调用了 InactivityTimer.onPause,其主要任务就是停止当前的计时任务,并且通过 activity.unregisterReceiver(powerStatusReceiver),取消注册广播接收器
  • shutdown:调用 cancel 方法,终止后台计时任务

二、程序设置页面 PreferencesActivity

在 Android 中,有一个专门用来实现程序设置界面及参数存储的 Activity——PreferencesActivity,官方建议 PreferenceActivity 与 PreferenceFragment 结合使用,其中 PreferenceActivity 负责加载选项配置列表的布局文件,PreferenceFragment 负责加载选项配置的布局文件

Fragment是一种可以嵌入在活动中的UI片段,能够让程序更加合理和充分地利用大屏幕的空间,可以将其看成一个小型Activity,又称作Activity片段。
Fragment不能够单独使用,需要嵌套在Activity中使用,其生命周期也受到宿主Activity的生命周期的影响

Zxing 项目的程序设置页面如下:
在这里插入图片描述

PreferenceActivity

在 PreferenceActivity 的代码中,只重写了生命周期函数 onCreate

  @Override
  protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    getFragmentManager().beginTransaction().replace(android.R.id.content, new PreferencesFragment()).commit();
  }

这里直接创建了一个 PreferencesFragment 对象,并将其覆盖在了 PreferenceActivity 之上

PreferencesFragment

public final class PreferencesFragment 
    extends PreferenceFragment 
    implements SharedPreferences.OnSharedPreferenceChangeListener

首先注意到,PreferencesFragment 继承了 PreferenceFragment 类,同时实现了 SharedPreferences.OnSharedPreferenceChangeListener 接口,以监听设置参数的改变

SharedPreferences 是一个轻量级的存储类,采用键值对的方式存储,适用于保存软件配置参数。利用 SharedPreferences 可以实现应用内数据的共享,因此在 PreferencesFragment 中完成某项设置后,其余的类就可以直接通过 PreferenceManager.getDefaultSharedPreferences(context) 来获取保存的设置

PreferencesFragment.onCreate

  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    // 加载 xml布局文件
    addPreferencesFromResource(R.xml.preferences);
    // 创建 PreferenceScreen 对象
    PreferenceScreen preferences = getPreferenceScreen();
    //注册SharedPreference设置监听器
    preferences.getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
...

在 onCreate 方法中,首先做了三件事:

  • 加载 xml 布局文件
  • 创建一个 PreferenceScreen 的对象作为 PreferencesFragment 基本布局的根容器
  • 为 SharedPreference 的改变设置监听器

而后的代码是对设置勾选框(CheckBoxPreference)的一些处理:

    // 搜索 SharedPreference,根据key找到value(CheckBoxPreference对象),放到checkBoxPrefs数组中
    checkBoxPrefs = findDecodePrefs(preferences,
                                    PreferencesActivity.KEY_DECODE_1D_PRODUCT,
                                    PreferencesActivity.KEY_DECODE_1D_INDUSTRIAL,
                                    PreferencesActivity.KEY_DECODE_QR,
                                    PreferencesActivity.KEY_DECODE_DATA_MATRIX,
                                    PreferencesActivity.KEY_DECODE_AZTEC,
                                    PreferencesActivity.KEY_DECODE_PDF417);
    // 更新勾选设置
    disableLastCheckedPref();
  }

CheckBoxPreference 也是 Android 中,与设置相关的一个类。其复选框选中为 true,取消选中为 false ,值会以boolean的形式储存在SharedPreferences中

PreferencesFragment.disableLastCheckedPref

  private void disableLastCheckedPref() {
    Collection<CheckBoxPreference> checked = new ArrayList<>(checkBoxPrefs.length);
    // 遍历 CheckBoxPreference 设置数组中的每一项,判断是否勾选
    for (CheckBoxPreference pref : checkBoxPrefs) {
      // 如果勾选上了,就加到 checked 数组中
      if (pref.isChecked()) {
        checked.add(pref);
      }
    }
    // 如果没有被勾选中的设置时,disable为true
    boolean disable = checked.size() <= 1;
    for (CheckBoxPreference pref : checkBoxPrefs) {
      // 使 checked 数组中的设置生效
      pref.setEnabled(!(disable && checked.contains(pref)));
    }
  }

可见在该方法中,就是获取了所有勾选中的设置,并且使其生效

在 PreferencesFragment 中重写的 onSharedPreferenceChanged 方法,就是直接调用了该函数,来更新用户选择的设置


总结

通过此次代码分析,对 Zxing 项目中的辅助功能有了更深的了解。同时学习了 Android 中 Preference 的相关处理操作

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值