You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomi/src/gtask/data/SqlData.java

259 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 版权所有 (c) 2010-2011MiCode 开源社区 (www.micode.net)
* 根据 Apache 许可证 2.0 版本("许可证")授权;
* 除非符合许可证的规定,否则不得使用本文件。
* 您可以从以下网址获取许可证副本:
* http://www.apache.org/licenses/LICENSE-2.0
* 除非适用法律要求或书面同意,本软件按"原样"分发,
* 没有任何明示或暗示的保证或条件。
* 详见许可证中规定的权限和限制。
* 这是一份标准的Apache许可证2.0版本的开源声明)
*/
// 定义当前类所在的包路径
package net.micode.notes.gtask.data;
// 导入Android内容提供者相关类
import android.content.ContentResolver; // 内容解析器用于访问ContentProvider
import android.content.ContentUris; // 用于构建带有ID的URI
import android.content.ContentValues; // 键值对存储,用于数据库操作
import android.content.Context; // 应用上下文
import android.database.Cursor; // 数据库查询结果集
import android.net.Uri; // 通用资源标识符
import android.os.Build; // 获取Android版本信息
import android.util.Log; // 日志工具
// 导入AndroidX注解版本检查
import androidx.annotation.RequiresApi;
// 导入笔记应用数据相关常量
import net.micode.notes.data.Notes; // 笔记数据常量
import net.micode.notes.data.Notes.DataColumns; // 数据列名常量
import net.micode.notes.data.Notes.DataConstants; // 数据相关常量
import net.micode.notes.data.Notes.NoteColumns; // 笔记列名常量
import net.micode.notes.data.NotesDatabaseHelper.TABLE; // 数据库表名
// 导入同步异常类
import net.micode.notes.gtask.exception.ActionFailureException;
// 导入JSON处理相关类
import org.json.JSONException; // JSON异常
import org.json.JSONObject; // JSON对象
// 导入Java工具类
import java.util.Objects; // 对象工具类
/**
* SqlData类 - 处理笔记数据的SQLite数据库操作
* 功能:
* 1. 封装笔记数据的增删改查操作
* 2. 管理本地数据与JSON格式的相互转换
* 3. 处理数据版本控制
*/
public class SqlData {
// 日志标签
private static final String TAG = SqlData.class.getSimpleName();
// 无效ID常量
private static final int INVALID_ID = -99999;
// 数据查询的列投影(指定需要查询的列)
public static final String[] PROJECTION_DATA = new String[] {
DataColumns.ID, // 数据ID
DataColumns.MIME_TYPE, // MIME类型
DataColumns.CONTENT, // 内容
DataColumns.DATA1, // 扩展数据1
DataColumns.DATA3 // 扩展数据3
};
// 列索引常量
public static final int DATA_ID_COLUMN = 0; // ID列索引
public static final int DATA_MIME_TYPE_COLUMN = 1; // MIME类型列索引
public static final int DATA_CONTENT_COLUMN = 2; // 内容列索引
public static final int DATA_CONTENT_DATA_1_COLUMN = 3; // 扩展数据1列索引
public static final int DATA_CONTENT_DATA_3_COLUMN = 4; // 扩展数据3列索引
// 内容解析器实例
private final ContentResolver mContentResolver;
// 是否为新创建数据的标志
private boolean mIsCreate;
// 数据字段
private long mDataId; // 数据ID
private String mDataMimeType; // MIME类型
private String mDataContent; // 内容
private long mDataContentData1; // 扩展数据1长整型
private String mDataContentData3; // 扩展数据3字符串
// 存储有变动的数据值(用于增量更新)
private final ContentValues mDiffDataValues;
/**
* 构造函数(用于创建新数据)
* @param context 应用上下文
*/
public SqlData(Context context) {
mContentResolver = context.getContentResolver();
mIsCreate = true; // 标记为新创建
mDataId = INVALID_ID; // 初始化无效ID
mDataMimeType = DataConstants.NOTE; // 默认MIME类型
mDataContent = ""; // 空内容
mDataContentData1 = 0; // 默认扩展数据1
mDataContentData3 = ""; // 空扩展数据3
mDiffDataValues = new ContentValues(); // 初始化变更集合
}
/**
* 构造函数基于Cursor加载已有数据
* @param context 应用上下文
* @param c 数据库Cursor对象
*/
public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver();
mIsCreate = false; // 标记为已存在数据
loadFromCursor(c); // 从Cursor加载数据
mDiffDataValues = new ContentValues(); // 初始化变更集合
}
/**
* 从Cursor加载数据
* @param c 数据库Cursor对象
*/
private void loadFromCursor(Cursor c) {
mDataId = c.getLong(DATA_ID_COLUMN);
mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);
mDataContent = c.getString(DATA_CONTENT_COLUMN);
mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);
mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);
}
/**
* 设置内容从JSON对象
* @param js 包含数据的JSON对象
* @throws JSONException JSON解析异常
*/
public void setContent(JSONObject js) throws JSONException {
// 处理数据ID
long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;
if (mIsCreate || mDataId != dataId) {
mDiffDataValues.put(DataColumns.ID, dataId);
}
mDataId = dataId;
// 处理MIME类型
String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE)
: DataConstants.NOTE;
if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {
mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);
}
mDataMimeType = dataMimeType;
// 处理内容
String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";
if (mIsCreate || !mDataContent.equals(dataContent)) {
mDiffDataValues.put(DataColumns.CONTENT, dataContent);
}
mDataContent = dataContent;
// 处理扩展数据1
long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;
if (mIsCreate || mDataContentData1 != dataContentData1) {
mDiffDataValues.put(DataColumns.DATA1, dataContentData1);
}
mDataContentData1 = dataContentData1;
// 处理扩展数据3
String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";
if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {
mDiffDataValues.put(DataColumns.DATA3, dataContentData3);
}
mDataContentData3 = dataContentData3;
}
/**
* 获取内容转换为JSON对象
* @return 包含数据的JSON对象
* @throws JSONException JSON构造异常
*/
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
// 构建JSON对象
JSONObject js = new JSONObject();
js.put(DataColumns.ID, mDataId);
js.put(DataColumns.MIME_TYPE, mDataMimeType);
js.put(DataColumns.CONTENT, mDataContent);
js.put(DataColumns.DATA1, mDataContentData1);
js.put(DataColumns.DATA3, mDataContentData3);
return js;
}
/**
* 提交数据到数据库
* @param noteId 关联的笔记ID
* @param validateVersion 是否验证版本
* @param version 版本号当validateVersion为true时使用
*/
@RequiresApi(api = Build.VERSION_CODES.R)
public void commit(long noteId, boolean validateVersion, long version) {
// 处理新建数据的情况
if (mIsCreate) {
// 如果ID无效且有ID变更移除无效ID
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID);
}
// 设置关联笔记ID
mDiffDataValues.put(DataColumns.NOTE_ID, noteId);
// 插入新数据
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
// 从返回的URI中解析出新数据的ID
mDataId = Long.parseLong(Objects.requireNonNull(uri).getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e);
throw new ActionFailureException("create note failed");
}
} else {
// 处理更新已有数据的情况
if (!mDiffDataValues.isEmpty()) {
int result;
if (!validateVersion) {
// 不验证版本的普通更新
result = mContentResolver.update(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mDataId),
mDiffDataValues,
null,
null
);
} else {
// 带版本验证的更新
result = mContentResolver.update(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mDataId),
mDiffDataValues,
" ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.VERSION + "=?)",
new String[] { String.valueOf(noteId), String.valueOf(version) }
);
}
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}
}
// 重置状态
mDiffDataValues.clear();
mIsCreate = false;
}
/**
* 获取数据ID
* @return 数据ID
*/
public long getId() {
return mDataId;
}
}