文章目录
- 前言
- 一、SQLiteOpenHelper
* - 1. SQLite数据库介绍
- 2. SQLiteOpenHelper类介绍
- 二、代码分析
* - 1. 创建 HistoryManager 对象
– - 2. 保存扫码结果条目
– - 3. 点击”历史记录”按钮
– - 总结
前言
在前面的博客中,我们已经分析了 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 方法来对结果进行处理
基本流程如下:
在第十篇博客中,我们介绍了 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 方法,在页面显示结果。
这里显示的是数据库中存储的内容,没有二维码图片
总结
通过本次代码分析,理清了在 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/
转载文章受原作者版权保护。转载请注明原作者出处!