diff --git a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java index 3a2050b..babec53 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/MetaData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/MetaData.java @@ -1,19 +1,3 @@ -/* - * 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.database.Cursor; @@ -24,59 +8,99 @@ import net.micode.notes.tool.GTaskStringUtils; import org.json.JSONException; import org.json.JSONObject; - +/** + * 元数据实体类,继承自Task基类 + * 功能:处理与Google Task关联的元数据信息 + * 注意:此类仅支持远程数据操作,本地操作会抛出异常 + */ public class MetaData extends Task { + // 日志标签(使用类名简化) private final static String TAG = MetaData.class.getSimpleName(); + // 关联的Google Task服务端ID private String mRelatedGid = null; + /** + * 设置元数据信息 + * @param gid 关联的Google Task ID + * @param metaInfo 需要封装的元数据JSON对象 + */ public void setMeta(String gid, JSONObject metaInfo) { try { + // 将Google Task ID注入元数据头部 metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { - Log.e(TAG, "failed to put related gid"); + Log.e(TAG, "failed to put related gid"); // 理论上不会触发,因META_HEAD_GTASK_ID是合法key } + // 将元数据存储到父类的notes字段 setNotes(metaInfo.toString()); + // 设置固定名称标识 setName(GTaskStringUtils.META_NOTE_NAME); } + /** + * 获取关联的Google Task ID + */ public String getRelatedGid() { return mRelatedGid; } + /** + * 判断是否需要持久化存储 + * @return 当包含有效元数据时返回true + */ @Override public boolean isWorthSaving() { - return getNotes() != null; + return getNotes() != null; // 仅当存在元数据时需要保存 } + /** + * 从服务端JSON数据解析内容 + * @param js 包含元数据的服务端JSON对象 + */ @Override public void setContentByRemoteJSON(JSONObject js) { super.setContentByRemoteJSON(js); if (getNotes() != null) { try { + // 解析notes字段中的元数据(去除前后空格确保格式正确) JSONObject metaInfo = new JSONObject(getNotes().trim()); + // 提取关联的Google Task ID mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { - Log.w(TAG, "failed to get related gid"); + Log.w(TAG, "failed to get related gid"); // 处理元数据格式错误 mRelatedGid = null; } } } + //------------------------ 以下方法禁用 ------------------------ + // 设计约束:此类仅用于处理服务端元数据,禁止本地操作 + + /** + * 禁止本地JSON设置(直接抛出异常) + * @throws IllegalAccessError 当尝试调用时抛出 + */ @Override public void setContentByLocalJSON(JSONObject js) { - // this function should not be called throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); } + /** + * 禁止获取本地JSON(直接抛出异常) + * @throws IllegalAccessError 当尝试调用时抛出 + */ @Override public JSONObject getLocalJSONFromContent() { throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); } + /** + * 禁止同步操作(直接抛出异常) + * @throws IllegalAccessError 当尝试调用时抛出 + */ @Override public int getSyncAction(Cursor c) { throw new IllegalAccessError("MetaData:getSyncAction should not be called"); } - -} +} \ No newline at end of file diff --git a/app/src/main/java/net/micode/notes/gtask/data/Node.java b/app/src/main/java/net/micode/notes/gtask/data/Node.java index 63950e0..16b4cdb 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/Node.java +++ b/app/src/main/java/net/micode/notes/gtask/data/Node.java @@ -1,101 +1,143 @@ -/* - * 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.database.Cursor; - import org.json.JSONObject; +/** + * 同步节点抽象基类 + * + * 功能:定义数据同步的核心属性和行为规范,提供以下能力: + * 1. 维护节点基础属性(GID、名称、时间戳、删除状态) + * 2. 定义同步动作类型常量 + * 3. 声明数据序列化/反序列化抽象方法 + * 4. 提供基础字段访问器 + * + * 设计约束:具体同步逻辑需由子类实现(如Note/Task等实体) + */ public abstract class Node { + /* 同步动作类型常量定义 */ + + /** 无需同步操作 */ public static final int SYNC_ACTION_NONE = 0; + /** 需要在远程服务端创建新节点 */ public static final int SYNC_ACTION_ADD_REMOTE = 1; + /** 需要在本地创建新节点 */ public static final int SYNC_ACTION_ADD_LOCAL = 2; + /** 需要删除远程节点 */ public static final int SYNC_ACTION_DEL_REMOTE = 3; + /** 需要删除本地节点 */ public static final int SYNC_ACTION_DEL_LOCAL = 4; + /** 需要更新远程节点数据 */ public static final int SYNC_ACTION_UPDATE_REMOTE = 5; + /** 需要更新本地节点数据 */ public static final int SYNC_ACTION_UPDATE_LOCAL = 6; + /** 数据冲突需要解决(本地和远程版本都有修改) */ public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; + /** 同步过程中发生错误 */ public static final int SYNC_ACTION_ERROR = 8; - private String mGid; - - private String mName; - - private long mLastModified; - - private boolean mDeleted; + // 节点基础属性 + private String mGid; // 全局唯一标识(服务端分配) + private String mName; // 节点显示名称 + private long mLastModified; // 最后修改时间戳(毫秒) + private boolean mDeleted; // 软删除标记 + /** 初始化节点默认属性 */ public Node() { - mGid = null; - mName = ""; - mLastModified = 0; - mDeleted = false; + mGid = null; // 新建节点尚未分配GID + mName = ""; // 空名称初始化 + mLastModified = 0; // 时间戳初始为0表示未同步 + mDeleted = false; // 初始为非删除状态 } + /* 抽象方法定义(需子类实现) */ + + /** + * 生成创建动作的JSON数据包 + * @param actionId 动作序列号(用于请求排序) + * @return 包含创建指令的JSON对象 + */ public abstract JSONObject getCreateAction(int actionId); + /** + * 生成更新动作的JSON数据包 + * @param actionId 动作序列号 + * @return 包含更新指令的JSON对象 + */ public abstract JSONObject getUpdateAction(int actionId); + /** + * 从服务端JSON数据加载节点内容 + * @param js 包含节点数据的服务端响应JSON + */ public abstract void setContentByRemoteJSON(JSONObject js); + /** + * 从本地JSON数据加载节点内容 + * @param js 本地存储的节点数据JSON + */ public abstract void setContentByLocalJSON(JSONObject js); + /** + * 将节点内容转换为本地存储的JSON格式 + * @return 可用于本地存储的JSON对象 + */ public abstract JSONObject getLocalJSONFromContent(); + /** + * 根据数据库游标判断需要的同步动作 + * @param c 指向本地数据库记录的游标 + * @return 需要执行的同步动作类型常量 + */ public abstract int getSyncAction(Cursor c); + /* 基础属性访问方法 */ + + /** 设置全局唯一标识(通常由服务端分配) */ public void setGid(String gid) { this.mGid = gid; } + /** 设置节点显示名称 */ public void setName(String name) { this.mName = name; } + /** 设置最后修改时间戳(UTC毫秒数) */ public void setLastModified(long lastModified) { this.mLastModified = lastModified; } + /** 标记节点删除状态(true=已删除) */ public void setDeleted(boolean deleted) { this.mDeleted = deleted; } + /** 获取全局唯一标识 */ public String getGid() { return this.mGid; } + /** 获取节点显示名称 */ public String getName() { return this.mName; } + /** 获取最后修改时间戳 */ public long getLastModified() { return this.mLastModified; } + /** 获取删除状态 */ public boolean getDeleted() { return this.mDeleted; } - -} +} \ No newline at end of file diff --git a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index d3ec3be..c12a3f3 100644 --- a/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -1,29 +1,14 @@ -/* - * 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; +// 导入所需的Android包 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; @@ -31,46 +16,42 @@ 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; 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 }; + // 定义投影中各列的索引 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; + // 数据成员用于存储内容解析器、是否创建、数据ID、MIME类型、内容等信息 private ContentResolver mContentResolver; - private boolean mIsCreate; - private long mDataId; - private String mDataMimeType; - private String mDataContent; - private long mDataContentData1; - private String mDataContentData3; - private ContentValues mDiffDataValues; + // 构造函数,用于创建新的SqlData对象 public SqlData(Context context) { mContentResolver = context.getContentResolver(); mIsCreate = true; @@ -82,6 +63,7 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + // 构造函数,用于从游标加载现有数据 public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); mIsCreate = false; @@ -89,6 +71,7 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + // 从游标加载数据到SqlData对象 private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -97,6 +80,7 @@ public class SqlData { mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } + // 设置内容,更新内部状态和ContentValues public void setContent(JSONObject js) throws JSONException { long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; if (mIsCreate || mDataId != dataId) { @@ -130,6 +114,7 @@ public class SqlData { mDataContentData3 = dataContentData3; } + // 获取当前数据的内容,封装为JSONObject public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); @@ -144,6 +129,7 @@ public class SqlData { return js; } + // 提交更改到数据库 public void commit(long noteId, boolean validateVersion, long version) { if (mIsCreate) { @@ -167,7 +153,7 @@ public class SqlData { Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); } else { result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, + Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.VERSION + "=?)", new String[] { String.valueOf(noteId), String.valueOf(version) @@ -183,7 +169,8 @@ public class SqlData { mIsCreate = false; } + // 获取当前数据的ID public long getId() { return mDataId; } -} +} \ No newline at end of file