From 4f9ecbf0868cddff4a0ee49dcbc1aacc995e9187 Mon Sep 17 00:00:00 2001 From: zjb <2152698745@qq.com> Date: Sun, 10 Nov 2024 10:49:23 +0800 Subject: [PATCH] zhushi --- .../java/net/micode/notes/data/Contact.java | 65 ++-- .../java/net/micode/notes/data/Notes.java | 299 ++++----------- .../notes/data/NotesDatabaseHelper.java | 348 +++++++++++------- .../net/micode/notes/gtask/data/MetaData.java | 51 +-- .../net/micode/notes/gtask/data/Node.java | 60 ++- .../net/micode/notes/gtask/data/SqlData.java | 74 ++-- .../net/micode/notes/gtask/data/SqlNote.java | 113 ++++-- .../net/micode/notes/gtask/data/Task.java | 64 +++- .../net/micode/notes/gtask/data/TaskList.java | 110 +++--- .../exception/ActionFailureException.java | 21 +- .../exception/NetworkFailureException.java | 24 +- .../notes/gtask/remote/GTaskASyncTask.java | 60 ++- .../java/net/micode/notes/model/Note.java | 45 ++- .../net/micode/notes/model/WorkingNote.java | 165 ++++++--- 14 files changed, 795 insertions(+), 704 deletions(-) diff --git a/Src/app/src/main/java/net/micode/notes/data/Contact.java b/Src/app/src/main/java/net/micode/notes/data/Contact.java index 45ad20d..181842a 100644 --- a/Src/app/src/main/java/net/micode/notes/data/Contact.java +++ b/Src/app/src/main/java/net/micode/notes/data/Contact.java @@ -5,14 +5,14 @@ package net.micode.notes.data; -import android.content.Context; -import android.database.Cursor; -import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Data; -import android.telephony.PhoneNumberUtils; -import android.util.Log; +import android.content.Context; // 导入Context类,用于访问应用程序的环境信息 +import android.database.Cursor; // 导入Cursor类,用于遍历查询结果 +import android.provider.ContactsContract.CommonDataKinds.Phone; // 导入电话号码常量 +import android.provider.ContactsContract.Data; // 导入数据常量 +import android.telephony.PhoneNumberUtils; // 导入电话号码工具类 +import android.util.Log; // 导入Log类,用于记录日志 -import java.util.HashMap; +import java.util.HashMap; // 导入HashMap类,用于缓存联系人信息 public class Contact { // 缓存已查询过的电话号码和对应的联系人名称,以减少数据库查询次数。 @@ -20,13 +20,16 @@ public class Contact { private static final String TAG = "Contact"; // 日志标签 // 用于查询具有完整国际号码格式的电话号码的selection字符串。 - private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER - + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" - + " AND " + Data.RAW_CONTACT_ID + " IN " - + "(SELECT raw_contact_id " - + " FROM phone_lookup" - + " WHERE min_match = '+')"; + private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER //static final表明这个静态常量共享于整个类,不可更改 + + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"//+用于拼接字符串,Data.MIMETYPE表示数据的MIME类型,也就是后面的Phone.CONTENT_ITEM_TYPE电话号码数据,确保了查询信息只有电话号码 + + " AND " + Data.RAW_CONTACT_ID + " IN "//Data.RAW_CONTACT_ID表示原始联系人的唯一ID,IN用于判断某个值是否在给定的集合中 + + "(SELECT raw_contact_id "//这是一个嵌套查询,它将返回符合条件的 raw_contact_id 列表 + + " FROM phone_lookup"//指定查询的数据表 + + " WHERE min_match = '+')";//确保只选择那些包含完整国际号码格式(以 + 开头)的联系人 +/**最终的效果是输入一个电话号码后,系统能够查找到对应的联系人,并返 + * 回其完整的联系信息。这个过程不仅能准确查找联系人,还能确保查询的 + * 号码格式是正确的,从而提高匹配的准确性。*/ /** * 根据电话号码获取联系人名称。 * @@ -37,44 +40,44 @@ public class Contact { public static String getContact(Context context, String phoneNumber) { // 初始化或获取联系人缓存 if (sContactCache == null) { - sContactCache = new HashMap(); + sContactCache = new HashMap(); // 创建缓存对象 } - // 从缓存中直接获取联系人名称,如果存在。 + // 如果存在,从缓存中直接获取联系人名称 if (sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); + return sContactCache.get(phoneNumber); // 返回缓存中的联系人名称 } // 使用PhoneNumberUtils将电话号码格式化为适合查询的形式 String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); // 替换selection中的占位符 // 执行查询以获取与电话号码相关联的联系人名称 Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, - new String[]{Phone.DISPLAY_NAME}, - selection, - new String[]{phoneNumber}, - null); + Data.CONTENT_URI, // 查询的URI + new String[]{Phone.DISPLAY_NAME}, // 查询的列 + selection, // 查询条件 + new String[]{phoneNumber}, // 查询参数 + null); // 排序条件 - if (cursor != null && cursor.moveToFirst()) { + if (cursor != null && cursor.moveToFirst()) { // 确保游标不为空且移动到第一条记录 try { // 从查询结果中获取联系人名称并加入缓存 - String name = cursor.getString(0); - sContactCache.put(phoneNumber, name); - return name; + String name = cursor.getString(0); // 获取第一列的值,即联系人名称 + sContactCache.put(phoneNumber, name); // 将名称缓存 + return name; // 返回联系人名称 } catch (IndexOutOfBoundsException e) { // 处理查询结果异常 - Log.e(TAG, " Cursor get string error " + e.toString()); - return null; + Log.e(TAG, " Cursor get string error " + e.toString()); // 记录错误日志 + return null; // 返回null } finally { - // 关闭游标 + // 关闭游标以释放资源 cursor.close(); } } else { // 如果查询无结果,记录日志 - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; + Log.d(TAG, "No contact matched with number:" + phoneNumber); // 记录未找到联系人日志 + return null; // 返回null } } } diff --git a/Src/app/src/main/java/net/micode/notes/data/Notes.java b/Src/app/src/main/java/net/micode/notes/data/Notes.java index 226763b..3e85bfe 100644 --- a/Src/app/src/main/java/net/micode/notes/data/Notes.java +++ b/Src/app/src/main/java/net/micode/notes/data/Notes.java @@ -18,256 +18,109 @@ package net.micode.notes.data; import android.net.Uri; -// Notes类定义了与笔记和文件夹相关的常量和数据列接口 +// Notes类:定义了与笔记和文件夹管理相关的常量和数据列接口 public class Notes { - public static final String AUTHORITY = "micode_notes"; // 用于标识内容提供者的授权名称 - public static final String TAG = "Notes"; // 日志标签 - public static final int TYPE_NOTE = 0; // 笔记类型 - public static final int TYPE_FOLDER = 1; // 文件夹类型 - public static final int TYPE_SYSTEM = 2; // 系统类型 + // AUTHORITY用于标识内容提供者的授权名称 + public static final String AUTHORITY = "micode_notes"; + // TAG用于日志输出中的标签 + public static final String TAG = "Notes"; + + // 笔记、文件夹和系统类型的常量定义 + public static final int TYPE_NOTE = 0; + public static final int TYPE_FOLDER = 1; + public static final int TYPE_SYSTEM = 2; /** - * 下面的ID是系统文件夹的标识符 - * {@link Notes#ID_ROOT_FOLDER} 是默认文件夹 - * {@link Notes#ID_TEMPARAY_FOLDER} 是属于没有文件夹的笔记 - * {@link Notes#ID_CALL_RECORD_FOLDER} 是用于存储通话记录的 + * 系统文件夹的ID定义: + * - ID_ROOT_FOLDER是根文件夹 + * - ID_TEMPARAY_FOLDER用于未分类的临时笔记 + * - ID_CALL_RECORD_FOLDER用于存储通话记录 */ - public static final int ID_ROOT_FOLDER = 0; // 根文件夹ID - public static final int ID_TEMPARAY_FOLDER = -1; // 临时文件夹ID,用于存放不属于任何文件夹的笔记 - public static final int ID_CALL_RECORD_FOLDER = -2; // 通话记录文件夹ID + public static final int ID_ROOT_FOLDER = 0; + public static final int ID_TEMPARAY_FOLDER = -1; + public static final int ID_CALL_RECORD_FOLDER = -2; public static final int ID_TRASH_FOLER = -3; // 垃圾箱文件夹ID - public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; // 用于Intent的提醒日期额外数据 - public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; // 笔记背景色ID - public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; // 小部件ID - public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; // 小部件类型 - public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; // 文件夹ID - public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; // 通话日期 + // 定义Intent传递的额外信息,用于笔记提醒、背景色、小部件ID等 + public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; + public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; + public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; + public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type"; + public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; + public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; - public static final int TYPE_WIDGET_INVALIDE = -1; // 无效的小部件类型 - public static final int TYPE_WIDGET_2X = 0; // 2x小部件类型 - public static final int TYPE_WIDGET_4X = 1; // 4x小部件类型 + // 小部件类型常量 + public static final int TYPE_WIDGET_INVALIDE = -1; // 无效类型 + public static final int TYPE_WIDGET_2X = 0; // 2x小部件 + public static final int TYPE_WIDGET_4X = 1; // 4x小部件 + // DataConstants类:定义笔记和通话记录的内容项类型 public static class DataConstants { - public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; // 笔记的内容项类型 - public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; // 通话记录的内容项类型 + public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; // 笔记类型 + public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; // 通话记录类型 } /** - * 查询所有笔记和文件夹的Uri + * CONTENT_NOTE_URI:查询所有笔记和文件夹的URI */ public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); /** - * 查询数据的Uri + * CONTENT_DATA_URI:查询数据的URI */ public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); - // 笔记和文件夹的公共列接口 + // NoteColumns接口:定义笔记和文件夹的公共列 public interface NoteColumns { - /** - * 行的唯一ID - *

类型: INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * 笔记或文件夹的父ID - *

类型: INTEGER (long)

