2021SC@SDUSC Zxing开源代码(十四)HistoryManager 代码分析

文章目录

前言

在前面的博客中,我们已经分析了 Zxing 安卓端的几大主要功能。本次博客将重点分析历史记录功能的相关代码,同时学习 Android 数据库存储的相关知识

一、SQLiteOpenHelper

1. SQLite数据库介绍

  • SQLite是Android内置的一个小型、关系型、属于文本型的数据库。
    Android提供了对 SQLite数据库的完全支持,应用程序中的任何类都可以通过名称来访问任何的数据库,但是应用程序之外的就不能访问。
  • Android中,通过SQLiteOpenHelper类来实现对SQLite数据库的操作。

2. SQLiteOpenHelper类介绍

  • 定义:SQLiteOpenHelper是一个辅助类
  • 作用:管理数据库(创建、增、删、改、查) 以及版本的控制
  • 使用过程:通过创建子类继承SQLiteOpenHelper类,实现它的一些方法来对数据库进行操作
  • SQLiteOpenHelper类的数据库操作方法介绍如下:

方法作用onCreate()创建数据库onUpgrade()升级数据库close()关闭所有打开的数据库对象execSQL()可进行增删改操作, 不能进行查询操作query()、rawQuery()查询数据库insert()插入数据delete()删除数据getWritableDatabase()创建或打开可以读/写的数据库getReadableDatabase()创建或打开可读的数据库

以上只是对 Android 数据库操作知识的基本介绍,具体使用将结合 Zxing 项目的代码来进行分析。

二、代码分析

在 Zxing 项目的主页面 CaptureActivity 中, 应用到历史记录的主要有以下几个地方:

1. 创建 HistoryManager 对象

在 CaptureActivity 的生命周期函数 onResume 中,就首先创建了一个 HistoryManager 对象,并且调用了 trimHistory 方法

    historyManager = new HistoryManager(this);
    historyManager.trimHistory();

HistoryManager 构造方法

  public HistoryManager(Activity activity) {
    this.activity = activity;

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);

    enableHistory = prefs.getBoolean(PreferencesActivity.KEY_ENABLE_HISTORY, true);
  }

可知在 HistoryManager 的构造方法中,传入了 CaptureActivity 的实例对象,同时获取程序设置,来判断是否允许使用历史记录功能

DBHelper 类

trimHistory 方法中,就涉及到了 SQLite 数据库的处理。
而可以操作 SQLite 数据库的 SQLiteOpenHelper 是一个抽象类,因此需要首先自己定义一个类对其进行继承,Zxing 项目在 history 包中定义了 DBHelper 类来继承 SQLiteOpenHelper

DBHelper 构造方法


  DBHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
  }

onCreate 方法
onCreate 方法在数据库第一次创建时被调用,这里在创建数据库的同时,也创建了一个表。可知表中存储了一次扫码结果的条目编号、文字、编码格式、展现内容、时间戳和细节信息几个字段。

  @Override
  public void onCreate(SQLiteDatabase sqLiteDatabase) {

    sqLiteDatabase.execSQL(
            "CREATE TABLE " + TABLE_NAME + " (" +
            ID_COL + " INTEGER PRIMARY KEY, " +
            TEXT_COL + " TEXT, " +
            FORMAT_COL + " TEXT, " +
            DISPLAY_COL + " TEXT, " +
            TIMESTAMP_COL + " INTEGER, " +
            DETAILS_COL + " TEXT);");
  }

onUpgrade 方法
当打开数据库时传入的版本号与当前的版本号不同时会调用该方法,可知这里首先删除了已有的数据,并且重新调用了 onCreate 方法来完成升级


  @Override
  public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
    sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
    onCreate(sqLiteDatabase);
  }

HistoryManager. trimHistory

  public void trimHistory() {

    SQLiteOpenHelper helper = new DBHelper(activity);

    try (SQLiteDatabase db = helper.getWritableDatabase();

     Cursor cursor = db.query(DBHelper.TABLE_NAME,
                                  ID_COL_PROJECTION,
                                  null, null, null, null,
                                  DBHelper.TIMESTAMP_COL + " DESC")) {

      cursor.move(MAX_ITEMS);

      while (cursor.moveToNext()) {
        String id = cursor.getString(0);
        Log.i(TAG, "Deleting scan history ID " + id);
        db.delete(DBHelper.TABLE_NAME, DBHelper.ID_COL + '=' + id, null);
      }
    } catch (SQLException sqle) {
      Log.w(TAG, sqle);
    }
  }

可知在 HistoryManager 的 trimHistory 方法中,主要完成的任务就是清理数据库中过多的历史记录条目。

