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.

230 lines
8.9 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.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.gtask.data;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
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;
import org.json.JSONException;
import org.json.JSONObject;
/**
* 便签数据操作类,封装本地数据库操作逻辑
* 负责便签数据的增删改查、JSON序列化与反序列化
* 支持增量更新和版本验证,确保数据一致性
*/
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, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,
DataColumns.DATA3
};
// 投影列索引常量(用于快速定位查询结果中的字段)
public static final int DATA_ID_COLUMN = 0;
public static final int DATA_MIME_TYPE_COLUMN = 1;
public static final int DATA_CONTENT_COLUMN = 2;
public static final int DATA_CONTENT_DATA_1_COLUMN = 3;
public static final int DATA_CONTENT_DATA_3_COLUMN = 4;
// 数据访问与状态管理
private 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 ContentValues mDiffDataValues; // 差异值集合(存储需要更新的字段)
/**
* 构造函数(新建数据对象)
* 初始化默认值,设置为新建状态
*/
public SqlData(Context context) {
mContentResolver = context.getContentResolver();
mIsCreate = true;
mDataId = INVALID_ID;
mDataMimeType = DataConstants.NOTE; // 默认MIME类型为普通便签
mDataContent = "";
mDataContentData1 = 0;
mDataContentData3 = "";
mDiffDataValues = new ContentValues();
}
/**
* 构造函数(从数据库加载数据)
* 从游标中加载数据,设置为非新建状态
*/
public SqlData(Context context, Cursor c) {
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDiffDataValues = new ContentValues();
}
/**
* 从游标加载数据
* 用于从查询结果中初始化对象属性
*/
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对象包含要设置的字段
*/
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表示
* 将当前对象属性转换为JSON对象
* @return 包含当前对象属性的JSON对象
*/
public JSONObject getContent() throws JSONException {
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
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 预期的版本号
*/
public void commit(long noteId, boolean validateVersion, long version) {
if (mIsCreate) {
// 新建数据处理
if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {
mDiffDataValues.remove(DataColumns.ID); // 移除无效ID
}
mDiffDataValues.put(DataColumns.NOTE_ID, noteId); // 设置关联便签ID
Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);
try {
mDataId = Long.valueOf(uri.getPathSegments().get(1)); // 获取插入后的ID
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
} else {
// 更新数据处理
if (mDiffDataValues.size() > 0) {
int result = 0;
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;
}
}