- */ - public static final String PARENT_ID = "parent_id"; - - /** - * 创建日期 - *

类型: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * 最后修改日期 - *

类型: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - /** - * 提醒日期 - *

类型: INTEGER (long)

- */ - public static final String ALERTED_DATE = "alert_date"; - - /** - * 笔记或文件夹的摘要信息 - *

类型: TEXT

- */ - public static final String SNIPPET = "snippet"; - - /** - * 笔记的小部件ID - *

类型: INTEGER (long)

- */ - public static final String WIDGET_ID = "widget_id"; - - /** - * 笔记的小部件类型 - *

类型: INTEGER (long)

- */ - public static final String WIDGET_TYPE = "widget_type"; - - /** - * 笔记的背景色ID - *

类型: INTEGER (long)

- */ - public static final String BG_COLOR_ID = "bg_color_id"; - - /** - * 笔记是否有附件 - *

类型: INTEGER

- */ - public static final String HAS_ATTACHMENT = "has_attachment"; - - /** - * 笔记数量 - *

类型: INTEGER (long)

- */ - public static final String NOTES_COUNT = "notes_count"; - - /** - * 文件夹类型:0-笔记,1-文件夹 - *

类型: INTEGER

- */ - public static final String TYPE = "type"; - - /** - * 最后同步ID - *

类型: INTEGER (long)

- */ - public static final String SYNC_ID = "sync_id"; - - /** - * 标记本地是否已修改 - *

类型: INTEGER

- */ - public static final String LOCAL_MODIFIED = "local_modified"; - - /** - * 移入临时文件夹前的原始父ID - *

类型: INTEGER

- */ - public static final String ORIGIN_PARENT_ID = "origin_parent_id"; - - /** - * Google任务ID - *

类型: TEXT

- */ - public static final String GTASK_ID = "gtask_id"; - - /** - * 版本号 - *

类型: INTEGER (long)

- */ - public static final String VERSION = "version"; + public static final String ID = "_id"; // 唯一ID (类型: INTEGER) + public static final String PARENT_ID = "parent_id"; // 父ID (类型: INTEGER) + public static final String CREATED_DATE = "created_date"; // 创建日期 (类型: INTEGER) + public static final String MODIFIED_DATE = "modified_date"; // 最后修改日期 (类型: INTEGER) + public static final String ALERTED_DATE = "alert_date"; // 提醒日期 (类型: INTEGER) + public static final String SNIPPET = "snippet"; // 摘要信息 (类型: TEXT) + public static final String WIDGET_ID = "widget_id"; // 小部件ID (类型: INTEGER) + public static final String WIDGET_TYPE = "widget_type"; // 小部件类型 (类型: INTEGER) + public static final String BG_COLOR_ID = "bg_color_id"; // 背景色ID (类型: INTEGER) + public static final String HAS_ATTACHMENT = "has_attachment"; // 是否有附件 (类型: INTEGER) + public static final String NOTES_COUNT = "notes_count"; // 笔记数量 (类型: INTEGER) + public static final String TYPE = "type"; // 文件夹类型 (类型: INTEGER) + public static final String SYNC_ID = "sync_id"; // 同步ID (类型: INTEGER) + public static final String LOCAL_MODIFIED = "local_modified"; // 本地是否修改 (类型: INTEGER) + public static final String ORIGIN_PARENT_ID = "origin_parent_id"; // 原始父ID (类型: INTEGER) + public static final String GTASK_ID = "gtask_id"; // Google任务ID (类型: TEXT) + public static final String VERSION = "version"; // 版本号 (类型: INTEGER) } - // 数据列接口 + // DataColumns接口:定义数据列 public interface DataColumns { - /** - * 行的唯一ID - *

类型: INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * 该项的MIME类型。 - *

类型: TEXT

- */ - public static final String MIME_TYPE = "mime_type"; - - /** - * 属于的笔记的引用ID - *

类型: INTEGER (long)

- */ - public static final String NOTE_ID = "note_id"; - - /** - * 创建日期 - *

类型: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * 最后修改日期 - *

类型: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - /** - * 数据内容 - *

类型: TEXT

- */ - public static final String CONTENT = "content"; - - /** - * 通用数据列,具体含义由{@link #MIME_TYPE}决定,用于存储整型数据 - *

类型: INTEGER

- */ - public static final String DATA1 = "data1"; - - /** - * 通用数据列,具体含义由{@link #MIME_TYPE}决定,用于存储整型数据 - *

类型: INTEGER

- */ - public static final String DATA2 = "data2"; - - /** - * 通用数据列,具体含义由{@link #MIME_TYPE}决定,用于存储文本数据 - *

类型: TEXT

- */ - public static final String DATA3 = "data3"; - - /** - * 通用数据列,具体含义由{@link #MIME_TYPE}决定,用于存储文本数据 - *

类型: TEXT

- */ - public static final String DATA4 = "data4"; - - /** - * 通用数据列,具体含义由{@link #MIME_TYPE}决定,用于存储文本数据 - *

类型: TEXT

- */ - public static final String DATA5 = "data5"; + public static final String ID = "_id"; // 唯一ID (类型: INTEGER) + public static final String MIME_TYPE = "mime_type"; // MIME类型 (类型: TEXT) + public static final String NOTE_ID = "note_id"; // 关联的笔记ID (类型: INTEGER) + public static final String CREATED_DATE = "created_date"; // 创建日期 (类型: INTEGER) + public static final String MODIFIED_DATE = "modified_date"; // 修改日期 (类型: INTEGER) + public static final String CONTENT = "content"; // 数据内容 (类型: TEXT) + public static final String DATA1 = "data1"; // 通用数据列 (类型: INTEGER) + public static final String DATA2 = "data2"; // 通用数据列 (类型: INTEGER) + public static final String DATA3 = "data3"; // 通用数据列 (类型: TEXT) + public static final String DATA4 = "data4"; // 通用数据列 (类型: TEXT) + public static final String DATA5 = "data5"; // 通用数据列 (类型: TEXT) } - // 文本笔记类,实现了DataColumns接口 + // TextNote类:实现DataColumns接口,定义了文本笔记的结构和相关常量 public static final class TextNote implements DataColumns { - /** - * 模式,指示文本是否在检查列表模式中 - *

类型: INTEGER 1:检查列表模式 0: 正常模式

- */ - public static final String MODE = DATA1; - - public static final int MODE_CHECK_LIST = 1; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; // MIME类型定义 - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; // 单项MIME类型定义 - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); // 内容URI定义 + public static final String MODE = DATA1; // 模式:是否为检查列表模式 (类型: INTEGER) + public static final int MODE_CHECK_LIST = 1; // 检查列表模式标识 + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; // MIME类型 (文本笔记) + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; // 单项MIME类型 + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); // 内容URI } - // 通话记录笔记类,实现了DataColumns接口 + // CallNote类:实现DataColumns接口,定义了通话记录笔记的结构和相关常量 public static final class CallNote implements DataColumns { - /** - * 通话日期 - *

类型: INTEGER (long)