这里注意一下获取数据库对象的流程:

  • 首先创建一个 SQLiteOpenHelper 对象
  • 然后调用该对象的 getWritableDatabase 或 getReadableDatabase 方法来获得SQLiteDatabase 对象
  • 在 getWritableDatabase 和 getReadableDatabase 方法中,会判断指定的数据库是否存在,不存在则调用 SQLiteOpenHelper.onCreate 方法来创建数据库

2. 保存扫码结果条目

在前面的博客中,我们已经分析了整个扫码处理的流程,其中 CaptureActivity 的 handleDecode 方法,就对扫码得到的结果进行了各种处理,有代码:

historyManager.addHistoryItem(rawResult, resultHandler);

下面我们看一下 HistoryManager 的这个方法

HistoryManager.addHistoryItem

  public void addHistoryItem(Result result, ResultHandler handler) {

    if (!activity.getIntent().getBooleanExtra(Intents.Scan.SAVE_HISTORY, true) ||
        handler.areContentsSecure() || !enableHistory) {
      return;
    }

    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
    if (!prefs.getBoolean(PreferencesActivity.KEY_REMEMBER_DUPLICATES, false)) {
      deletePrevious(result.getText());
    }

    ContentValues values = new ContentValues();
    values.put(DBHelper.TEXT_COL, result.getText());
    values.put(DBHelper.FORMAT_COL, result.getBarcodeFormat().toString());
    values.put(DBHelper.DISPLAY_COL, handler.getDisplayContents().toString());
    values.put(DBHelper.TIMESTAMP_COL, System.currentTimeMillis());

    SQLiteOpenHelper helper = new DBHelper(activity);
    try (SQLiteDatabase db = helper.getWritableDatabase()) {

      db.insert(DBHelper.TABLE_NAME, DBHelper.TIMESTAMP_COL, values);
    } catch (SQLException sqle) {
      Log.w(TAG, sqle);
    }
  }

这样就成功地保存了扫码结果到数据库

3. 点击”历史记录”按钮

这里类似前面分析过的 ShareActivity 代码部分的操作
在 CaptureAcitivity 的 onOptionsItemSelected 方法中,也对点击”历史记录”按钮进行了响应

      case R.id.menu_history:
        intent.setClassName(this, HistoryActivity.class.getName());
        startActivityForResult(intent, HISTORY_REQUEST_CODE);
        break;

其使用了意图跳转方法,也就是说在这里会跳转到 HistoryActivity 的界面,而在 HistoryActivity 中处理完毕后,会回调到 CaptureActivity 的 onActivityResult 方法来对结果进行处理
基本流程如下:

2021SC@SDUSC Zxing开源代码(十四)HistoryManager 代码分析
在第十篇博客中,我们介绍了 Android Adapter 体系,Adapter 完成对数据和界面的适配。一些不能直接赋值到界面上的数据类型,就需要靠适配器来展示到页面
  • HistoryActivity 页面中的条目就是通过继承了 ArrayAdapter 的 HistoryItemAdapter 来完成的适配显示
  • 在页面初始构造时,除了加载布局文件、设置适配器,还调用了 HistoryManager 的
    buildHistoryItems() 方法,来获取所有的历史记录
  • 最终在点击历史记录条目时,跳转回了 CaptureActivity 来处理

CaptureActivity.onActivityResult

  public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    if (resultCode == RESULT_OK && requestCode == HISTORY_REQUEST_CODE && historyManager != null) {

      int itemNumber = intent.getIntExtra(Intents.History.ITEM_NUMBER, -1);
      if (itemNumber >= 0) {

        HistoryItem historyItem = historyManager.buildHistoryItem(itemNumber);

        decodeOrStoreSavedBitmap(null, historyItem.getResult());
      }
    }
  }

可知在方法中,根据返回点击的历史条目号,来查询数据库找到了对应的存储内容,而后调用 decodeOrStoreSavedBitmap 方法显示返回结果
而在 decodeOrStoreSavedBitmap 中有:

    Message message = Message.obtain(handler, R.id.decode_succeeded, savedResultToShow);
    handler.sendMessage(message);

这里向 CaptureActivityHandler 发送消息来处理,之后的流程与之前在博客(六)中分析的类似,在 CaptureActivityHandler.handleMessage 中处理消息,再调用 CaptureActivity 的 handleMessage 方法,在页面显示结果。

2021SC@SDUSC Zxing开源代码(十四)HistoryManager 代码分析
这里显示的是数据库中存储的内容,没有二维码图片

总结

通过本次代码分析,理清了在 Zxing 项目中历史记录的处理流程,同时学习了 Android 数据存储的相关知识

Original: https://blog.csdn.net/Dream_Glow/article/details/121864693
Author: Winter-tea
Title: 2021SC@SDUSC Zxing开源代码(十四)HistoryManager 代码分析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/816057/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球