From eab5b917c52f7bc864ca33d7b83d8c6d63b089fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B8=B8=E7=9B=8A=E7=91=9E?= Date: Wed, 18 Sep 2024 21:13:43 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B8=B8=E7=9B=8A=E7=91=9E=E4=B8=8A=E4=BC=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/micode/notes/gtask/data/SqlData.java | 58 ++++++++- .../net/micode/notes/gtask/data/SqlNote.java | 119 +++++++++++++++--- .../net/micode/notes/gtask/data/TaskList.java | 41 +++--- 3 files changed, 184 insertions(+), 34 deletions(-) diff --git a/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index d3ec3be..6640a88 100644 --- a/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +//下面是常益瑞的标注 package net.micode.notes.gtask.data; import android.content.ContentResolver; @@ -89,7 +89,13 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + /** + * 从Cursor中加载数据 + * + * @param c Cursor对象,用于从中读取数据 + */ private void loadFromCursor(Cursor c) { + // 从Cursor中读取数据,并赋值给相应的类成员变量 mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); mDataContent = c.getString(DATA_CONTENT_COLUMN); @@ -97,65 +103,103 @@ public class SqlData { mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } + /** + * 设置内容,根据传入的JSON对象更新数据值 + * 此方法主要用于解析JSON对象并更新数据模型 + * + * @param js 包含数据的JSON对象 + * @throws JSONException 如果解析过程中发生错误 + */ public void setContent(JSONObject js) throws JSONException { + // 获取数据ID,如果JSON对象中没有ID,则默认为无效ID long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; + // 如果是创建新数据,或者当前数据ID与新ID不同,则更新差分 if (mIsCreate || mDataId != dataId) { mDiffDataValues.put(DataColumns.ID, dataId); } + // 更新当前数据ID mDataId = dataId; String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) : DataConstants.NOTE; + // 如果是创建新数据,或者当前MIME类型与新MIME类型不同,则更新差分数据值中的MIME类型 if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); } + // 更新当前数据MIME类型 mDataMimeType = dataMimeType; - + // 获取数据内容,如果JSON对象中没有内容,则默认为空字符串 String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; + // 如果是创建新数据,或者当前内容与新内容不同,则更新差分数据值中的内容 if (mIsCreate || !mDataContent.equals(dataContent)) { mDiffDataValues.put(DataColumns.CONTENT, dataContent); } + // 更新当前数据内容 mDataContent = dataContent; - + // 获取第一个数据附加信息,如果JSON对象中没有,则默认为0 long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; + // 如果是创建新数据,或者当前的第一个附加信息与新的不同,则更新差分数据值中的第一个附加信息 if (mIsCreate || mDataContentData1 != dataContentData1) { mDiffDataValues.put(DataColumns.DATA1, dataContentData1); } mDataContentData1 = dataContentData1; String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; + // 如果是创建新数据,或者当前的第三个附加信息与新的不同,则更新差分数据值中的第三个附加信息 if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { mDiffDataValues.put(DataColumns.DATA3, dataContentData3); } + // 更新当前第三个数据附加信息 mDataContentData3 = dataContentData3; } + /** + * 获取内容的JSON对象 + * 此方法用于生成一个包含当前数据内容的JSONObject + * 如果该内容尚未在数据库中创建,则返回null + * + * @return JSONObject包含内容的数据,如果内容未创建则返回null + * @throws JSONException 如果创建JSONObject或添加数据时发生错误 + */ public JSONObject getContent() throws JSONException { + // 检查是否已创建此内容 if (mIsCreate) { + // 如果尚未创建,记录信息并返回null Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } + // 创建一个新的JSONObject来存储内容 JSONObject js = new JSONObject(); + // 将内容的ID添加到JSONObject中 js.put(DataColumns.ID, mDataId); + // 将内容的MIME类型添加到JSONObject中 js.put(DataColumns.MIME_TYPE, mDataMimeType); + // 将内容的主体添加到JSONObject中 js.put(DataColumns.CONTENT, mDataContent); + // 将内容的data1字段添加到JSONObject中 js.put(DataColumns.DATA1, mDataContentData1); + // 将内容的data3字段添加到JSONObject中 js.put(DataColumns.DATA3, mDataContentData3); + // 返回包含内容的JSONObject return js; } 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 uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); + // 从URI中解析新插入数据的ID try { mDataId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { + // 如果无法解析ID,记录错误并抛出异常 Log.e(TAG, "Get note id error :" + e.toString()); throw new ActionFailureException("create note failed"); } @@ -166,6 +210,7 @@ public class SqlData { 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 @@ -173,12 +218,13 @@ public class SqlData { String.valueOf(noteId), String.valueOf(version) }); } + // 如果更新结果为0,表示没有更新,可能是因为用户在同步时更新了笔记 if (result == 0) { Log.w(TAG, "there is no update. maybe user updates note when syncing"); } } } - + // 清空更改值并重置创建状态 mDiffDataValues.clear(); mIsCreate = false; } diff --git a/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java b/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java index 79a4095..f1b794a 100644 --- a/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java +++ b/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +//常益瑞的阅读代码和标注 package net.micode.notes.gtask.data; import android.appwidget.AppWidgetManager; @@ -122,6 +122,11 @@ public class SqlNote { private ArrayList mDataList; + /** + * 构造一个新的SqlNote对象,并初始化其属性。 + * + * @param context 上下文环境 + */ public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -142,7 +147,12 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } - + /** + * 根据给定的上下文环境和游标构造一个SqlNote对象,并从游标加载数据。 + * + * @param context 上下文环境 + * @param c 游标对象 + */ public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -153,7 +163,12 @@ public class SqlNote { loadDataContent(); mDiffNoteValues = new ContentValues(); } - + /** + * 根据给定的上下文环境和指定ID构造一个SqlNote对象,并根据ID加载数据。 + * + * @param context 上下文环境 + * @param id 数据的唯一标识符 + */ public SqlNote(Context context, long id) { mContext = context; mContentResolver = context.getContentResolver(); @@ -166,25 +181,43 @@ public class SqlNote { } + /** + * 从数据库加载指定ID的笔记信息 + * + * @param id 需要加载的笔记的ID + */ private void loadFromCursor(long id) { + // 创建Cursor对象,用于执行SQL查询 Cursor c = null; try { + // 根据传入的ID查询数据库中的笔记信息 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", new String[] { String.valueOf(id) }, null); + // 如果查询结果不为空,移动到查询结果的第一行,并调用loadFromCursor方法处理数据 if (c != null) { c.moveToNext(); loadFromCursor(c); } else { + // 如果查询结果为空,记录警告日志 Log.w(TAG, "loadFromCursor: cursor = null"); } } finally { + // 关闭Cursor资源,避免内存泄漏 if (c != null) c.close(); } } + /** + * 从Cursor中加载数据 + * + * 此方法用于从数据库查询结果(Cursor)中提取数据,并将其赋值给当前对象的成员变量 + * 它按列索引读取各种类型的数据(长整型、整型、字符串等),并更新对象的状态 + * + * @param c 数据库查询结果的Cursor对象,包含待加载的数据 + */ private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); @@ -200,24 +233,37 @@ public class SqlNote { mVersion = c.getLong(VERSION_COLUMN); } + /** + * 加载笔记内容 + * + * 本方法从内容提供者中查询特定笔记的详细数据主要用途是在笔记详情活动中展示笔记的具体内容 + * 方法首先清除现有的数据列表,然后从内容提供者处获取并添加新的数据 + */ private void loadDataContent() { + // 声明一个Cursor对象用于查询数据 Cursor c = null; + // 清空数据列表,准备加载新的数据 mDataList.clear(); try { + // 执行查询操作,根据note_id获取笔记的详细数据 c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, "(note_id=?)", new String[] { String.valueOf(mId) }, null); + // 检查查询结果 if (c != null) { + // 如果查询结果为空,记录警告日志并返回 if (c.getCount() == 0) { Log.w(TAG, "it seems that the note has not data"); return; } + // 遍历查询结果,将每个数据项添加到数据列表中 while (c.moveToNext()) { SqlData data = new SqlData(mContext, c); mDataList.add(data); } } else { + // 如果查询结果的Cursor为null,记录警告日志 Log.w(TAG, "loadDataContent: cursor = null"); } } finally { @@ -226,19 +272,27 @@ public class SqlNote { } } + /** + * 从给定的JSONObject中设置便笺的内容。 + * + * @param js 包含便笺信息的JSON对象。 + * @return 如果成功设置内容返回true,否则返回false。 + */ public boolean setContent(JSONObject js) { try { + // 获取便笺数组 JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + // 初始化便笺数据对象 if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { Log.w(TAG, "cannot set system folder"); } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - // for folder we can only update the snnipet and type - String snippet = note.has(NoteColumns.SNIPPET) ? note + // 更新文件夹类型的便笺的摘要和类型 String snippet = note.has(NoteColumns.SNIPPET) ? note .getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); } mSnippet = snippet; + // int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; @@ -359,17 +413,24 @@ public class SqlNote { return true; } + /** + * 根据对象的类型组装并返回一个包含笔记或文件夹信息的JSONObject + * 此方法主要用于生成内容的JSON表示,包括笔记的详细信息以及可能关联的数据 + * + * @return 包含笔记或文件夹信息的JSONObject,如果未创建则返回null + */ public JSONObject getContent() { try { JSONObject js = new JSONObject(); - + // 检查标记,确保对象已经在数据库中创建,否则记录错误并返回null if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } - + // 根据对象类型,构造不同的JSONObject JSONObject note = new JSONObject(); if (mType == Notes.TYPE_NOTE) { + // 如果是笔记类型,将笔记的详细信息添加到JSONObject中 note.put(NoteColumns.ID, mId); note.put(NoteColumns.ALERTED_DATE, mAlertDate); note.put(NoteColumns.BG_COLOR_ID, mBgColorId); @@ -383,7 +444,7 @@ public class SqlNote { note.put(NoteColumns.WIDGET_TYPE, mWidgetType); note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); js.put(GTaskStringUtils.META_HEAD_NOTE, note); - + // 构造一个JSONArray来存储关联的数据对象,并将其添加到主JSONObject中 JSONArray dataArray = new JSONArray(); for (SqlData sqlData : mDataList) { JSONObject data = sqlData.getContent(); @@ -393,6 +454,7 @@ public class SqlNote { } js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { + // 如果是文件夹或系统类型,将基本信息添加到JSONObject中 note.put(NoteColumns.ID, mId); note.put(NoteColumns.TYPE, mType); note.put(NoteColumns.SNIPPET, mSnippet); @@ -401,6 +463,7 @@ public class SqlNote { return js; } catch (JSONException e) { + // 捕获JSONException异常,记录错误并打印堆栈跟踪 Log.e(TAG, e.toString()); e.printStackTrace(); } @@ -408,18 +471,29 @@ public class SqlNote { } public void setParentId(long id) { + // 设置父ID mParentId = id; + // 记录父ID的变更值 mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } - + /** + * 设置任务的GtaskId + * + * @param gid 任务的GtaskId + */ public void setGtaskId(String gid) { mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } - + //设置同步I public void setSyncId(long syncId) { mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); } - + /** + * 将本地修改状态重置为未修改 + * + * 本方法通过将本地修改状态值设置为0,来标记当前笔记未经过本地修改 + * 这对于同步或者比较操作中,判断笔记是否经过本地修改至关重要 + */ public void resetLocalModified() { mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); } @@ -440,23 +514,38 @@ public class SqlNote { return mType == Notes.TYPE_NOTE; } + /** + * 提交笔记更改或创建新笔记 + * 如果是新创建的笔记,将尝试把笔记插入数据库 + * 如果是更新现有笔记,将尝试更新数据库中的笔记信息 + * + * @param validateVersion 是否验证版本在更新时的有效性 + * @throws ActionFailureException 如果创建笔记失败 + * @throws IllegalStateException 如果创建线程ID失败或尝试用无效ID更新笔记 + */ public void commit(boolean validateVersion) { + // 如果是新创建的笔记 if (mIsCreate) { + // 检查是否需要移除无效的ID值 if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { mDiffNoteValues.remove(NoteColumns.ID); } - + // 插入新笔记并获取URI Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); try { + // 从URI中提取并设置新创建的笔记ID mId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { + // 日志记录获取笔记ID错误 Log.e(TAG, "Get note id error :" + e.toString()); + // 抛出异常指示创建笔记失败 throw new ActionFailureException("create note failed"); } if (mId == 0) { + // 抛出异常指示创建线程ID失败 throw new IllegalStateException("Create thread id failed"); } - + // 如果是普通笔记,提交附加数据 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, false, -1); @@ -467,6 +556,7 @@ public class SqlNote { Log.e(TAG, "No such note"); throw new IllegalStateException("Try to update note with invalid id"); } + // 如果有更改值,更新笔记 if (mDiffNoteValues.size() > 0) { mVersion ++; int result = 0; @@ -482,11 +572,12 @@ public class SqlNote { String.valueOf(mId), String.valueOf(mVersion) }); } + // 如果更新结果为0,日志记录可能的同步时更新冲突 if (result == 0) { Log.w(TAG, "there is no update. maybe user updates note when syncing"); } } - + // 如果是普通笔记,提交附加数据 if (mType == Notes.TYPE_NOTE) { for (SqlData sqlData : mDataList) { sqlData.commit(mId, validateVersion, mVersion); diff --git a/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/TaskList.java b/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/TaskList.java index 4ea21c5..1f1b887 100644 --- a/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/TaskList.java +++ b/src/MiNote/app/src/main/java/net/micode/notes/gtask/data/TaskList.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +//常益瑞的阅读和注释 package net.micode.notes.gtask.data; import android.database.Cursor; @@ -30,13 +30,20 @@ import org.json.JSONObject; import java.util.ArrayList; +/** + * 任务列表类,继承自Node,用于管理一系列子任务 + */ public class TaskList extends Node { private static final String TAG = TaskList.class.getSimpleName(); - + /** + * 当前任务列表的索引值,用于排序或标识位置 + */ private int mIndex; private ArrayList mChildren; - + /** + * 构造一个新的任务列表 + */ public TaskList() { super(); mChildren = new ArrayList(); @@ -47,18 +54,17 @@ public class TaskList extends Node { JSONObject js = new JSONObject(); try { - // action_type + // 设置操作类型为创建 + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - // action_id + // 设置操作ID,用于服务端识别操作 js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // index - js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); + // 设置操作索引,表示操作在列表中的位置 js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); - // entity_delta - JSONObject entity = new JSONObject(); + // 构建实体变化的JSON对象,包括任务的名称、创建者ID和实体类型 JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, @@ -73,17 +79,24 @@ public class TaskList extends Node { return js; } - + /** + * 构建一个表示任务更新操作的JSONObject + * 此方法用于生成一个包含任务更新操作信息的JSON对象,包括操作类型、操作ID、任务ID和任务的变更详情 + * + * @param actionId 更新操作的ID,用于标识此次更新操作 + * @return 返回一个JSONObject,包含任务更新操作的相关信息 + * @throws ActionFailureException 如果构建JSON对象失败,则抛出此自定义异常 + */ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); try { - // action_type - js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, + // 操作类型 + js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + // 操作ID + /js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // id js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());