diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java b/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java index 3a2050b..8503387 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/MetaData.java @@ -26,8 +26,9 @@ import org.json.JSONObject; public class MetaData extends Task { + // 日志标签,使用类名作为标签 private final static String TAG = MetaData.class.getSimpleName(); - + // 存储关联的Google Task ID private String mRelatedGid = null; public void setMeta(String gid, JSONObject metaInfo) { @@ -37,6 +38,7 @@ public class MetaData extends Task { Log.e(TAG, "failed to put related gid"); } setNotes(metaInfo.toString()); + // 设置任务名称为元数据特定的名称 setName(GTaskStringUtils.META_NOTE_NAME); } @@ -51,12 +53,16 @@ public class MetaData extends Task { @Override public void setContentByRemoteJSON(JSONObject js) { + // 调用父类的解析方法 super.setContentByRemoteJSON(js); + // 如果notes字段存在,则从中解析关联的GTask ID if (getNotes() != null) { try { JSONObject metaInfo = new JSONObject(getNotes().trim()); + // 从JSON中提取关联的GTask ID mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { + // 解析失败时记录警告并清空关联ID Log.w(TAG, "failed to get related gid"); mRelatedGid = null; } diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/Node.java b/src/Notes-master/src/net/micode/notes/gtask/data/Node.java index 63950e0..06fa13b 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/Node.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/Node.java @@ -19,7 +19,10 @@ package net.micode.notes.gtask.data; import android.database.Cursor; import org.json.JSONObject; - +/** + * 定义了GTask同步过程中通用的节点属性(唯一标识、名称、修改时间、删除标记)、 + * 是本地笔记与远程GTask数据同步的核心,子类需实现具体的同步逻辑。 + */ public abstract class Node { public static final int SYNC_ACTION_NONE = 0; @@ -38,15 +41,21 @@ public abstract class Node { public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; public static final int SYNC_ACTION_ERROR = 8; - + //GTask节点唯一标识(Gid,Google Tasks体系的全局唯一ID) private String mGid; - + //节点名称(对应GTask标题/本地笔记标题) private String mName; - + //最后修改时间戳 private long mLastModified; - + //删除标记 private boolean mDeleted; - + /** + * 构造方法:初始化节点默认属性 + * - Gid:null(未关联远程GTask) + * - 名称:空字符串 + * - 最后修改时间:0(未修改) + * - 删除标记:false(正常状态) + */ public Node() { mGid = null; mName = ""; diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java b/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java index d3ec3be..c62e085 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/SqlData.java @@ -36,10 +36,11 @@ import org.json.JSONObject; 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 @@ -56,7 +57,7 @@ public class SqlData { public static final int DATA_CONTENT_DATA_3_COLUMN = 4; private ContentResolver mContentResolver; - + //返回true表示是新建数据,false表示已存在 private boolean mIsCreate; private long mDataId; @@ -68,9 +69,11 @@ public class SqlData { private long mDataContentData1; private String mDataContentData3; - + // 存储数据字段的差异值 private ContentValues mDiffDataValues; - + /** + * 构造函数 - 用于创建新的SqlData对象 + */ public SqlData(Context context) { mContentResolver = context.getContentResolver(); mIsCreate = true; @@ -88,7 +91,9 @@ public class SqlData { loadFromCursor(c); mDiffDataValues = new ContentValues(); } - + /** + * 从数据库cursor加载数据到对象字段 + */ private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -98,31 +103,32 @@ public class SqlData { } 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); @@ -148,24 +154,27 @@ public class SqlData { if (mIsCreate) { if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { - mDiffDataValues.remove(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.valueOf(uri.getPathSegments().get(1)); } 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 @@ -179,8 +188,8 @@ public class SqlData { } } - mDiffDataValues.clear(); - mIsCreate = false; + mDiffDataValues.clear();// 清除差异值 + mIsCreate = false;// 标记为已提交 } public long getId() { diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java b/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java index 79a4095..217c5b4 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java @@ -36,13 +36,19 @@ import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; - +/** + * 本地笔记数据库操作核心类(适配GTask同步) + * 封装笔记主表(note)的字段属性、数据库操作 + */ public class SqlNote { private static final String TAG = SqlNote.class.getSimpleName(); private static final int INVALID_ID = -99999; - + /** + * 笔记主表(note)查询投影字段数组 + * 定义查询笔记时需要加载的所有字段,与NoteColumns一一对应,用于Cursor取值 + */ public static final String[] PROJECTION_NOTE = new String[] { NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE, @@ -121,7 +127,9 @@ public class SqlNote { private ContentValues mDiffNoteValues; private ArrayList mDataList; - + /** + * 初始化笔记默认属性,如背景色为默认值、创建/修改时间为当前时间、类型为普通笔记 + */ public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -142,7 +150,10 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } - + /** + * 从数据库Cursor加载已有笔记 + * 从Cursor中解析笔记主表字段,并加载附属数据 + */ public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -153,7 +164,10 @@ public class SqlNote { loadDataContent(); mDiffNoteValues = new ContentValues(); } - + /** + * 通过笔记ID加载已有笔记 + * 根据ID查询数据库获取Cursor,再加载笔记属性和附属数据 + */ public SqlNote(Context context, long id) { mContext = context; mContentResolver = context.getContentResolver(); @@ -165,7 +179,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); } - + //按笔记ID查询数据库,加载笔记主表属性 private void loadFromCursor(long id) { Cursor c = null; try { @@ -184,7 +198,7 @@ public class SqlNote { c.close(); } } - + //从Cursor解析笔记主表字段到成员变量 private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); @@ -199,7 +213,7 @@ public class SqlNote { mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); mVersion = c.getLong(VERSION_COLUMN); } - + //加载笔记附属数据,从data表查询并封装为SqlData对象 private void loadDataContent() { Cursor c = null; mDataList.clear(); @@ -232,7 +246,7 @@ public class SqlNote { 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 .getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { @@ -247,6 +261,7 @@ public class SqlNote { } mType = type; } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { + //对所有普通笔记,更新所有字段 + 处理附属数据 JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; if (mIsCreate || mId != id) { @@ -330,7 +345,7 @@ public class SqlNote { mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); } mOriginParent = originParent; - + // 处理附属数据列表 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); SqlData sqlData = null; @@ -358,7 +373,10 @@ public class SqlNote { } return true; } - + /** + * 将笔记内容序列化为JSON对象,适配GTask同步格式 + * @return 封装笔记数据的JSON对象;新建笔记未提交时返回null,解析异常时返回null + */ public JSONObject getContent() { try { JSONObject js = new JSONObject(); @@ -463,10 +481,12 @@ public class SqlNote { } } } else { + // 更新笔记:验证ID有效性 if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { Log.e(TAG, "No such note"); throw new IllegalStateException("Try to update note with invalid id"); } + // 更新主表(仅当有变更时) if (mDiffNoteValues.size() > 0) { mVersion ++; int result = 0; @@ -486,7 +506,7 @@ public class SqlNote { 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/Notes-master/src/net/micode/notes/gtask/data/Task.java b/src/Notes-master/src/net/micode/notes/gtask/data/Task.java index 6a19454..89c114d 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/Task.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/Task.java @@ -33,18 +33,21 @@ import org.json.JSONObject; public class Task extends Node { + // 使用类名作为日志标签 private static final String TAG = Task.class.getSimpleName(); - + // 任务完成状态 private boolean mCompleted; private String mNotes; private JSONObject mMetaInfo; - + // 前一个兄弟任务 private Task mPriorSibling; private TaskList mParent; - + /** + * 初始化任务对象 + */ public Task() { super(); mCompleted = false; @@ -53,22 +56,24 @@ public class Task extends Node { mParent = null; mMetaInfo = null; } - + /** + * 生成创建任务的JSON动作 + * 用于向Google Tasks API发送创建请求 + */ public JSONObject getCreateAction(int actionId) { 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, mParent.getChildTaskIndex(this)); - // entity_delta JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); @@ -79,17 +84,13 @@ public class Task extends Node { } js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); - // parent_id js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); - // dest_parent_type js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - // list_id js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); - // prior_sibling_id if (mPriorSibling != null) { js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); } @@ -97,6 +98,7 @@ public class Task extends Node { } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); + // 抛出应用层的异常 throw new ActionFailureException("fail to generate task-create jsonobject"); } @@ -107,17 +109,15 @@ public class Task extends Node { JSONObject js = new JSONObject(); try { - // action_type + // 设置动作类型 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // action_id + // 设置动作id js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // id js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // entity_delta JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); if (getNotes() != null) { @@ -138,32 +138,26 @@ public class Task extends Node { public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { - // id if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); } - // last_modified if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); } - // name if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); } - // notes if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); } - // deleted if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); } - // completed if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); } @@ -208,7 +202,6 @@ public class Task extends Node { String name = getName(); try { if (mMetaInfo == null) { - // new task created from web if (name == null) { Log.w(TAG, "the note seems to be an empty one"); return null; @@ -225,7 +218,7 @@ public class Task extends Node { js.put(GTaskStringUtils.META_HEAD_NOTE, note); return js; } else { - // synced task + // 同步任务 JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); @@ -282,22 +275,19 @@ public class Task extends Node { } if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side return SYNC_ACTION_NONE; } else { - // apply remote to local + // 应用远程更新 return SYNC_ACTION_UPDATE_LOCAL; } } else { - // validate gtask id if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { Log.e(TAG, "gtask id doesn't match"); return SYNC_ACTION_ERROR; } if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only + // 仅允许本地更改 return SYNC_ACTION_UPDATE_REMOTE; } else { return SYNC_ACTION_UPDATE_CONFLICT; diff --git a/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java b/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java index 4ea21c5..7878ae3 100644 --- a/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java +++ b/src/Notes-master/src/net/micode/notes/gtask/data/TaskList.java @@ -47,17 +47,16 @@ 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); - // entity_delta JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); @@ -78,17 +77,15 @@ public class TaskList extends Node { JSONObject js = new JSONObject(); try { - // action_type + // 动作类型 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // action_id + // 动作id js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // id js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // entity_delta JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); @@ -111,12 +108,11 @@ public class TaskList extends Node { setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); } - // last_modified + // 时间戳 if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); } - // name if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); } @@ -186,25 +182,23 @@ public class TaskList extends Node { public int getSyncAction(Cursor c) { try { if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update + // 没有本地更新 if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side return SYNC_ACTION_NONE; } else { - // apply remote to local + // 应用同步 return SYNC_ACTION_UPDATE_LOCAL; } } else { - // validate gtask id if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { Log.e(TAG, "gtask id doesn't match"); return SYNC_ACTION_ERROR; } if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only + // 仅限本地修改 return SYNC_ACTION_UPDATE_REMOTE; } else { - // for folder conflicts, just apply local modification + // 对于文件夹冲突,只需应用本地修改 return SYNC_ACTION_UPDATE_REMOTE; } } @@ -225,7 +219,7 @@ public class TaskList extends Node { if (task != null && !mChildren.contains(task)) { ret = mChildren.add(task); if (ret) { - // need to set prior sibling and parent + task.setPriorSibling(mChildren.isEmpty() ? null : mChildren .get(mChildren.size() - 1)); task.setParent(this); @@ -244,7 +238,7 @@ public class TaskList extends Node { if (task != null && pos == -1) { mChildren.add(index, task); - // update the task list + // 更新任务列表 Task preTask = null; Task afterTask = null; if (index != 0) @@ -267,11 +261,11 @@ public class TaskList extends Node { ret = mChildren.remove(task); if (ret) { - // reset prior sibling and parent + // 重置父节点和兄弟节点 task.setPriorSibling(null); task.setParent(null); - // update the task list + // 更新任务列表 if (index != mChildren.size()) { mChildren.get(index).setPriorSibling( index == 0 ? null : mChildren.get(index - 1));