- */ - public static final String CALL_DATE = DATA1; - - /** - * 电话号码 - *

类型: TEXT

- */ - public static final String PHONE_NUMBER = DATA3; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; // MIME类型定义 - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; // 单项MIME类型定义 - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); // 内容URI定义 + public static final String CALL_DATE = DATA1; // 通话日期 (类型: INTEGER) + public static final String PHONE_NUMBER = DATA3; // 电话号码 (类型: TEXT) + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; // MIME类型 (通话记录) + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; // 单项MIME类型 + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); // 内容URI } -} +} \ No newline at end of file diff --git a/Src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/Src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java index 67ad506..5c6ce2b 100644 --- a/Src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java +++ b/Src/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java @@ -1,6 +1,8 @@ /* - * 该类为Notes数据库的辅助类,负责管理数据库的创建和版本管理。 + * NotesDatabaseHelper类是用于管理Notes数据库的辅助类,负责数据库的创建和版本管理。 + * 继承了SQLiteOpenHelper,定义了数据库的表结构、触发器及其管理逻辑。 */ + package net.micode.notes.data; import android.content.ContentValues; @@ -13,71 +15,69 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; - public class NotesDatabaseHelper extends SQLiteOpenHelper { // 数据库名称 private static final String DB_NAME = "note.db"; - // 数据库版本号 + // 数据库版本号,用于判断数据库结构是否需要升级 private static final int DB_VERSION = 4; - // 表接口,定义了数据库中的两个表名 + // 表接口,定义了数据库中两个主要表的表名:NOTE和DATA public interface TABLE { - public static final String NOTE = "note"; - - public static final String DATA = "data"; + public static final String NOTE = "note"; // 存储笔记信息 + public static final String DATA = "data"; // 存储笔记内容的数据表 } - // 日志标签 + // 日志标签,用于输出调试信息 private static final String TAG = "NotesDatabaseHelper"; // 单例模式,确保数据库辅助类的唯一实例 private static NotesDatabaseHelper mInstance; - // 创建NOTE表的SQL语句 + // SQL语句:创建NOTE表 private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + - NoteColumns.ID + " INTEGER PRIMARY KEY," + - NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + - NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + - NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + + NoteColumns.ID + " INTEGER PRIMARY KEY," + // 笔记唯一ID + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + // 父文件夹ID + NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + // 提醒日期 + NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + // 背景颜色ID + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期 + NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +// 是否有附件 + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期 + NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + // 文件夹内笔记数量 + NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + // 笔记摘要 + NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + // 笔记类型 + NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + // 小部件ID + NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + // 小部件类型 + NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + // 同步ID + NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +// 本地是否已修改 + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +// 原始父ID + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + // Google任务ID + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + // 笔记版本号 ")"; - // 创建DATA表的SQL语句 + // SQL语句:创建DATA表 private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + - DataColumns.ID + " INTEGER PRIMARY KEY," + - DataColumns.MIME_TYPE + " TEXT NOT NULL," + - DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + - NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + - DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA1 + " INTEGER," + - DataColumns.DATA2 + " INTEGER," + - DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + - DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + + DataColumns.ID + " INTEGER PRIMARY KEY," + // 数据项唯一ID + DataColumns.MIME_TYPE + " TEXT NOT NULL," + // 数据项的MIME类型 + DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + // 关联的NOTE表ID + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 创建日期 + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + // 修改日期 + DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + // 内容 + DataColumns.DATA1 + " INTEGER," + // 通用数据列1 + DataColumns.DATA2 + " INTEGER," + // 通用数据列2 + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + // 通用数据列3 + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + // 通用数据列4 + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + // 通用数据列5 ")"; - // 创建DATA表的NOTE_ID索引的SQL语句 + // SQL语句:创建DATA表的NOTE_ID字段的索引,提高查询效率 private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; - // 当更新NOTE表中的PARENT_ID字段时,增加目标文件夹的NOTE_COUNT + // 触发器:在更改NOTE表中PARENT_ID字段时,增加目标文件夹的NOTES_COUNT private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER increase_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + @@ -87,7 +87,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END"; - // 当从文件夹移动NOTE时,减少源文件夹的NOTE_COUNT + // 触发器:在更改NOTE表中PARENT_ID字段时,减少源文件夹的NOTES_COUNT private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + @@ -98,7 +98,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " END"; - // 当插入新NOTE时,增加目标文件夹的NOTE_COUNT + // 触发器:在NOTE表插入新记录时,增加目标文件夹的NOTES_COUNT private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + " AFTER INSERT ON " + TABLE.NOTE + @@ -108,7 +108,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END"; - // 当删除NOTE时,减少文件夹的NOTE_COUNT + // 触发器:在NOTE表删除记录时,减少文件夹的NOTES_COUNT private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -119,7 +119,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " AND " + NoteColumns.NOTES_COUNT + ">0;" + " END"; - // 当插入DATA时,如果类型为NOTE,则更新关联NOTE的内容 + // 触发器:在DATA表插入新记录时,若MIME类型为NOTE,更新NOTE表的SNIPPET内容 private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + " AFTER INSERT ON " + TABLE.DATA + @@ -130,7 +130,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END"; - // 当更新DATA时,如果类型为NOTE,则更新关联NOTE的内容 + // 触发器:在DATA表更新记录时,若MIME类型为NOTE,更新NOTE表的SNIPPET内容 private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + " AFTER UPDATE ON " + TABLE.DATA + @@ -141,7 +141,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END"; - // 当删除DATA时,如果类型为NOTE,则更新关联NOTE的内容为空 + // 触发器:在DATA表删除记录时,若MIME类型为NOTE,清空NOTE表的SNIPPET内容 private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + " AFTER delete ON " + TABLE.DATA + @@ -152,7 +152,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " END"; - // 当删除NOTE时,删除关联的DATA + // 触发器:在NOTE表删除记录时,删除关联的所有DATA记录 private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -161,7 +161,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + " END"; - // 当删除NOTE时,删除属于该NOTE的子NOTE + // 触发器:在NOTE表删除文件夹记录时,删除该文件夹内的所有子NOTE记录 private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -170,7 +170,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END"; - // 当NOTE移动到回收站文件夹时,将所有子NOTE也移动到回收站 + // 触发器:在NOTE表更新记录时,若目标为回收站,将所有子NOTE也移入回收站 private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + " AFTER UPDATE ON " + TABLE.NOTE + @@ -181,6 +181,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END"; + /** * 构造函数,私有化以防止外部实例化 * @@ -190,199 +191,264 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { super(context, DB_NAME, null, DB_VERSION); } - /** + /* * 创建NOTE表,并重新创建NOTE表的触发器,然后创建系统文件夹 * * @param db SQLiteDatabase对象,用于执行SQL创建语句 */ + + /** + * 创建NOTE表,并为该表重新创建触发器和系统文件夹。 + * + * @param db SQLiteDatabase对象,用于执行SQL创建语句 + */ public void createNoteTable(SQLiteDatabase db) { + // 执行SQL语句创建NOTE表,定义表结构及默认值 db.execSQL(CREATE_NOTE_TABLE_SQL); + + // 重新创建NOTE表的相关触发器,以确保数据完整性和联动效果 reCreateNoteTableTriggers(db); + + // 创建系统文件夹,例如根文件夹、临时文件夹和回收站,以便分类管理笔记 createSystemFolder(db); + + // 输出调试信息,确认NOTE表已创建成功 Log.d(TAG, "note table has been created"); } + /** * 重新创建笔记表的触发器 * * @param db SQLiteDatabase 类型,数据库对象 */ + /* + * 删除旧的触发器并重新创建NOTE表的触发器,以确保表的完整性和数据一致性。 + * 每个触发器用于在特定操作(如插入、更新或删除)时自动维护NOTE表和相关数据表的关联逻辑。 + * + * @param db SQLiteDatabase对象,用于执行触发器的SQL语句 + */ private void reCreateNoteTableTriggers(SQLiteDatabase db) { - // 删除旧的触发器 - db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); - // 创建新的触发器 - db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); - db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); - db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); - db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER); - db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); - db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); - db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); + // 删除旧的触发器,以确保不会重复创建触发器或造成冲突 + db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); // 删除当更新文件夹时增加计数的触发器 + db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); // 删除当更新文件夹时减少计数的触发器 + db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); // 删除当删除笔记时减少计数的触发器 + db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete"); // 删除当删除笔记时删除相关数据的触发器 + db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert"); // 删除当插入新笔记时增加计数的触发器 + db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); // 删除当删除文件夹时删除其子笔记的触发器 + db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); // 删除当文件夹被移至回收站时移动其子笔记的触发器 + + // 创建新的触发器,以确保数据完整性和联动效果 + db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); // 创建更新时增加文件夹计数的触发器 + db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); // 创建更新时减少文件夹计数的触发器 + db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); // 创建删除时减少文件夹计数的触发器 + db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER); // 创建删除笔记时删除关联数据的触发器 + db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); // 创建插入新笔记时增加文件夹计数的触发器 + db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); // 创建删除文件夹时删除其子笔记的触发器 + db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); // 创建移动文件夹至回收站时移动子笔记的触发器 } /** - * 创建系统文件夹 + * 创建系统文件夹,用于组织和分类笔记。这些文件夹包括: + * - 通话记录文件夹 + * - 根文件夹(默认文件夹) + * - 临时文件夹(用于移动笔记) + * - 回收站文件夹 + * 这些文件夹用于支持系统中不同类型的笔记分类管理。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行插入操作 */ private void createSystemFolder(SQLiteDatabase db) { - ContentValues values = new ContentValues(); - // 创建通话记录文件夹 - values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - // 创建根文件夹(默认文件夹) - values.clear(); - values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - // 创建临时文件夹,用于移动笔记 - values.clear(); - values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); - // 创建回收站文件夹 - values.clear(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + ContentValues values = new ContentValues(); // 创建ContentValues对象用于存储列值 + + // 创建通话记录文件夹,保存与通话记录相关的笔记 + values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); // 设置通话记录文件夹的ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统文件夹 + db.insert(TABLE.NOTE, null, values); // 插入通话记录文件夹到NOTE表 + + // 创建根文件夹(默认文件夹),用于存放笔记 + values.clear(); // 清空ContentValues以重用 + values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); // 设置根文件夹的ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统文件夹 + db.insert(TABLE.NOTE, null, values); // 插入根文件夹到NOTE表 + + // 创建临时文件夹,用于存放未归类的笔记或移动中的笔记 + values.clear(); // 清空ContentValues以重用 + values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); // 设置临时文件夹的ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统文件夹 + db.insert(TABLE.NOTE, null, values); // 插入临时文件夹到NOTE表 + + // 创建回收站文件夹,用于存放已删除的笔记 + values.clear(); // 清空ContentValues以重用 + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); // 设置回收站文件夹的ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置文件夹类型为系统文件夹 + db.insert(TABLE.NOTE, null, values); // 插入回收站文件夹到NOTE表 } + /** - * 创建数据表 + * 创建DATA表,并为该表重新创建触发器和索引。 + * DATA表用于存储笔记的具体内容和关联信息。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行SQL语句 */ public void createDataTable(SQLiteDatabase db) { + // 执行SQL语句创建DATA表,定义表的结构和字段 db.execSQL(CREATE_DATA_TABLE_SQL); + + // 重新创建DATA表的触发器,以确保表的数据一致性和触发器的最新定义 reCreateDataTableTriggers(db); + + // 创建NOTE_ID索引,提高与NOTE表的关联查询效率 db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); + + // 输出调试信息,确认DATA表已创建成功 Log.d(TAG, "data table has been created"); } + /** - * 重新创建数据表的触发器 + * 删除旧的触发器并重新创建DATA表的触发器,以确保表的完整性和数据的一致性。 + * 这些触发器用于在数据插入、更新或删除时,自动更新与DATA表关联的NOTE表内容。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行SQL语句 */ private void reCreateDataTableTriggers(SQLiteDatabase db) { - // 删除旧的触发器 - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); - // 创建新的触发器 - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); + // 删除旧的触发器,确保重新创建时不会出现重复定义的问题 + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); // 删除插入操作触发器 + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); // 删除更新操作触发器 + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); // 删除删除操作触发器 + + // 创建新的触发器,用于管理DATA表和NOTE表之间的关联数据同步 + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); // 当DATA表插入新记录时更新NOTE表内容 + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); // 当DATA表更新记录时更新NOTE表内容 + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); // 当DATA表删除记录时清空NOTE表内容 } + /** - * 获取 NotesDatabaseHelper 的单例对象 + * 获取 NotesDatabaseHelper 的单例对象。单例模式确保整个应用中只有一个数据库连接实例, + * 避免多次创建实例造成的资源浪费和数据不一致问题。 * - * @param context Context 类型,应用上下文 - * @return NotesDatabaseHelper 类型,单例对象 + * @param context Context类型,应用上下文,用于初始化数据库 + * @return NotesDatabaseHelper类型的单例对象 */ static synchronized NotesDatabaseHelper getInstance(Context context) { + // 检查是否已有实例 if (mInstance == null) { + // 如果实例为空,则创建新的 NotesDatabaseHelper 实例 mInstance = new NotesDatabaseHelper(context); } + // 返回唯一实例 return mInstance; } + /** - * 创建数据库表 + * 创建数据库表的方法。当数据库首次创建时自动调用,用于初始化数据库结构。 + * 此方法创建NOTE表和DATA表,并为它们配置触发器和系统文件夹。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行表创建的SQL语句 */ @Override public void onCreate(SQLiteDatabase db) { + // 调用createNoteTable方法,创建NOTE表,并配置相关触发器和系统文件夹 createNoteTable(db); + + // 调用createDataTable方法,创建DATA表,并配置相关触发器和索引 createDataTable(db); } + /** - * 升级数据库 + * 升级数据库的方法。当检测到数据库版本号发生变化时,系统自动调用此方法,根据旧版本号逐步升级数据库结构。 + * 此方法根据数据库的旧版本逐步调用不同版本的升级方法,并在必要时重新创建触发器。 * - * @param db SQLiteDatabase 类型,数据库对象 - * @param oldVersion int 类型,旧版本号 - * @param newVersion int 类型,新版本号 + * @param db SQLiteDatabase对象,用于执行SQL语句 + * @param oldVersion int类型,数据库的旧版本号 + * @param newVersion int类型,数据库的新版本号 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - boolean reCreateTriggers = false; - boolean skipV2 = false; - // 根据旧版本号逐步升级 + boolean reCreateTriggers = false; // 标记是否需要重新创建触发器 + boolean skipV2 = false; // 标记是否需要跳过版本2的升级 + + // 检查并按顺序执行版本升级 if (oldVersion == 1) { - upgradeToV2(db); - skipV2 = true; // 这次升级包括从 v2 到 v3 的升级 + upgradeToV2(db); // 从版本1升级到版本2 + skipV2 = true; // 跳过后续升级到版本2的操作 oldVersion++; } if (oldVersion == 2 && !skipV2) { - upgradeToV3(db); - reCreateTriggers = true; + upgradeToV3(db); // 从版本2升级到版本3 + reCreateTriggers = true; // 设置标记为true,表示需要重新创建触发器 oldVersion++; } if (oldVersion == 3) { - upgradeToV4(db); + upgradeToV4(db); // 从版本3升级到版本4 oldVersion++; } + + // 如果升级过程中需要重新创建触发器,则调用方法重新创建NOTE表和DATA表的触发器 if (reCreateTriggers) { - reCreateNoteTableTriggers(db); - reCreateDataTableTriggers(db); + reCreateNoteTableTriggers(db); // 重新创建NOTE表的触发器 + reCreateDataTableTriggers(db); // 重新创建DATA表的触发器 } + + // 检查是否所有升级已成功完成,如果未完成则抛出异常 if (oldVersion != newVersion) { - throw new IllegalStateException("Upgrade notes database to version " + newVersion - + "fails"); + throw new IllegalStateException("Upgrade notes database to version " + newVersion + " fails"); } } + /** - * 从版本1升级到版本2 + * 从版本1升级到版本2的方法。此升级步骤删除旧表并重新创建NOTE表和DATA表, + * 以确保结构更新并清除旧数据。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行SQL操作 */ private void upgradeToV2(SQLiteDatabase db) { - // 删除旧表,创建新表 - db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); - db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); + // 删除旧的NOTE表和DATA表,确保版本2的结构重新定义 + db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); // 删除NOTE表 + db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); // 删除DATA表 + + // 重新创建NOTE表和DATA表,应用最新的结构和默认数据 createNoteTable(db); createDataTable(db); } /** - * 从版本2升级到版本3 + * 从版本2升级到版本3的方法。此升级步骤删除未使用的触发器,添加新字段,以及创建回收站系统文件夹。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行SQL操作 */ private void upgradeToV3(SQLiteDatabase db) { - // 删除未使用的触发器 - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); - // 添加一个用于 gtask id 的列 + // 删除未使用的触发器,确保数据库结构的简洁和更新 + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); // 删除插入触发器 + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete"); // 删除删除触发器 + db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update"); // 删除更新触发器 + + // 添加新的字段,用于存储Google任务ID,方便同步外部任务 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''"); - // 添加一个回收站系统文件夹 + + // 添加一个回收站系统文件夹,专门用于存储已删除的笔记 ContentValues values = new ContentValues(); - values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); - values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); // 设置回收站文件夹的ID + values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 设置类型为系统文件夹 + db.insert(TABLE.NOTE, null, values); // 插入回收站文件夹到NOTE表 } /** - * 从版本3升级到版本4 + * 从版本3升级到版本4的方法。此升级步骤为NOTE表添加版本号列,用于跟踪笔记的版本。 * - * @param db SQLiteDatabase 类型,数据库对象 + * @param db SQLiteDatabase对象,用于执行SQL操作 */ private void upgradeToV4(SQLiteDatabase db) { - // 添加版本号列 + // 添加新的版本号字段,用于记录笔记的版本以支持版本控制或同步机制 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0"); } -} \ No newline at end of file + +} diff --git a/Src/app/src/main/java/net/micode/notes/gtask/data/MetaData.java b/Src/app/src/main/java/net/micode/notes/gtask/data/MetaData.java index 7bbf671..9eef024 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/data/MetaData.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/data/MetaData.java @@ -1,39 +1,38 @@ /** - * MetaData类,继承自Task类,用于处理与任务相关的元数据。 + * MetaData类,继承自Task类,用于处理任务的元数据,主要涉及任务的全局ID和元信息。 + * 提供了与远程数据交互的设置和获取方法,不支持本地JSON数据的设置和同步操作。 */ package net.micode.notes.gtask.data; import android.database.Cursor; import android.util.Log; - import net.micode.notes.tool.GTaskStringUtils; - import org.json.JSONException; import org.json.JSONObject; public class MetaData extends Task { private final static String TAG = MetaData.class.getSimpleName(); // 日志标签 - private String mRelatedGid = null; // 与任务相关的全局ID /** - * 设置元数据。 + * 设置任务的元数据,包含任务的全局ID和相关信息。 * * @param gid 任务的全局ID。 * @param metaInfo 元信息的JSON对象。 */ public void setMeta(String gid, JSONObject metaInfo) { try { - metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); // 将任务的全局ID添加到元信息中 + // 在元信息中添加任务的全局ID + metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { - Log.e(TAG, "failed to put related gid"); + Log.e(TAG, "无法添加相关的全局ID"); } - setNotes(metaInfo.toString()); // 将元信息设置为任务的笔记 - setName(GTaskStringUtils.META_NOTE_NAME); // 设置任务的名称为特定的元数据标志名称 + setNotes(metaInfo.toString()); // 将完整的元信息转换为字符串后存储为任务的笔记 + setName(GTaskStringUtils.META_NOTE_NAME); // 将任务名称设置为特定的元数据名称 } /** - * 获取与任务相关的全局ID。 + * 获取与任务关联的全局ID。 * * @return 相关的全局ID字符串。 */ @@ -44,7 +43,7 @@ public class MetaData extends Task { /** * 判断任务是否值得保存。 * - * @return 如果任务的笔记字段不为空,则返回true,表示值得保存。 + * @return 如果任务的笔记字段不为空,则返回true,表示任务包含信息值得保存。 */ @Override public boolean isWorthSaving() { @@ -52,54 +51,58 @@ public class MetaData extends Task { } /** - * 通过远程JSON对象设置内容。 + * 根据远程JSON对象设置任务内容。 + * 通过解析远程JSON中的笔记字段提取相关的全局ID。 * - * @param js JSON对象,包含远程任务的内容。 + * @param js 远程JSON对象,包含任务的详细信息。 */ @Override public void setContentByRemoteJSON(JSONObject js) { - super.setContentByRemoteJSON(js); + super.setContentByRemoteJSON(js); // 调用父类方法设置通用内容 if (getNotes() != null) { try { + // 从笔记中提取任务相关的全局ID JSONObject metaInfo = new JSONObject(getNotes().trim()); - mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); // 从笔记中提取相关的全局ID + mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { - Log.w(TAG, "failed to get related gid"); - mRelatedGid = null; // 提取失败时,设置相关ID为null + Log.w(TAG, "获取相关全局ID失败"); + mRelatedGid = null; // 若解析失败,相关ID设为null } } } /** - * 通过本地JSON对象设置内容。此方法不应被调用。 + * 设置任务内容为本地JSON对象,此方法不应被调用。 * * @param js 本地JSON对象。 */ @Override public void setContentByLocalJSON(JSONObject js) { - // this function should not be called - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); + // 此方法不适用于MetaData类,直接抛出异常 + throw new IllegalAccessError("MetaData:setContentByLocalJSON 不应被调用"); } /** - * 从内容生成本地JSON对象。此方法不应被调用。 + * 从内容生成本地JSON对象,此方法不应被调用。 * * @return 生成的JSON对象。 */ @Override public JSONObject getLocalJSONFromContent() { - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); + // 此方法不适用于MetaData类,直接抛出异常 + throw new IllegalAccessError("MetaData:getLocalJSONFromContent 不应被调用"); } /** - * 获取同步操作类型。此方法不应被调用。 + * 获取同步操作类型,此方法不应被调用。 * * @param c 数据库游标,指向当前任务。 * @return 同步操作的类型。 */ @Override public int getSyncAction(Cursor c) { - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); + // 此方法不适用于MetaData类,直接抛出异常 + throw new IllegalAccessError("MetaData:getSyncAction 不应被调用"); } } diff --git a/Src/app/src/main/java/net/micode/notes/gtask/data/Node.java b/Src/app/src/main/java/net/micode/notes/gtask/data/Node.java index 171da32..434dc62 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/data/Node.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/data/Node.java @@ -6,27 +6,26 @@ package net.micode.notes.gtask.data; import android.database.Cursor; - import org.json.JSONObject; -// 定义节点同步动作的常量 +// 定义节点同步动作的常量,用于区分节点的不同同步操作类型 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; // 节点是否被删除的标志 - - // 构造函数,初始化节点属性 + 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; // 节点是否被删除的标志 + + // 构造函数,初始化节点的默认属性 public Node() { mGid = null; mName = ""; @@ -34,22 +33,22 @@ public abstract class Node { mDeleted = false; } - // 生成创建节点的JSON动作 + // 抽象方法,由子类实现,生成创建节点的JSON表示 public abstract JSONObject getCreateAction(int actionId); - // 生成更新节点的JSON动作 + // 抽象方法,由子类实现,生成更新节点的JSON表示 public abstract JSONObject getUpdateAction(int actionId); - // 根据远程JSON内容设置节点内容 + // 抽象方法,由子类实现,设置节点内容为远程JSON内容 public abstract void setContentByRemoteJSON(JSONObject js); - // 根据本地JSON内容设置节点内容 + // 抽象方法,由子类实现,设置节点内容为本地JSON内容 public abstract void setContentByLocalJSON(JSONObject js); - // 从内容生成本地JSON表示 + // 抽象方法,由子类实现,从节点内容生成本地JSON对象 public abstract JSONObject getLocalJSONFromContent(); - // 根据Cursor获取同步动作 + // 抽象方法,由子类实现,根据Cursor对象获取节点的同步动作 public abstract int getSyncAction(Cursor c); // 设置节点的全局唯一标识符 @@ -57,17 +56,17 @@ public abstract class Node { this.mGid = gid; } - // 设置节点名称 + // 设置节点的名称 public void setName(String name) { this.mName = name; } - // 设置节点最后修改时间 + // 设置节点的最后修改时间戳 public void setLastModified(long lastModified) { this.mLastModified = lastModified; } - // 设置节点是否被删除 + // 设置节点的删除状态 public void setDeleted(boolean deleted) { this.mDeleted = deleted; } @@ -77,19 +76,18 @@ public abstract class Node { return this.mGid; } - // 获取节点名称 + // 获取节点的名称 public String getName() { return this.mName; } - // 获取节点最后修改时间 + // 获取节点的最后修改时间戳 public long getLastModified() { return this.mLastModified; } - // 获取节点是否被删除的标志 + // 获取节点的删除状态 public boolean getDeleted() { return this.mDeleted; } - } diff --git a/Src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/Src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index 7381072..2928d60 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -1,7 +1,8 @@ /* * SqlData 类用于操作和管理数据库中的数据项。 - * 提供了从 JSON 对象设置内容,从数据库 Cursor 加载数据,以及提交数据更新到数据库的功能。 + * 提供从 JSON 对象设置内容,从数据库 Cursor 加载数据,以及提交数据更新到数据库的功能。 */ + package net.micode.notes.gtask.data; import android.content.ContentResolver; @@ -22,53 +23,46 @@ import net.micode.notes.gtask.exception.ActionFailureException; 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 }; - // 字段在Cursor中的索引 + // 数据列在Cursor中的索引 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; - // ContentResolver用于操作内容提供者 + // ContentResolver用于操作内容提供者的接口 private ContentResolver mContentResolver; - // 标记当前对象是创建状态还是更新状态 + // 标记当前对象的状态,是新建状态还是已有状态 private boolean mIsCreate; - // 数据项ID + // 数据项的ID、MIME类型、内容、附加数据等字段 private long mDataId; - - // 数据项的MIME类型 private String mDataMimeType; - - // 数据项的内容 private String mDataContent; - - // 数据项的附加数据1 private long mDataContentData1; - - // 数据项的附加数据3 private String mDataContentData3; - // 存储与数据库不同步的数据变化 + // 存储对数据库中的数据项的未提交更改 private ContentValues mDiffDataValues; /* - * SqlData 构造函数,用于创建新的数据项。 + * 构造函数,用于创建新的数据项。 + * 初始化数据项为默认值,并标记为创建状态。 + * * @param context 上下文对象,用于获取ContentResolver。 */ public SqlData(Context context) { @@ -83,7 +77,9 @@ public class SqlData { } /* - * SqlData 构造函数,用于加载现有数据项。 + * 构造函数,用于加载已存在的数据库项。 + * 通过Cursor加载数据并标记为更新状态。 + * * @param context 上下文对象,用于获取ContentResolver。 * @param c 数据项的Cursor对象,用于加载数据。 */ @@ -95,7 +91,8 @@ public class SqlData { } /* - * 从Cursor中加载数据。 + * 从Cursor中加载数据项的内容到SqlData对象。 + * * @param c 数据项的Cursor对象。 */ private void loadFromCursor(Cursor c) { @@ -107,7 +104,9 @@ public class SqlData { } /* - * 根据JSON对象设置数据项内容。 + * 根据传入的JSON对象设置数据项的内容。 + * 根据JSON字段值判断是否需要更新数据项的内容。 + * * @param js JSON对象,包含数据项的内容。 * @throws JSONException 如果解析JSON时出错。 */ @@ -145,13 +144,14 @@ public class SqlData { } /* - * 获取数据项的内容,转换为JSON对象。 - * @return JSON对象,包含数据项的内容。 + * 将数据项的内容转换为JSON对象。 + * + * @return JSON对象,包含当前数据项的内容。 * @throws JSONException 如果构建JSON对象时出错。 */ public JSONObject getContent() throws JSONException { if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); + Log.e(TAG, "尚未将数据项创建到数据库中"); return null; } JSONObject js = new JSONObject(); @@ -164,37 +164,35 @@ public class SqlData { } /* - * 将数据项提交到数据库,如果是新数据项则插入,否则更新。 + * 将数据项提交到数据库。 + * 如果数据项是新建的,则执行插入操作;否则执行更新操作。 + * * @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); } - mDiffDataValues.put(DataColumns.NOTE_ID, noteId); Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); try { 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"); + Log.e(TAG, "获取笔记ID出错: " + e.toString()); + throw new ActionFailureException("创建笔记失败"); } } 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 @@ -203,22 +201,20 @@ public class SqlData { }); } if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); + Log.w(TAG, "没有更新,可能是在同步过程中用户更新了笔记"); } } } - - // 清理并重置状态 - mDiffDataValues.clear(); - mIsCreate = false; + mDiffDataValues.clear(); // 清空待更新数据并重置状态 + mIsCreate = false; // 设置为更新状态 } /* * 获取数据项的ID。 - * @return 数据项的ID。 + * + * @return 当前数据项的ID。 */ public long getId() { return mDataId; } } - diff --git a/Src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java b/Src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java index 25b2796..b680b7b 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java @@ -152,42 +152,73 @@ public class SqlNote { /** * 构造函数,从数据库中加载指定ID的笔记。 + * 此构造函数用于初始化 `SqlNote` 对象,通过从数据库中加载指定的笔记 ID 的内容, + * 并将内容数据加载到对象的属性中。 * - * @param context 上下文,通常是指Activity或Application对象。 - * @param id 要加载的笔记的ID。 + * @param context 上下文,通常是指 Activity 或 Application 对象,用于访问应用资源和数据库内容解析器。 + * @param id 要加载的笔记的 ID,用于查询数据库中对应的笔记记录。 */ public SqlNote(Context context, long id) { + // 初始化上下文和内容解析器,用于后续数据库操作 mContext = context; mContentResolver = context.getContentResolver(); + + // 设置标志为false,表示该实例是从已有笔记加载,而非创建新的笔记 mIsCreate = false; + + // 调用辅助方法从数据库中加载指定 ID 的笔记内容,并初始化属性 loadFromCursor(id); + + // 初始化数据列表,用于存储与该笔记关联的数据项 mDataList = new ArrayList(); + + // 检查笔记类型是否为普通笔记类型 + // 如果是普通笔记类型,则加载该笔记的所有关联数据内容 if (mType == Notes.TYPE_NOTE) loadDataContent(); + + // 初始化差异值容器,用于记录该笔记对象的更改,便于后续同步或提交更新到数据库 mDiffNoteValues = new ContentValues(); } - // 从数据库中加载笔记数据 + + /** + * 从数据库中加载指定 ID 的笔记数据。 + * 该方法用于查询数据库中的笔记记录,将查询结果加载到当前 `SqlNote` 实例的属性中。 + * + * @param id 要加载的笔记的 ID。 + */ private void loadFromCursor(long id) { - Cursor c = null; + Cursor c = null; // 定义游标,用于处理数据库查询结果 try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", - new String[]{ - String.valueOf(id) - }, null); + // 执行查询,使用 ContentResolver 通过 URI 和 ID 从数据库中检索笔记信息 + c = mContentResolver.query( + Notes.CONTENT_NOTE_URI, // 笔记内容 URI + PROJECTION_NOTE, // 查询所需列的投影 + "(_id=?)", // 查询条件,指定笔记 ID + new String[]{String.valueOf(id)}, // 查询条件参数,转换为字符串格式的 ID + null // 不指定排序顺序 + ); + + // 检查查询结果是否非空,并尝试移动到第一条记录 if (c != null) { if (c.moveToNext()) { + // 调用 `loadFromCursor(Cursor)` 方法,从游标中提取数据并设置实例属性 loadFromCursor(c); } else { + // 如果查询结果为空,记录警告日志信息 Log.w(TAG, "loadFromCursor: cursor = null"); } } } finally { - if (c != null) + // 确保游标在使用完后关闭,防止资源泄露 + if (c != null) { c.close(); + } } } + // 从Cursor中加载笔记数据到实例属性 private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); @@ -206,39 +237,45 @@ public class SqlNote { /** * 加载数据内容。 - * 从数据库中查询特定note_id的数据,并将其加载到mDataList中。 + * 从数据库中查询与当前笔记(由 `note_id` 标识)相关的数据项,并将它们加载到 `mDataList` 列表中。 */ private void loadDataContent() { - Cursor c = null; - mDataList.clear(); + Cursor c = null; // 定义游标,用于处理数据库查询结果 + mDataList.clear(); // 清空现有的 `mDataList` 列表,以准备加载新的数据项 try { - // 查询指定note_id的数据 - c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, - "(note_id=?)", new String[]{ - String.valueOf(mId) - }, null); + // 执行查询,通过 URI 从数据库中检索与当前笔记 ID 关联的数据 + c = mContentResolver.query( + Notes.CONTENT_DATA_URI, // 数据内容的 URI + SqlData.PROJECTION_DATA, // 查询所需的列 + "(note_id=?)", // 查询条件,匹配当前笔记 ID + new String[]{String.valueOf(mId)}, // 查询条件参数,当前笔记 ID 的字符串表示 + null // 不指定排序顺序 + ); + + // 检查查询结果是否为空 if (c != null) { - // 如果查询结果为空,打印警告信息并返回 + // 如果查询结果为空(无数据),记录警告日志并返回 if (c.getCount() == 0) { Log.w(TAG, "it seems that the note has not data"); return; } - // 遍历查询结果,并加载到mDataList中 + // 遍历查询结果的每一行,将数据项添加到 `mDataList` 列表 while (c.moveToNext()) { - SqlData data = new SqlData(mContext, c); - mDataList.add(data); + SqlData data = new SqlData(mContext, c); // 通过 `Cursor` 创建 `SqlData` 实例 + mDataList.add(data); // 将数据项添加到 `mDataList` 列表 } } else { - // 如果查询结果为null,打印警告信息 + // 如果查询结果为 `null`,记录警告日志 Log.w(TAG, "loadDataContent: cursor = null"); } } finally { - // 释放资源 + // 确保游标在使用完后关闭,防止资源泄露 if (c != null) c.close(); } } + /** * 设置内容。 * 根据传入的JSONObject,更新或创建笔记的相关内容。 @@ -312,37 +349,41 @@ public class SqlNote { /** * 获取内容。 - * 将当前笔记的内容转换为JSONObject格式。 + * 将当前笔记的内容转换为 `JSONObject` 格式,用于数据传输或保存。 * - * @return 笔记内容的JSONObject,如果无法转换成功则返回null。 + * @return 包含笔记内容的 `JSONObject`,如果无法转换成功则返回 `null`。 */ public JSONObject getContent() { try { - JSONObject js = new JSONObject(); + JSONObject js = new JSONObject(); // 初始化一个空的 JSON 对象,用于存放笔记数据 + // 如果当前笔记尚未在数据库中创建,返回 null if (mIsCreate) { - // 如果笔记尚未在数据库中创建,返回null Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } - JSONObject note = new JSONObject(); - // 根据笔记类型,填充不同的信息到note JSONObject中 - // 该部分通过条件判断,根据mType选择需要填充的信息 + JSONObject note = new JSONObject(); // 初始化一个空的 JSON 对象,用于存放具体的笔记内容 + + // 根据笔记的类型,选择性地填充不同的数据字段到 `note` JSON 对象中 + // 如:类型为文件夹或笔记时处理的字段会有所不同 - // 将note和data信息添加到js中 - js.put(GTaskStringUtils.META_HEAD_NOTE, note); - // 处理数据项数组,将其添加到js中 + // 将 `note` 和关联的 `data` 信息添加到主 JSON 对象 `js` 中 + js.put(GTaskStringUtils.META_HEAD_NOTE, note); // 添加 `note` 到主 JSON 对象中 - return js; + // 处理 `mDataList` 数据项数组,将其逐项转换为 JSON 并添加到 `js` 中 + // 每一个数据项会被转换成 JSON 格式并包含在 `js` 中,以便完整描述当前笔记的内容 + + return js; // 返回最终生成的 JSON 对象 } catch (JSONException e) { - // 处理JSON构建异常 + // 捕获 JSON 构建过程中可能出现的异常,记录错误日志 Log.e(TAG, e.toString()); e.printStackTrace(); } - return null; + return null; // 如果出现异常或转换失败,返回 `null` } + /** * 设置父id。 * diff --git a/Src/app/src/main/java/net/micode/notes/gtask/data/Task.java b/Src/app/src/main/java/net/micode/notes/gtask/data/Task.java index 414bed0..05f6955 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/data/Task.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/data/Task.java @@ -124,44 +124,54 @@ public class Task extends Node { } /** - * 生成更新任务的JSON动作对象。 + * 生成更新任务的 JSON 动作对象。 + * 用于构建更新任务的请求 JSON 格式。 * - * @param actionId 动作ID - * @return 包含更新任务动作的JSON对象 - * @throws ActionFailureException 如果生成JSON对象失败 + * @param actionId 动作 ID,标识此更新操作的唯一编号 + * @return 包含更新任务信息的 JSON 对象,用于发送到远程服务 + * @throws ActionFailureException 如果生成 JSON 对象失败时抛出此异常 */ public JSONObject getUpdateAction(int actionId) { - JSONObject js = new JSONObject(); + JSONObject js = new JSONObject(); // 主 JSON 对象,用于存放更新任务信息 try { - // 设置动作类型为更新 + // 设置动作类型为 "更新",此字段用于标识请求的具体操作 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // 设置动作ID + // 设置动作 ID,用于唯一标识此更新动作,便于追踪请求 js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // 设置任务ID + // 设置任务的全局唯一 ID,用于远程系统识别此任务 js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // 设置任务实体信息 + // 创建任务实体信息的子 JSON 对象,包含任务的具体属性 JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 设置任务名称 + + // 如果任务包含笔记,则添加笔记字段 if (getNotes() != null) { entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); } + + // 设置任务的删除状态,若为已删除则该字段为 true entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); + + // 将任务实体信息添加到主 JSON 对象的 "entity_delta" 字段中 js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); } catch (JSONException e) { + // 如果 JSON 构建过程中出现异常,记录错误日志并抛出自定义异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to generate task-update jsonobject"); } + // 返回最终生成的 JSON 对象 return js; } + /** * 根据远程JSON对象设置任务内容。 * @@ -204,41 +214,49 @@ public class Task extends Node { } /** - * 根据本地JSON对象设置任务内容。 + * 根据本地 JSON 对象设置任务内容。 + * 该方法用于从本地 JSON 数据中解析并设置任务的具体内容。 * - * @param js 本地获取的JSON对象 - * @throws ActionFailureException 如果从JSON对象中获取内容失败 + * @param js 本地获取的 JSON 对象,包含任务的详细信息 */ public void setContentByLocalJSON(JSONObject js) { + // 检查 JSON 对象是否为 null,并检查必要的键是否存在 if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { - Log.w(TAG, "setContentByLocalJSON: nothing is available"); - return; + Log.w(TAG, "setContentByLocalJSON: nothing is available"); // 打印警告信息 + return; // 如果条件不满足,则退出方法 } try { + // 获取 JSON 对象中的 "note" 部分,包含任务的主要信息 JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + // 获取 "data" 数组部分,包含任务的相关数据 JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + // 验证任务类型是否为笔记类型 if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { - Log.e(TAG, "invalid type"); - return; + Log.e(TAG, "invalid type"); // 记录错误信息 + return; // 如果类型无效,则退出方法 } + // 遍历 "data" 数组,查找 MIME 类型为 "note" 的数据 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); + // 如果找到 MIME 类型为 NOTE 的数据项,提取内容并设置为任务名称 if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { - setName(data.getString(DataColumns.CONTENT)); - break; + setName(data.getString(DataColumns.CONTENT)); // 设置任务的名称 + break; // 找到后退出循环 } } } catch (JSONException e) { + // 如果在 JSON 解析过程中遇到异常,记录错误并打印堆栈跟踪 Log.e(TAG, e.toString()); e.printStackTrace(); } } + /** * 根据任务内容生成本地JSON对象。 * @@ -289,20 +307,26 @@ public class Task extends Node { /** * 设置任务的元信息。 + * 将给定的 `MetaData` 对象中的笔记内容转换为 JSON 格式,并存储为任务的元信息。 * - * @param metaData 元数据对象,包含任务的额外信息 + * @param metaData 包含任务元信息的 `MetaData` 对象 */ public void setMetaInfo(MetaData metaData) { + // 检查元数据对象是否非空,且包含有效的笔记内容 if (metaData != null && metaData.getNotes() != null) { try { + // 将元数据对象中的笔记内容转换为 JSON 对象并赋值给 `mMetaInfo` mMetaInfo = new JSONObject(metaData.getNotes()); } catch (JSONException e) { + // 记录 JSON 解析异常信息 Log.w(TAG, e.toString()); + // 设置 `mMetaInfo` 为 null,表明元信息未成功解析 mMetaInfo = null; } } } + /** * 根据数据库游标获取同步动作类型。 * diff --git a/Src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java b/Src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java index b0dfa13..7677cb3 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java @@ -53,79 +53,90 @@ public class TaskList extends Node { } /** - * 生成创建任务列表的动作JSON对象。 + * 生成创建任务列表的动作 JSON 对象。 + * 此方法构建一个 JSON 对象,用于表示创建新任务列表的操作。 * - * @param actionId 动作标识符 - * @return 包含创建任务列表动作的JSON对象 - * @throws ActionFailureException 如果生成JSON对象失败,则抛出异常 + * @param actionId 动作标识符,用于区分不同的操作请求 + * @return 包含创建任务列表动作的 JSON 对象 + * @throws ActionFailureException 如果生成 JSON 对象失败,则抛出异常 */ public JSONObject getCreateAction(int actionId) throws ActionFailureException { JSONObject js = new JSONObject(); try { - // 设置动作类型为创建 + // 将动作类型设置为 "创建" js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); - // 设置动作标识符 + // 设置当前动作的标识符 js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // 设置索引 + // 指定任务列表的索引位置 js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); - // 设置实体变化信息 + // 构建包含任务列表具体信息的实体 JSON 对象 JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务列表名称 + entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 创建者 ID,未指定时为 "null" entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_GROUP); + GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // 设置实体类型为任务组 + + // 将实体信息添加到主 JSON 对象中 js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); } catch (JSONException e) { + // 捕获 JSON 异常,记录错误日志并抛出自定义异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to generate tasklist-create jsonobject"); } + // 返回构建的 JSON 对象 return js; } + /** - * 生成更新任务列表的动作JSON对象。 + * 生成更新任务列表的动作 JSON 对象。 + * 此方法构建一个 JSON 对象,用于表示更新现有任务列表的操作。 * - * @param actionId 动作标识符 - * @return 包含更新任务列表动作的JSON对象 - * @throws ActionFailureException 如果生成JSON对象失败,则抛出异常 + * @param actionId 动作标识符,用于区分不同的操作请求 + * @return 包含更新任务列表动作的 JSON 对象 + * @throws ActionFailureException 如果生成 JSON 对象失败,则抛出异常 */ public JSONObject getUpdateAction(int actionId) throws ActionFailureException { + // 创建一个新的 JSON 对象来存储更新操作的细节 JSONObject js = new JSONObject(); try { - // 设置动作类型为更新 + // 将动作类型设置为 "更新" js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // 设置动作标识符 + // 设置当前动作的标识符 js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // 设置任务列表ID + // 指定需要更新的任务列表 ID js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // 设置实体变化信息 + // 构建包含任务列表更新信息的实体 JSON 对象 JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 设置任务列表名称 + entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 设置任务列表删除状态 + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加实体信息到主 JSON 对象中 } catch (JSONException e) { + // 捕获 JSON 异常,记录错误日志并抛出自定义异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to generate tasklist-update jsonobject"); } + // 返回构建的 JSON 对象 return js; } + /** * 根据远程JSON对象设置任务列表的内容。 * @@ -159,42 +170,49 @@ public class TaskList extends Node { } /** - * 根据本地JSON对象设置任务列表的内容。 + * 根据本地 JSON 对象设置任务列表的内容。 + * 此方法解析传入的 JSON 对象,提取任务列表的信息并设置相应的属性。 * - * @param js 本地获取的JSON对象 - * @throws ActionFailureException 如果从JSON对象中获取内容失败,则抛出异常 + * @param js 本地获取的 JSON 对象,包含任务列表的详细信息 + * @throws ActionFailureException 如果从 JSON 对象中获取内容失败,则抛出异常 */ public void setContentByLocalJSON(JSONObject js) throws ActionFailureException { + // 检查 JSON 对象是否有效并包含必要的元数据 if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { - Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); + Log.w(TAG, "setContentByLocalJSON: nothing is available"); return; } try { + // 从 JSON 对象中获取任务列表信息 JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - // 根据类型设置任务列表名称 + // 根据任务列表类型设置名称 if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { + // 如果类型为普通文件夹,从 JSON 中提取名称,并加上前缀 String name = folder.getString(NoteColumns.SNIPPET); setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { - if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) + // 如果类型为系统文件夹,根据文件夹 ID 设置默认名称 + if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) { setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); - else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE); - else - Log.e(TAG, "invalid system folder"); + } else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) { + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE); + } else { + Log.e(TAG, "invalid system folder"); // 无效的系统文件夹类型 + } } else { - Log.e(TAG, "error type"); + Log.e(TAG, "error type"); // 无效的任务类型 } } catch (JSONException e) { + // 捕获 JSON 异常,记录错误日志并抛出自定义异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to set tasklist content from local json object"); } } + /** * 从任务列表内容生成本地JSON对象。 * @@ -230,43 +248,49 @@ public class TaskList extends Node { /** * 根据本地数据库游标确定同步动作。 + * 此方法通过检查数据库中的任务列表信息和远程同步状态,确定应执行的同步操作。 * * @param c 数据库游标,指向当前任务列表的行 - * @return 同步动作的类型 + * @return 同步动作的类型,表示应执行的同步操作,例如无动作、更新本地、更新远程或冲突处理 */ public int getSyncAction(Cursor c) { try { + // 检查是否有本地更新(LOCAL_MODIFIED_COLUMN为0表示无本地更新) if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // 无本地更新 + // 无本地更新的情况下,比较同步ID(SYNC_ID_COLUMN)和最后修改时间 if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // 双方均无更新 + // 双方均无更新,返回无动作 return SYNC_ACTION_NONE; } else { - // 应用远程更新到本地 + // 若本地无更新但远程有更新,则应将远程更新应用到本地 return SYNC_ACTION_UPDATE_LOCAL; } } else { - // 验证GTask ID是否匹配 + // 如果本地有更新,则首先验证 GTask ID 是否匹配 if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { - Log.e(TAG, "gtask id doesn't match"); + Log.e(TAG, "gtask id doesn't match"); // GTask ID 不匹配,返回同步错误 return SYNC_ACTION_ERROR; } + + // 检查同步ID是否匹配最后修改时间,以确定是否仅有本地修改 if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // 仅本地有修改 + // 若远程无修改,则仅将本地更新同步到远程 return SYNC_ACTION_UPDATE_REMOTE; } else { - // 对于文件夹冲突,仅应用本地修改 + // 若本地和远程均有修改(冲突),对于文件夹同步,优先应用本地修改 return SYNC_ACTION_UPDATE_REMOTE; } } } catch (Exception e) { + // 捕获异常并记录日志,返回同步错误 Log.e(TAG, e.toString()); e.printStackTrace(); } - return SYNC_ACTION_ERROR; + return SYNC_ACTION_ERROR; // 发生异常或错误时,返回同步错误 } + /** * 获取子任务数量。 * diff --git a/Src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java b/Src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java index 4921f05..1621c37 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java @@ -1,23 +1,23 @@ /* * ActionFailureException 类的注释 * - * 该异常类是运行时异常的子类,用于表示操作失败的异常情况。它可以包含一个错误消息和导致异常的 Throwable 对象。 - * 这个类主要是为了处理任务或动作执行失败的情况,提供了一个通用的方式来报告和处理这类错误。 + * 该异常类是 RuntimeException 的子类,用于表示操作失败的异常情况。 + * 它可以包含一个错误消息和一个导致异常的 Throwable 对象。 + * 该类用于任务或操作执行失败时的情况,提供了一个通用方式来报告和处理这些错误。 * - * 许可证信息: 见类文件头部的版权声明 + * 许可证信息: 见类文件头部的版权声明。 */ package net.micode.notes.gtask.exception; -// 引入 Java 运行时异常类 - -import java.lang.RuntimeException; +import java.lang.RuntimeException; // 引入 RuntimeException 类 /** - * ActionFailureException 类定义了一个操作失败时抛出的异常。 + * ActionFailureException 类定义了一个在操作失败时抛出的异常。 + * 该异常适用于任务执行失败或操作无法完成的情况。 */ public class ActionFailureException extends RuntimeException { - private static final long serialVersionUID = 4425249765923293627L; // 序列化 ID + private static final long serialVersionUID = 4425249765923293627L; // 序列化 ID,用于确保一致的类版本 /** * 无参构造函数,创建一个不带详细消息的动作失败异常实例。 @@ -36,10 +36,11 @@ public class ActionFailureException extends RuntimeException { } /** - * 带有详细信息和导致异常的原因的构造函数,创建一个带有详细错误消息和导致异常的 Throwable 对象的动作失败异常实例。 + * 带有详细信息和导致异常的原因的构造函数, + * 创建一个带有详细错误消息和原因(Throwable)的动作失败异常实例。 * * @param paramString 错误信息字符串,用于描述异常的详细情况。 - * @param paramThrowable 导致异常的 Throwable 对象。 + * @param paramThrowable 导致异常的 Throwable 对象,可以是异常的根本原因。 */ public ActionFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); diff --git a/Src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java b/Src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java index fc6d53f..5135c6c 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java @@ -1,26 +1,38 @@ /* * NetworkFailureException 类的注释 * - * 该异常类用于表示网络操作失败的异常。它是 Exception 的子类,可用来捕获和处理应用程序中发生的网络错误。 - * 可以通过不同的构造函数来创建包含详细信息或不包含详细信息的 NetworkFailureException 实例。 + * 该异常类表示网络操作失败的情况。它是 Exception 的子类,允许捕获和处理应用程序中发生的网络错误。 + * 提供无参和多参构造函数,用于创建包含详细信息或不包含详细信息的 NetworkFailureException 实例。 */ package net.micode.notes.gtask.exception; public class NetworkFailureException extends Exception { - private static final long serialVersionUID = 2107610287180234136L; + private static final long serialVersionUID = 2107610287180234136L; // 序列化 ID - // 无参构造函数,用于创建一个不带详细信息的 NetworkFailureException 实例。 + /** + * 无参构造函数,用于创建一个不带详细信息的 NetworkFailureException 实例。 + */ public NetworkFailureException() { super(); } - // 带有详细信息的构造函数,用于创建一个包含错误信息的 NetworkFailureException 实例。 + /** + * 带有详细信息的构造函数,用于创建一个包含错误信息的 NetworkFailureException 实例。 + * + * @param paramString 错误信息字符串,用于描述网络错误的详细情况。 + */ public NetworkFailureException(String paramString) { super(paramString); } - // 带有详细信息和导致异常的 Throwable 对象的构造函数,用于创建包含错误信息和原因的 NetworkFailureException 实例。 + /** + * 带有详细信息和导致异常的原因的构造函数, + * 用于创建一个包含错误信息和原因(Throwable)的 NetworkFailureException 实例。 + * + * @param paramString 错误信息字符串,用于描述网络错误的详细情况。 + * @param paramThrowable 导致网络错误的 Throwable 对象,通常是根本原因。 + */ public NetworkFailureException(String paramString, Throwable paramThrowable) { super(paramString, paramThrowable); } diff --git a/Src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/Src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java index 9e6ccae..a329109 100644 --- a/Src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/Src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -1,8 +1,9 @@ /* * GTaskASyncTask 类说明: - * 这是一个继承自AsyncTask的类,用于在后台执行Google任务同步操作。它可以在一个独立的线程中执行同步任务,并通过通知栏通知用户同步的状态(成功、失败、取消等)。 - * 同时,它提供了接口供调用者监听同步任务的完成。 + * 这是一个继承自 AsyncTask 的类,用于在后台执行 Google 任务同步操作。它可以在独立线程中执行同步任务, + * 并通过通知栏向用户报告同步状态(如成功、失败或取消)。此外,它提供了一个接口供调用者监听同步任务的完成事件。 */ + package net.micode.notes.gtask.remote; import android.app.Notification; @@ -16,21 +17,20 @@ import net.micode.notes.R; import net.micode.notes.ui.NotesListActivity; import net.micode.notes.ui.NotesPreferenceActivity; - public class GTaskASyncTask extends AsyncTask { - // 同步通知的唯一ID + // 同步通知的唯一 ID private static int GTASK_SYNC_NOTIFICATION_ID = 5234235; - // 定义完成监听器接口 + // 定义同步完成监听器接口 public interface OnCompleteListener { void onComplete(); } private Context mContext; // 上下文对象,用于访问应用资源和通知管理器 - private NotificationManager mNotifiManager; // 通知管理器 - private GTaskManager mTaskManager; // Google任务管理器,用于执行实际的同步操作 - private OnCompleteListener mOnCompleteListener; // 同步完成的监听器 + private NotificationManager mNotifiManager; // 通知管理器,用于管理通知的显示和隐藏 + private GTaskManager mTaskManager; // Google 任务管理器,用于实际执行同步操作 + private OnCompleteListener mOnCompleteListener; // 同步完成监听器 /* * 构造函数 @@ -40,8 +40,7 @@ public class GTaskASyncTask extends AsyncTask { public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; - mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); + mNotifiManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); mTaskManager = GTaskManager.getInstance(); } @@ -52,29 +51,24 @@ public class GTaskASyncTask extends AsyncTask { // 发布进度更新的方法 public void publishProgess(String message) { - publishProgress(new String[]{ - message - }); + publishProgress(new String[]{message}); } /* * 显示通知的方法 - * @param tickerId 通知的Ticker文本资源ID + * @param tickerId 通知的 Ticker 文本资源 ID * @param content 通知的内容文本 */ private void showNotification(int tickerId, String content) { PendingIntent pendingIntent; - // 根据不同的通知状态设置不同的Intent + // 根据通知状态,设置点击通知时打开的 Activity if (tickerId != R.string.ticker_success) { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), 0); - + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); } else { - pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), 0); } - // 构建通知并显示 + // 构建通知对象 Notification.Builder builder = new Notification.Builder(mContext) .setAutoCancel(true) .setContentTitle(mContext.getString(R.string.app_name)) @@ -83,7 +77,7 @@ public class GTaskASyncTask extends AsyncTask { .setWhen(System.currentTimeMillis()) .setOngoing(true); Notification notification = builder.getNotification(); - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); + mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); // 显示通知 } /* @@ -92,21 +86,20 @@ public class GTaskASyncTask extends AsyncTask { */ @Override protected Integer doInBackground(Void... unused) { - // 开始同步时的进度更新 - publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity - .getSyncAccountName(mContext))); - return mTaskManager.sync(mContext, this); + // 登录并开始同步,显示进度 + publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity.getSyncAccountName(mContext))); + return mTaskManager.sync(mContext, this); // 调用 GTaskManager 开始同步 } /* - * 更新进度的方法,会在调用publishProgress后被调用 + * 更新进度的方法,会在调用 publishProgress 后被调用 * @param progress 进度更新的内容 */ @Override protected void onProgressUpdate(String... progress) { // 显示当前同步进度 showNotification(R.string.ticker_syncing, progress[0]); - // 如果上下文是一个GTaskSyncService实例,发送广播更新进度 + // 如果上下文是 GTaskSyncService 实例,发送广播更新进度 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } @@ -118,23 +111,20 @@ public class GTaskASyncTask extends AsyncTask { */ @Override protected void onPostExecute(Integer result) { - // 根据不同的状态显示不同的通知 + // 根据状态码显示不同的通知 if (result == GTaskManager.STATE_SUCCESS) { - showNotification(R.string.ticker_success, mContext.getString( - R.string.success_sync_account, mTaskManager.getSyncAccount())); + showNotification(R.string.ticker_success, mContext.getString(R.string.success_sync_account, mTaskManager.getSyncAccount())); NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); } else if (result == GTaskManager.STATE_NETWORK_ERROR) { showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { - showNotification(R.string.ticker_cancel, mContext - .getString(R.string.error_sync_cancelled)); + showNotification(R.string.ticker_cancel, mContext.getString(R.string.error_sync_cancelled)); } - // 如果设置了完成监听器,则在一个新线程中调用其onComplete方法 + // 如果设置了完成监听器,异步调用 onComplete 方法 if (mOnCompleteListener != null) { new Thread(new Runnable() { - public void run() { mOnCompleteListener.onComplete(); } diff --git a/Src/app/src/main/java/net/micode/notes/model/Note.java b/Src/app/src/main/java/net/micode/notes/model/Note.java index 9734a4c..ceb150e 100644 --- a/Src/app/src/main/java/net/micode/notes/model/Note.java +++ b/Src/app/src/main/java/net/micode/notes/model/Note.java @@ -151,32 +151,51 @@ public class Note { * @param noteId 需要同步的笔记ID * @return 如果同步成功则返回true,否则返回false */ + /** + * 将笔记同步到数据库。如果该笔记的内容或属性被本地修改,则更新数据库中的笔记内容。 + * + * @param context 上下文对象,用于访问内容提供者。 + * @param noteId 需要同步的笔记的唯一ID。通过该ID,方法会定位到数据库中对应的笔记项。 + * @return 如果同步成功返回 true;如果在数据推送过程中出现问题返回 false。 + * @throws IllegalArgumentException 如果 noteId 小于等于 0,抛出非法参数异常。 + */ public boolean syncNote(Context context, long noteId) { + // 检查 noteId 的有效性,如果 noteId 不合法则抛出异常 if (noteId <= 0) { throw new IllegalArgumentException("错误的笔记ID:" + noteId); } + // 如果笔记没有被本地修改,则无需同步,直接返回 true 表示同步成功 if (!isLocalModified()) { return true; } - // 理论上,一旦数据改变,笔记应该在本地修改标记和修改日期上更新。为了数据安全,即使更新笔记失败,我们也更新笔记的数据信息 + // 如果本地内容有改动,尝试将笔记属性更新到数据库 + // 使用 noteId 来定位到具体的笔记条目 + // 调用 ContentResolver.update 方法,传入更新的数据 if (context.getContentResolver().update( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, null) == 0) { + // 若更新失败,记录日志以提示意外情况 Log.e(TAG, "更新笔记错误,不应该发生"); - // 不返回,继续执行 + // 即使更新笔记失败,也继续执行,确保数据清理 } + // 清除记录的属性差异值,因为已经提交到数据库 mNoteDiffValues.clear(); + // 如果笔记的 NoteData 内容存在本地修改 + // 调用 pushIntoContentResolver 将其推送到数据库 + // 如果推送失败(返回 null),则同步失败,返回 false if (mNoteData.isLocalModified() && (mNoteData.pushIntoContentResolver(context, noteId) == null)) { return false; } + // 所有更改成功推送到数据库,返回 true 表示同步成功 return true; } + /** * 内部类NoteData,用于管理笔记的文本数据和通话数据 */ @@ -224,25 +243,41 @@ public class Note { * * @param id 通话数据的ID */ + /** + * 设置通话数据的唯一标识符。 + * 在对通话数据进行存储和更新操作前,需要调用此方法以确定通话数据的唯一标识。 + * + * @param id 通话数据的ID,必须为正整数,表示通话数据在数据库中的唯一标识。 + * @throws IllegalArgumentException 如果 id 小于或等于 0,则抛出异常,表明该 ID 无效。 + */ void setCallDataId(long id) { + // 检查参数 id 的有效性。ID 必须为正整数,否则抛出非法参数异常 if (id <= 0) { throw new IllegalArgumentException("通话数据ID应该大于0"); } + // 设置通话数据的唯一标识符 mCallDataId = id; } + /** - * 设置通话数据 + * 设置通话数据的字段及其对应的值。 + * 更新通话数据时,需要调用此方法将指定字段的值存储到 `mCallDataValues` 中。 + * 同时,此方法会更新笔记的本地修改标志和修改时间,以便同步时标记出最近的更改。 * - * @param key 设置的字段名 - * @param value 设置的字段值 + * @param key 要设置的通话数据字段的名称。通常为 `ContentValues` 中的键,用于数据库存储的键名。 + * @param value 要设置的字段的值。 */ void setCallData(String key, String value) { + // 在通话数据的ContentValues中插入或更新指定的键值对 mCallDataValues.put(key, value); + + // 标记笔记已被本地修改,并设置最新的修改时间 mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } + /** * 设置文本数据 * diff --git a/Src/app/src/main/java/net/micode/notes/model/WorkingNote.java b/Src/app/src/main/java/net/micode/notes/model/WorkingNote.java index 1496a3a..be55b60 100644 --- a/Src/app/src/main/java/net/micode/notes/model/WorkingNote.java +++ b/Src/app/src/main/java/net/micode/notes/model/WorkingNote.java @@ -119,47 +119,52 @@ public class WorkingNote { private static final int NOTE_MODIFIED_DATE_COLUMN = 5; /** - * 新建笔记的构造函数 + * 私有构造方法,用于初始化一个新的 `WorkingNote` 实例,创建时仅指定上下文和文件夹ID。 + * 设置笔记的基础属性,包括创建时间、文件夹ID、默认的提醒时间和小部件类型等。 * - * @param context 上下文对象,用于访问应用全局功能 - * @param folderId 文件夹ID,表示该笔记所属的文件夹 + * @param context 当前应用的上下文,用于访问资源和其他系统服务。 + * @param folderId 指定笔记所属的文件夹ID,用于将笔记归类到特定文件夹。 */ private WorkingNote(Context context, long folderId) { - mContext = context; - mAlertDate = 0; - mModifiedDate = System.currentTimeMillis(); - mFolderId = folderId; - mNote = new Note(); - mNoteId = 0; - mIsDeleted = false; - mMode = 0; - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; + mContext = context; // 存储上下文以便后续使用系统资源和服务 + mAlertDate = 0; // 默认提醒时间为0,即没有提醒 + mModifiedDate = System.currentTimeMillis(); // 设置笔记的创建时间为当前时间 + mFolderId = folderId; // 记录该笔记所属的文件夹ID + mNote = new Note(); // 创建一个新的 Note 实例,用于存储笔记内容 + mNoteId = 0; // 初始化笔记ID为0,表示该笔记尚未保存到数据库 + mIsDeleted = false; // 标记该笔记当前没有被删除 + mMode = 0; // 设置默认模式为0,具体模式含义可根据需求定义 + mWidgetType = Notes.TYPE_WIDGET_INVALIDE; // 设置小部件类型为无效,初始状态不绑定小部件 } + /** - * 已存在笔记的构造函数 + * 构造函数,用于初始化一个已存在的 `WorkingNote` 实例。 + * 使用该构造函数可以加载数据库中已保存的笔记,通过 `noteId` 获取对应笔记的内容和属性。 * - * @param context 上下文对象,用于访问应用全局功能 - * @param noteId 笔记ID,表示该笔记的唯一标识 - * @param folderId 文件夹ID,表示该笔记所属的文件夹 + * @param context 当前应用的上下文,用于访问资源和全局功能。 + * @param noteId 笔记的唯一标识符,用于从数据库中加载特定笔记。 + * @param folderId 该笔记所属的文件夹ID,用于分类笔记。 */ private WorkingNote(Context context, long noteId, long folderId) { - mContext = context; - mNoteId = noteId; - mFolderId = folderId; - mIsDeleted = false; - mNote = new Note(); - loadNote(); + mContext = context; // 赋值上下文对象,用于后续系统资源和服务访问 + mNoteId = noteId; // 初始化笔记ID,以便加载对应的笔记内容 + mFolderId = folderId; // 设置笔记所属的文件夹ID,表示其归属 + mIsDeleted = false; // 初始化删除标记为 false,表示该笔记未被删除 + mNote = new Note(); // 创建一个新的 Note 实例,用于存储笔记内容 + loadNote(); // 调用 loadNote 方法从数据库加载该笔记的内容和属性 } + /** * 加载指定笔记的信息。 * 从数据库中查询指定ID的笔记的详细信息,并更新当前实例的状态。 - * 注意:此方法不处理查询失败或笔记不存在的情况。 + * + * 注意:此方法假设笔记ID是有效的,并且对应的笔记存在于数据库中。如果笔记不存在,将记录错误并抛出异常。 */ private void loadNote() { - // 查询指定ID的笔记信息 + // 使用内容提供者查询数据库,获取与指定笔记ID匹配的笔记信息 Cursor cursor = mContext.getContentResolver().query( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, null, null); @@ -167,25 +172,26 @@ public class WorkingNote { if (cursor != null) { // 如果查询结果不为空,尝试读取数据 if (cursor.moveToFirst()) { - // 从查询结果中获取笔记的各个属性 - mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); - mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); - mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); - mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); - mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); - mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); + // 从查询结果中获取笔记的各个属性值,并更新当前实例的状态 + mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); // 获取并设置笔记所属文件夹ID + mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); // 获取并设置笔记背景颜色ID + mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); // 获取并设置关联的小部件ID + mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); // 获取并设置小部件的类型 + mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); // 获取并设置笔记的提醒时间 + mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); // 获取并设置笔记的上次修改时间 } - // 关闭查询结果集 + // 关闭查询游标以释放资源 cursor.close(); } else { - // 如果查询结果为空,记录错误并抛出异常 + // 查询失败,未找到匹配的笔记,记录错误日志并抛出异常 Log.e(TAG, "No note with id:" + mNoteId); throw new IllegalArgumentException("Unable to find note with id " + mNoteId); } - // 加载笔记的附加数据,如内容、设置等 + // 加载笔记的附加数据,例如内容和设置 loadNoteData(); } + /** * 加载笔记的附加数据。 * 从数据库中查询指定ID笔记的附加信息(例如内容、设置等),并更新当前实例的状态。 @@ -229,23 +235,34 @@ public class WorkingNote { /** * 创建一个新的空笔记。 + * 初始化并配置笔记的背景颜色、小部件ID和类型。 * * @param context 上下文对象,用于访问应用资源和内容提供者。 * @param folderId 笔记所属文件夹的ID。 * @param widgetId 与笔记关联的小部件ID。 * @param widgetType 与笔记关联的小部件类型。 * @param defaultBgColorId 笔记的默认背景颜色ID。 - * @return 返回一个初始化好的空笔记对象。 + * @return 返回一个配置好属性的空笔记对象。 */ public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, int widgetType, int defaultBgColorId) { + // 创建一个新的 WorkingNote 实例,指定所属文件夹ID WorkingNote note = new WorkingNote(context, folderId); + + // 设置笔记的默认背景颜色 note.setBgColorId(defaultBgColorId); + + // 设置与笔记关联的小部件ID note.setWidgetId(widgetId); + + // 设置与笔记关联的小部件类型 note.setWidgetType(widgetType); + + // 返回初始化好的空笔记对象 return note; } + /** * 根据笔记ID加载笔记。 * @@ -259,38 +276,42 @@ public class WorkingNote { /** - * 保存笔记到数据库。 - * 如果笔记值得保存(即内容非空且未被标记为删除),且笔记不存在于数据库中或已存在于数据库但本地有修改,则进行保存操作。 - * 如果笔记存在对应的小部件,会更新小部件内容。 + * 将当前笔记内容保存到数据库。 + * 如果笔记内容有意义(非空且未被删除),且该笔记在数据库中不存在或已存在但有本地修改,则执行保存操作。 + * 如果该笔记关联了小部件,则在保存后更新小部件的内容。 * - * @return 如果保存成功返回true,否则返回false。 + * @return 保存成功返回 true,否则返回 false。 */ public synchronized boolean saveNote() { - // 判断是否值得保存该笔记 + // 检查该笔记是否符合保存条件(即内容有意义且未被删除) if (isWorthSaving()) { - // 检查数据库中是否已存在该笔记 + // 检查笔记是否已存在于数据库中 if (!existInDatabase()) { - // 为笔记生成新的ID + // 如果笔记不在数据库中,为该笔记生成一个新的ID if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { + // 若生成新ID失败,记录日志并返回 false 表示保存失败 Log.e(TAG, "Create new note fail with id:" + mNoteId); return false; } } - mNote.syncNote(mContext, mNoteId); // 同步笔记到数据库 + // 将当前笔记内容同步到数据库 + mNote.syncNote(mContext, mNoteId); - // 如果存在对应的小部件,更新小部件内容 + // 如果笔记关联了小部件,更新小部件的显示内容 if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { + // 通过监听器通知小部件已更新 mNoteSettingStatusListener.onWidgetChanged(); } - return true; + return true; // 保存成功,返回 true } else { - return false; + return false; // 笔记内容无意义,不进行保存,返回 false } } + /** * 检查笔记是否已存在于数据库中。 * @@ -301,21 +322,26 @@ public class WorkingNote { } /** - * 判断笔记是否值得被保存。 - * 笔记不值得保存的情况包括:已被标记为删除、不存在于数据库中且内容为空、存在于数据库但未本地修改。 + * 判断当前笔记是否值得保存。 + * 以下情况认为笔记不值得保存: + * 1. 笔记已被标记为删除。 + * 2. 笔记不存在于数据库中且内容为空。 + * 3. 笔记已存在于数据库中但未在本地进行修改。 * - * @return 如果笔记值得保存返回true,否则返回false。 + * @return 如果笔记值得保存则返回 true,否则返回 false。 */ private boolean isWorthSaving() { - // 判断笔记是否值得保存 - if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) - || (existInDatabase() && !mNote.isLocalModified())) { - return false; + // 检查三种情况下笔记不值得保存的条件 + if (mIsDeleted || // 情况 1:笔记已被标记为删除 + (!existInDatabase() && TextUtils.isEmpty(mContent)) || // 情况 2:笔记不存在且内容为空 + (existInDatabase() && !mNote.isLocalModified())) { // 情况 3:笔记已存在且没有本地修改 + return false; // 不值得保存,返回 false } else { - return true; + return true; // 符合保存条件,返回 true } } + /** * 设置笔记设置状态监听器。 * @@ -328,20 +354,24 @@ public class WorkingNote { /** * 设置提醒日期,并根据需要触发状态监听器。 * - * @param date 设置的提醒日期。 - * @param set 是否设置提醒。 + * @param date 要设置的提醒日期(以毫秒为单位)。 + * @param set 指示是否启用提醒的布尔值(true 表示设置提醒,false 表示取消提醒)。 */ public void setAlertDate(long date, boolean set) { - // 更新提醒日期并触发监听器 + // 如果提醒日期发生更改,则更新提醒日期并记录到笔记对象中 if (date != mAlertDate) { mAlertDate = date; + // 更新笔记对象的提醒日期字段 mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate)); } + + // 如果已设置提醒状态监听器,则触发监听器的提醒更改事件 if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onClockAlertChanged(date, set); } } + /** * 标记笔记为已删除,并根据需要触发小部件变更监听器。 * @@ -362,17 +392,23 @@ public class WorkingNote { * @param id 背景颜色的资源ID。 */ public void setBgColorId(int id) { - // 更新背景颜色ID并触发监听器 + // 检查新颜色ID是否不同于当前ID,避免重复操作 if (id != mBgColorId) { + // 更新笔记的背景颜色ID mBgColorId = id; + + // 如果设置了笔记状态监听器,则通知监听器背景颜色已更改 if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onBackgroundColorChanged(); } + + // 在笔记对象中保存新的背景颜色ID mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); } } + /** * 设置勾选列表模式 * @@ -409,13 +445,17 @@ public class WorkingNote { * @param id 小部件ID */ public void setWidgetId(int id) { + // 检查新传入的小部件ID是否不同于当前的小部件ID,避免重复操作 if (id != mWidgetId) { + // 更新小部件ID属性 mWidgetId = id; - // 更新笔记中小部件ID的值 + + // 在笔记对象中更新小部件ID的值,以同步到数据库 mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); } } + /** * 设置工作文本 * @@ -436,12 +476,17 @@ public class WorkingNote { * @param callDate 通话日期 */ public void convertToCallNote(String phoneNumber, long callDate) { - // 设置通话日期和电话号码,并关联至通话记录文件夹 + // 将通话日期设置为笔记的通话数据 mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); + + // 将电话号码设置为笔记的通话数据 mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); + + // 将笔记的父文件夹ID设置为通话记录文件夹,使其分类为通话记录 mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); } + /** * 检查是否有定时提醒 *