irpas技术客

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

未知 7753

文章目录 前言一、SQLiteOpenHelper1. SQLite数据库介绍2. SQLiteOpenHelper类介绍 二、代码分析1. 创建 HistoryManager 对象HistoryManager 构造方法DBHelper 类HistoryManager. trimHistory 2. 保存扫码结果条目HistoryManager.addHistoryItem 3. 点击“历史记录”按钮CaptureActivity.onActivityResult 总结


前言

在前面的博客中,我们已经分析了 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; // 根据 activity 获取程序设置 SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity); // 是否 enable 历史记录 enableHistory = prefs.getBoolean(PreferencesActivity.KEY_ENABLE_HISTORY, true); }

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

DBHelper 类

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

DBHelper 构造方法

//在SQLiteOpenHelper的子类当中,必须有该构造函数 // 参数分别为:上下文对象、数据库名称、CursorFactory、数据库版本号 DBHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); }

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

@Override public void onCreate(SQLiteDatabase sqLiteDatabase) { // 执行SQL语句,创建一个表 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 方法来完成升级

//系统发现现有数据库版本不同,即会调用onUpgrade()方法 @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() { // 创建 DBHelper 实例对象 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")) { // 移动到 Zxing 项目所允许存留的最大条目数处 cursor.move(MAX_ITEMS); // 超过 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; } // 获取程序设置,判断是否允许保留重复的扫码条目。如果不允许则调用 deletePrevious 方法,将重复的旧的条目删除 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()); // 创建 DBHelper 对象 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 方法来对结果进行处理 基本流程如下: 在第十篇博客中,我们介绍了 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) { // 根据 HistoryManager 找到对应在数据库中的内容 HistoryItem historyItem = historyManager.buildHistoryItem(itemNumber); // 显示返回结果(因为数据库中没有存储 Bitmap,这里无法显示二维码图片) decodeOrStoreSavedBitmap(null, historyItem.getResult()); } } }

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

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

这里向 CaptureActivityHandler 发送消息来处理,之后的流程与之前在博客(六)中分析的类似,在 CaptureActivityHandler.handleMessage 中处理消息,再调用 CaptureActivity 的 handleMessage 方法,在页面显示结果。 这里显示的是数据库中存储的内容,没有二维码图片


总结

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


1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,会注明原创字样,如未注明都非原创,如有侵权请联系删除!;3.作者投稿可能会经我们编辑修改或补充;4.本站不提供任何储存功能只提供收集或者投稿人的网盘链接。

标签: #2021SCSDUSC #代码分析 #Android #数据库存储的相关知识