diff --git a/src/Notes-master/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java b/src/Notes-master/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java index d2b4082..2c34f22 100644 --- a/src/Notes-master/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java +++ b/src/Notes-master/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java @@ -48,45 +48,43 @@ import java.util.Iterator; import java.util.Map; +/** + * Google Tasks同步管理类 + * 负责本地笔记数据与Google Tasks服务之间的同步逻辑 + * 管理任务、任务列表的双向同步,处理冲突和更新 + * 采用单例模式确保全局唯一实例 + */ public class GTaskManager { private static final String TAG = GTaskManager.class.getSimpleName(); - public static final int STATE_SUCCESS = 0; - - public static final int STATE_NETWORK_ERROR = 1; - - public static final int STATE_INTERNAL_ERROR = 2; - - public static final int STATE_SYNC_IN_PROGRESS = 3; - - public static final int STATE_SYNC_CANCELLED = 4; - - private static GTaskManager mInstance = null; - - private Activity mActivity; - - private Context mContext; - - private ContentResolver mContentResolver; - - private boolean mSyncing; - - private boolean mCancelled; - - private HashMap mGTaskListHashMap; - - private HashMap mGTaskHashMap; - - private HashMap mMetaHashMap; - - private TaskList mMetaList; - - private HashSet mLocalDeleteIdMap; - - private HashMap mGidToNid; - - private HashMap mNidToGid; - + // 同步状态常量 + public static final int STATE_SUCCESS = 0; // 同步成功 + public static final int STATE_NETWORK_ERROR = 1; // 网络错误 + public static final int STATE_INTERNAL_ERROR = 2; // 内部错误 + public static final int STATE_SYNC_IN_PROGRESS = 3; // 同步进行中 + public static final int STATE_SYNC_CANCELLED = 4; // 同步已取消 + + private static GTaskManager mInstance = null; // 单例实例 + + private Activity mActivity; // 用于获取认证的Activity + private Context mContext; // 应用上下文 + private ContentResolver mContentResolver; // 内容解析器 + private boolean mSyncing; // 同步状态标记 + private boolean mCancelled; // 取消同步标记 + + // 数据缓存映射表 + private HashMap mGTaskListHashMap; // Google任务列表映射 + private HashMap mGTaskHashMap; // Google任务映射 + private HashMap mMetaHashMap; // 元数据映射 + private TaskList mMetaList; // 元数据任务列表 + private HashSet mLocalDeleteIdMap; // 本地删除ID集合 + private HashMap mGidToNid; // Google ID到本地ID映射 + private HashMap mNidToGid; // 本地ID到Google ID映射 + + /** + * 私有构造函数,初始化管理器状态 + * 单例模式下不允许外部直接创建实例 + */ private GTaskManager() { mSyncing = false; mCancelled = false; @@ -99,6 +97,10 @@ public class GTaskManager { mNidToGid = new HashMap(); } + /** + * 获取GTaskManager单例实例 + * @return GTaskManager实例 + */ public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); @@ -106,11 +108,20 @@ public class GTaskManager { return mInstance; } + /** + * 设置Activity上下文 + * @param activity 用于获取认证令牌的Activity + */ public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken mActivity = activity; } + /** + * 执行Google Tasks数据同步 + * @param context 应用上下文 + * @param asyncTask 异步任务用于发布进度 + * @return 同步状态码 + */ public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { Log.d(TAG, "Sync is in progress"); @@ -120,6 +131,8 @@ public class GTaskManager { mContentResolver = mContext.getContentResolver(); mSyncing = true; mCancelled = false; + + // 清空现有数据映射 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -131,18 +144,18 @@ public class GTaskManager { GTaskClient client = GTaskClient.getInstance(); client.resetUpdateArray(); - // login google task + // 登录Google Tasks if (!mCancelled) { if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } } - // get the task list from google + // 从Google获取任务列表 asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); initGTaskList(); - // do content sync work + // 执行内容同步 asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); } catch (NetworkFailureException e) { @@ -156,6 +169,7 @@ public class GTaskManager { e.printStackTrace(); return STATE_INTERNAL_ERROR; } finally { + // 清理资源 mGTaskListHashMap.clear(); mGTaskHashMap.clear(); mMetaHashMap.clear(); @@ -168,6 +182,11 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } + /** + * 初始化Google任务列表 + * 从服务器获取任务列表和元数据 + * @throws NetworkFailureException 网络错误时抛出 + */ private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; @@ -175,19 +194,19 @@ public class GTaskManager { try { JSONArray jsTaskLists = client.getTaskLists(); - // init meta list first + // 先初始化元数据列表 mMetaList = null; for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - if (name - .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + // 识别元数据文件夹 + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { mMetaList = new TaskList(); mMetaList.setContentByRemoteJSON(object); - // load meta data + // 加载元数据 JSONArray jsMetas = client.getTaskList(gid); for (int j = 0; j < jsMetas.length(); j++) { object = (JSONObject) jsMetas.getJSONObject(j); @@ -203,29 +222,28 @@ public class GTaskManager { } } - // create meta list if not existed + // 若元数据列表不存在则创建 if (mMetaList == null) { mMetaList = new TaskList(); - mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META); + mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META); GTaskClient.getInstance().createTaskList(mMetaList); } - // init task list + // 初始化任务列表 for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); + // 识别MIUI风格的任务文件夹 if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) - && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META)) { + && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { TaskList tasklist = new TaskList(); tasklist.setContentByRemoteJSON(object); mGTaskListHashMap.put(gid, tasklist); mGTaskHashMap.put(gid, tasklist); - // load tasks + // 加载任务列表中的任务 JSONArray jsTasks = client.getTaskList(gid); for (int j = 0; j < jsTasks.length(); j++) { object = (JSONObject) jsTasks.getJSONObject(j); @@ -247,6 +265,11 @@ public class GTaskManager { } } + /** + * 执行内容同步逻辑 + * 处理本地和远程数据的增删改查 + * @throws NetworkFailureException 网络错误时抛出 + */ private void syncContent() throws NetworkFailureException { int syncType; Cursor c = null; @@ -259,7 +282,7 @@ public class GTaskManager { return; } - // for local deleted note + // 处理本地已删除的笔记 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type<>? AND parent_id=?)", new String[] { @@ -286,10 +309,10 @@ public class GTaskManager { } } - // sync folder first + // 先同步文件夹 syncFolder(); - // for note existing in database + // 处理数据库中存在的笔记 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -306,10 +329,10 @@ public class GTaskManager { syncType = node.getSyncAction(c); } else { if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add + // 本地新增 syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { - // remote delete + // 远程删除 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } @@ -326,7 +349,7 @@ public class GTaskManager { } } - // go through remaining items + // 处理剩余的远程项目 Iterator> iter = mGTaskHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -334,16 +357,14 @@ public class GTaskManager { doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); } - // mCancelled can be set by another thread, so we neet to check one by - // one - // clear local delete table + // 清除本地删除记录 if (!mCancelled) { if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { throw new ActionFailureException("failed to batch-delete local deleted notes"); } } - // refresh local sync id + // 刷新本地同步ID if (!mCancelled) { GTaskClient.getInstance().commitUpdate(); refreshLocalSyncId(); @@ -351,6 +372,11 @@ public class GTaskManager { } + /** + * 同步文件夹数据 + * 处理本地和远程文件夹的同步 + * @throws NetworkFailureException 网络错误时抛出 + */ private void syncFolder() throws NetworkFailureException { Cursor c = null; String gid; @@ -361,7 +387,7 @@ public class GTaskManager { return; } - // for root folder + // 处理根文件夹 try { c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); @@ -373,7 +399,7 @@ public class GTaskManager { mGTaskHashMap.remove(gid); mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); - // for system folder, only update remote name if necessary + // 系统文件夹仅在必要时更新远程名称 if (!node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); @@ -390,7 +416,7 @@ public class GTaskManager { } } - // for call-note folder + // 处理通话记录文件夹 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", new String[] { @@ -404,11 +430,9 @@ public class GTaskManager { mGTaskHashMap.remove(gid); mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); - // for system folder, only update remote name if - // necessary + // 系统文件夹仅在必要时更新远程名称 if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE)) + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); } else { doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); @@ -424,7 +448,7 @@ public class GTaskManager { } } - // for local existing folders + // 处理本地现有文件夹 try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(type=? AND parent_id<>?)", new String[] { @@ -441,10 +465,10 @@ public class GTaskManager { syncType = node.getSyncAction(c); } else { if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add + // 本地新增 syncType = Node.SYNC_ACTION_ADD_REMOTE; } else { - // remote delete + // 远程删除 syncType = Node.SYNC_ACTION_DEL_LOCAL; } } @@ -460,7 +484,7 @@ public class GTaskManager { } } - // for remote add folders + // 处理远程新增的文件夹 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -476,6 +500,14 @@ public class GTaskManager { GTaskClient.getInstance().commitUpdate(); } + /** + * 执行内容同步操作 + * 根据同步类型执行相应的同步逻辑 + * @param syncType 同步操作类型 + * @param node 要同步的节点 + * @param c 数据库游标 + * @throws NetworkFailureException 网络错误时抛出 + */ private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -484,12 +516,15 @@ public class GTaskManager { MetaData meta; switch (syncType) { case Node.SYNC_ACTION_ADD_LOCAL: + // 从远程添加到本地 addLocalNode(node); break; case Node.SYNC_ACTION_ADD_REMOTE: + // 从本地添加到远程 addRemoteNode(node, c); break; case Node.SYNC_ACTION_DEL_LOCAL: + // 删除本地记录 meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); if (meta != null) { GTaskClient.getInstance().deleteNode(meta); @@ -497,6 +532,7 @@ public class GTaskManager { mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); break; case Node.SYNC_ACTION_DEL_REMOTE: + // 删除远程记录 meta = mMetaHashMap.get(node.getGid()); if (meta != null) { GTaskClient.getInstance().deleteNode(meta); @@ -504,14 +540,15 @@ public class GTaskManager { GTaskClient.getInstance().deleteNode(node); break; case Node.SYNC_ACTION_UPDATE_LOCAL: + // 更新本地记录 updateLocalNode(node, c); break; case Node.SYNC_ACTION_UPDATE_REMOTE: + // 更新远程记录 updateRemoteNode(node, c); break; case Node.SYNC_ACTION_UPDATE_CONFLICT: - // merging both modifications maybe a good idea - // right now just use local update simply + // 处理冲突,简单使用本地更新 updateRemoteNode(node, c); break; case Node.SYNC_ACTION_NONE: @@ -522,6 +559,11 @@ public class GTaskManager { } } + /** + * 将远程节点添加到本地 + * @param node 要添加的远程节点 + * @throws NetworkFailureException 网络错误时抛出 + */ private void addLocalNode(Node node) throws NetworkFailureException { if (mCancelled) { return; @@ -529,6 +571,7 @@ public class GTaskManager { SqlNote sqlNote; if (node instanceof TaskList) { + // 处理特殊文件夹 if (node.getName().equals( GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); @@ -536,20 +579,22 @@ public class GTaskManager { GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); } else { + // 普通文件夹 sqlNote = new SqlNote(mContext); sqlNote.setContent(node.getLocalJSONFromContent()); sqlNote.setParentId(Notes.ID_ROOT_FOLDER); } } else { + // 普通任务 sqlNote = new SqlNote(mContext); JSONObject js = node.getLocalJSONFromContent(); try { + // 处理可能的ID冲突 if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); if (note.has(NoteColumns.ID)) { long id = note.getLong(NoteColumns.ID); if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - // the id is not available, have to create a new one note.remove(NoteColumns.ID); } } @@ -562,13 +607,10 @@ public class GTaskManager { if (data.has(DataColumns.ID)) { long dataId = data.getLong(DataColumns.ID); if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { - // the data id is not available, have to create - // a new one data.remove(DataColumns.ID); } } } - } } catch (JSONException e) { Log.w(TAG, e.toString()); @@ -576,6 +618,7 @@ public class GTaskManager { } sqlNote.setContent(js); + // 设置父节点 Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); if (parentId == null) { Log.e(TAG, "cannot find task's parent id locally"); @@ -584,28 +627,35 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); } - // create the local node + // 创建本地节点 sqlNote.setGtaskId(node.getGid()); sqlNote.commit(false); - // update gid-nid mapping + // 更新ID映射 mGidToNid.put(node.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), node.getGid()); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + /** + * 更新本地节点 + * @param node 要更新的节点 + * @param c 数据库游标 + * @throws NetworkFailureException 网络错误时抛出 + */ private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; } SqlNote sqlNote; - // update the note locally + // 更新本地笔记 sqlNote = new SqlNote(mContext, c); sqlNote.setContent(node.getLocalJSONFromContent()); + // 设置父节点 Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) : new Long(Notes.ID_ROOT_FOLDER); if (parentId == null) { @@ -615,10 +665,16 @@ public class GTaskManager { sqlNote.setParentId(parentId.longValue()); sqlNote.commit(true); - // update meta info + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); } + /** + * 将本地节点添加到远程 + * @param node 要添加的本地节点 + * @param c 数据库游标 + * @throws NetworkFailureException 网络错误时抛出 + */ private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -627,11 +683,12 @@ public class GTaskManager { SqlNote sqlNote = new SqlNote(mContext, c); Node n; - // update remotely + // 更新到远程 if (sqlNote.isNoteType()) { Task task = new Task(); task.setContentByLocalJSON(sqlNote.getContent()); + // 设置父任务列表 String parentGid = mNidToGid.get(sqlNote.getParentId()); if (parentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); @@ -642,12 +699,12 @@ public class GTaskManager { GTaskClient.getInstance().createTask(task); n = (Node) task; - // add meta + // 添加元数据 updateRemoteMeta(task.getGid(), sqlNote); } else { TaskList tasklist = null; - // we need to skip folder if it has already existed + // 处理文件夹名称 String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) folderName += GTaskStringUtils.FOLDER_DEFAULT; @@ -656,6 +713,7 @@ public class GTaskManager { else folderName += sqlNote.getSnippet(); + // 检查文件夹是否已存在 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -671,7 +729,7 @@ public class GTaskManager { } } - // no match we can add now + // 不存在则创建新文件夹 if (tasklist == null) { tasklist = new TaskList(); tasklist.setContentByLocalJSON(sqlNote.getContent()); @@ -681,17 +739,23 @@ public class GTaskManager { n = (Node) tasklist; } - // update local note + // 更新本地笔记 sqlNote.setGtaskId(n.getGid()); sqlNote.commit(false); sqlNote.resetLocalModified(); sqlNote.commit(true); - // gid-id mapping + // 更新ID映射 mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } + /** + * 更新远程节点 + * @param node 要更新的节点 + * @param c 数据库游标 + * @throws NetworkFailureException 网络错误时抛出 + */ private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -699,14 +763,14 @@ public class GTaskManager { SqlNote sqlNote = new SqlNote(mContext, c); - // update remotely + // 更新到远程 node.setContentByLocalJSON(sqlNote.getContent()); GTaskClient.getInstance().addUpdateNode(node); - // update meta + // 更新元数据 updateRemoteMeta(node.getGid(), sqlNote); - // move task if necessary + // 必要时移动任务 if (sqlNote.isNoteType()) { Task task = (Task) node; TaskList preParentList = task.getParent(); @@ -718,6 +782,7 @@ public class GTaskManager { } TaskList curParentList = mGTaskListHashMap.get(curParentGid); + // 父任务列表变更时执行移动操作 if (preParentList != curParentList) { preParentList.removeChildTask(task); curParentList.addChildTask(task); @@ -725,18 +790,26 @@ public class GTaskManager { } } - // clear local modified flag + // 清除本地修改标记 sqlNote.resetLocalModified(); sqlNote.commit(true); } + /** + * 更新远程元数据 + * @param gid 节点的Google ID + * @param sqlNote 本地SQL笔记对象 + * @throws NetworkFailureException 网络错误时抛出 + */ private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { if (sqlNote != null && sqlNote.isNoteType()) { MetaData metaData = mMetaHashMap.get(gid); if (metaData != null) { + // 更新现有元数据 metaData.setMeta(gid, sqlNote.getContent()); GTaskClient.getInstance().addUpdateNode(metaData); } else { + // 创建新元数据 metaData = new MetaData(); metaData.setMeta(gid, sqlNote.getContent()); mMetaList.addChildTask(metaData); @@ -746,12 +819,17 @@ public class GTaskManager { } } + /** + * 刷新本地同步ID + * 更新本地记录的同步时间戳 + * @throws NetworkFailureException 网络错误时抛出 + */ private void refreshLocalSyncId() throws NetworkFailureException { if (mCancelled) { return; } - // get the latest gtask list + // 获取最新的任务列表 mGTaskHashMap.clear(); mGTaskListHashMap.clear(); mMetaHashMap.clear(); @@ -790,11 +868,18 @@ public class GTaskManager { } } + /** + * 获取当前同步的账户名称 + * @return 同步账户名称 + */ public String getSyncAccount() { return GTaskClient.getInstance().getSyncAccount().name; } + /** + * 取消同步操作 + */ public void cancelSync() { mCancelled = true; } -} +} \ No newline at end of file