From 2b14a29df1a3c5affc8e1cdb18773655a2772521 Mon Sep 17 00:00:00 2001 From: manic-zzz <1613759877@qq.com> Date: Wed, 14 May 2025 20:03:40 +0800 Subject: [PATCH] test2 --- src/net/micode/notes/data/Notes.java | 328 ++++++------------ .../notes/data/NotesDatabaseHelper.java | 68 ++-- src/net/micode/notes/data/NotesProvider.java | 88 +++-- 3 files changed, 207 insertions(+), 277 deletions(-) diff --git a/src/net/micode/notes/data/Notes.java b/src/net/micode/notes/data/Notes.java index f240604..e3468a3 100644 --- a/src/net/micode/notes/data/Notes.java +++ b/src/net/micode/notes/data/Notes.java @@ -17,24 +17,40 @@ package net.micode.notes.data; import android.net.Uri; + +/** + * Notes类定义了Notes应用的数据模型和常量,包括: + * - 内容提供者的AUTHORITY + * - 笔记和文件夹的类型常量 + * - 系统文件夹的特殊ID + * - Intent传递的额外数据键名 + * - 笔记和数据的URI + * - 数据库表结构的列定义 + * - 不同类型笔记的特定常量和URI + */ public class Notes { + // 内容提供者的AUTHORITY,用于访问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; + + // 笔记类型常量 + public static final int TYPE_NOTE = 0; // 普通笔记 + public static final int TYPE_FOLDER = 1; // 文件夹 + public static final int TYPE_SYSTEM = 2; // 系统项 /** - * Following IDs are system folders' identifiers - * {@link Notes#ID_ROOT_FOLDER } is default folder - * {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder - * {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records + * 系统文件夹的特殊ID: + * ID_ROOT_FOLDER:根文件夹,所有笔记的默认父文件夹 + * ID_TEMPARAY_FOLDER:临时文件夹,用于存放无父文件夹的笔记 + * ID_CALL_RECORD_FOLDER:通话记录文件夹,存放通话相关的笔记 + * ID_TRASH_FOLER:回收站文件夹,存放已删除的笔记 */ 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; + // Intent传递的额外数据键名,用于在组件间传递参数 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"; @@ -42,238 +58,108 @@ public class Notes { 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; - public static final int TYPE_WIDGET_4X = 1; + // 桌面小部件类型常量 + 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类定义了不同类型数据的MIME类型常量 + */ 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; // 文本笔记的MIME类型 + public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; // 通话记录笔记的MIME类型 } /** - * Uri to query all notes and folders + * 内容URI定义: + * CONTENT_NOTE_URI:查询所有笔记和文件夹的URI + * CONTENT_DATA_URI:查询笔记关联数据的URI */ public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); + public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); /** - * Uri to query data + * NoteColumns接口定义了笔记表的列名常量 */ - public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); - public interface NoteColumns { - /** - * The unique ID for a row - *

Type: INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * The parent's id for note or folder - *

Type: INTEGER (long)

- */ - public static final String PARENT_ID = "parent_id"; - - /** - * Created data for note or folder - *

Type: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * Latest modified date - *

Type: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - - /** - * Alert date - *

Type: INTEGER (long)

- */ - public static final String ALERTED_DATE = "alert_date"; - - /** - * Folder's name or text content of note - *

Type: TEXT

- */ - public static final String SNIPPET = "snippet"; - - /** - * Note's widget id - *

Type: INTEGER (long)

- */ - public static final String WIDGET_ID = "widget_id"; - - /** - * Note's widget type - *

Type: INTEGER (long)

- */ - public static final String WIDGET_TYPE = "widget_type"; - - /** - * Note's background color's id - *

Type: INTEGER (long)

- */ - public static final String BG_COLOR_ID = "bg_color_id"; - - /** - * For text note, it doesn't has attachment, for multi-media - * note, it has at least one attachment - *

Type: INTEGER

- */ - public static final String HAS_ATTACHMENT = "has_attachment"; - - /** - * Folder's count of notes - *

Type: INTEGER (long)

- */ - public static final String NOTES_COUNT = "notes_count"; - - /** - * The file type: folder or note - *

Type: INTEGER

- */ - public static final String TYPE = "type"; - - /** - * The last sync id - *

Type: INTEGER (long)

- */ - public static final String SYNC_ID = "sync_id"; - - /** - * Sign to indicate local modified or not - *

Type: INTEGER

- */ - public static final String LOCAL_MODIFIED = "local_modified"; - - /** - * Original parent id before moving into temporary folder - *

Type : INTEGER

- */ - public static final String ORIGIN_PARENT_ID = "origin_parent_id"; - - /** - * The gtask id - *

Type : TEXT

- */ - public static final String GTASK_ID = "gtask_id"; - - /** - * The version code - *

Type : INTEGER (long)

- */ - public static final String VERSION = "version"; + // 基础信息列 + public static final String ID = "_id"; // 唯一ID + public static final String PARENT_ID = "parent_id"; // 父文件夹ID + public static final String CREATED_DATE = "created_date"; // 创建日期 + public static final String MODIFIED_DATE = "modified_date"; // 修改日期 + + // 提醒相关列 + public static final String ALERTED_DATE = "alert_date"; // 提醒日期 + + // 内容和显示相关列 + public static final String SNIPPET = "snippet"; // 摘要或文件夹名称 + public static final String WIDGET_ID = "widget_id"; // 关联的小部件ID + public static final String WIDGET_TYPE = "widget_type"; // 小部件类型 + public static final String BG_COLOR_ID = "bg_color_id"; // 背景颜色ID + + // 附件和类型相关列 + public static final String HAS_ATTACHMENT = "has_attachment"; // 是否有附件 + public static final String TYPE = "type"; // 类型(笔记/文件夹/系统项) + + // 文件夹相关列 + public static final String NOTES_COUNT = "notes_count"; // 文件夹包含的笔记数量 + + // 同步和版本控制列 + public static final String SYNC_ID = "sync_id"; // 同步ID + public static final String LOCAL_MODIFIED = "local_modified"; // 本地修改标记 + public static final String ORIGIN_PARENT_ID = "origin_parent_id"; // 原始父文件夹ID(用于回收站) + public static final String GTASK_ID = "gtask_id"; // Google任务ID + public static final String VERSION = "version"; // 版本号 } + /** + * DataColumns接口定义了数据记录表的列名常量 + */ public interface DataColumns { - /** - * The unique ID for a row - *

Type: INTEGER (long)

- */ - public static final String ID = "_id"; - - /** - * The MIME type of the item represented by this row. - *

Type: Text

- */ - public static final String MIME_TYPE = "mime_type"; - - /** - * The reference id to note that this data belongs to - *

Type: INTEGER (long)

- */ - public static final String NOTE_ID = "note_id"; - - /** - * Created data for note or folder - *

Type: INTEGER (long)

- */ - public static final String CREATED_DATE = "created_date"; - - /** - * Latest modified date - *

Type: INTEGER (long)

- */ - public static final String MODIFIED_DATE = "modified_date"; - - /** - * Data's content - *

Type: TEXT

- */ - public static final String CONTENT = "content"; - - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * integer data type - *

Type: INTEGER

- */ - public static final String DATA1 = "data1"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * integer data type - *

Type: INTEGER

- */ - public static final String DATA2 = "data2"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA3 = "data3"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA4 = "data4"; - - /** - * Generic data column, the meaning is {@link #MIMETYPE} specific, used for - * TEXT data type - *

Type: TEXT

- */ - public static final String DATA5 = "data5"; + // 基础信息列 + public static final String ID = "_id"; // 唯一ID + public static final String MIME_TYPE = "mime_type"; // MIME类型 + public static final String NOTE_ID = "note_id"; // 关联的笔记ID + public static final String CREATED_DATE = "created_date"; // 创建日期 + public static final String MODIFIED_DATE = "modified_date"; // 修改日期 + + // 内容列 + public static final String CONTENT = "content"; // 内容 + + // 通用数据列,根据MIME类型有不同含义 + public static final String DATA1 = "data1"; // 通常用于整数类型数据 + public static final String DATA2 = "data2"; // 通常用于整数类型数据 + public static final String DATA3 = "data3"; // 通常用于文本类型数据 + public static final String DATA4 = "data4"; // 通常用于文本类型数据 + public static final String DATA5 = "data5"; // 通常用于文本类型数据 } + /** + * TextNote类定义了文本笔记的特定常量和URI + */ public static final class TextNote implements DataColumns { - /** - * Mode to indicate the text in check list mode or not - *

Type: Integer 1:check list mode 0: normal mode

- */ - 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"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; - - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); + // 文本笔记特有的数据列 + public static final String MODE = DATA1; // 文本模式(普通/检查列表) + public static final int MODE_CHECK_LIST = 1; // 检查列表模式 + + // MIME类型和URI定义 + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; // 目录类型 + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; // 单项类型 + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); // 内容URI } + /** + * CallNote类定义了通话记录笔记的特定常量和URI + */ public static final class CallNote implements DataColumns { - /** - * Call date for this record - *

Type: INTEGER (long)

- */ - public static final String CALL_DATE = DATA1; - - /** - * Phone number for this record - *

Type: TEXT

- */ - public static final String PHONE_NUMBER = DATA3; - - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; - - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; - - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); + // 通话记录特有的数据列 + public static final String CALL_DATE = DATA1; // 通话日期 + public static final String PHONE_NUMBER = DATA3; // 电话号码 + + // MIME类型和URI定义 + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; // 目录类型 + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; // 单项类型 + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); // 内容URI } -} +} \ No newline at end of file diff --git a/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/net/micode/notes/data/NotesDatabaseHelper.java index ffe5d57..98a580f 100644 --- a/src/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/net/micode/notes/data/NotesDatabaseHelper.java @@ -26,22 +26,27 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; - +/** + * NotesDatabaseHelper类用于管理笔记应用的数据库,包括创建表、升级数据库版本、 + * 管理系统文件夹和执行数据库操作的触发器。 + */ public class NotesDatabaseHelper extends SQLiteOpenHelper { + // 数据库文件名 private static final String DB_NAME = "note.db"; - + // 数据库版本号 private static final int DB_VERSION = 4; + // 数据库表名接口,定义了笔记表和数据记录表的名称 public interface TABLE { public static final String NOTE = "note"; - public static final String DATA = "data"; } private static final String TAG = "NotesDatabaseHelper"; - + // 单例实例 private static NotesDatabaseHelper mInstance; + // 创建笔记表的SQL语句 private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + @@ -63,6 +68,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")"; + // 创建数据记录表的SQL语句 private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + @@ -78,13 +84,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + ")"; + // 创建数据记录表中note_id索引的SQL语句 private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; - /** - * Increase folder's note count when move note to the folder - */ + // 当移动笔记到文件夹时增加文件夹的笔记数量的触发器SQL语句 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 + @@ -94,9 +99,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END"; - /** - * Decrease folder's note count when move note from folder - */ + // 当从文件夹中移动笔记时减少文件夹的笔记数量的触发器SQL语句 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 + @@ -107,9 +110,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " END"; - /** - * Increase folder's note count when insert new note to the folder - */ + // 当插入新笔记到文件夹时增加文件夹的笔记数量的触发器SQL语句 private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + " AFTER INSERT ON " + TABLE.NOTE + @@ -119,9 +120,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END"; - /** - * Decrease folder's note count when delete note from the folder - */ + // 当从文件夹中删除笔记时减少文件夹的笔记数量的触发器SQL语句 private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -132,9 +131,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " AND " + NoteColumns.NOTES_COUNT + ">0;" + " END"; - /** - * Update note's content when insert data with type {@link DataConstants#NOTE} - */ + // 当插入数据且类型为笔记时更新笔记内容的触发器SQL语句 private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + " AFTER INSERT ON " + TABLE.DATA + @@ -145,9 +142,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END"; - /** - * Update note's content when data with {@link DataConstants#NOTE} type has changed - */ + // 当更新数据且类型为笔记时更新笔记内容的触发器SQL语句 private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + " AFTER UPDATE ON " + TABLE.DATA + @@ -158,9 +153,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END"; - /** - * Update note's content when data with {@link DataConstants#NOTE} type has deleted - */ + // 当删除数据且类型为笔记时更新笔记内容的触发器SQL语句 private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + " AFTER delete ON " + TABLE.DATA + @@ -171,9 +164,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " END"; - /** - * Delete datas belong to note which has been deleted - */ + // 当删除笔记时删除相关数据的触发器SQL语句 private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -182,9 +173,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + " END"; - /** - * Delete notes belong to folder which has been deleted - */ + // 当删除文件夹时删除该文件夹下所有笔记的触发器SQL语句 private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + @@ -193,9 +182,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END"; - /** - * Move notes belong to folder which has been moved to trash folder - */ + // 当文件夹被移动到回收站时移动该文件夹下所有笔记到回收站的触发器SQL语句 private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + " AFTER UPDATE ON " + TABLE.NOTE + @@ -206,10 +193,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END"; + // 构造函数,调用父类构造函数初始化数据库辅助类 public NotesDatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } + // 创建笔记表的方法,执行创建表的SQL语句并创建相关触发器和系统文件夹 public void createNoteTable(SQLiteDatabase db) { db.execSQL(CREATE_NOTE_TABLE_SQL); reCreateNoteTableTriggers(db); @@ -217,6 +206,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { Log.d(TAG, "note table has been created"); } + // 重新创建笔记表触发器的方法,先删除旧触发器再创建新触发器 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"); @@ -235,6 +225,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); } + // 创建系统文件夹的方法,插入根文件夹、通话记录文件夹、临时文件夹和回收站文件夹 private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); @@ -270,6 +261,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); } + // 创建数据记录表的方法,执行创建表的SQL语句并创建相关触发器和索引 public void createDataTable(SQLiteDatabase db) { db.execSQL(CREATE_DATA_TABLE_SQL); reCreateDataTableTriggers(db); @@ -277,6 +269,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { Log.d(TAG, "data table has been created"); } + // 重新创建数据记录表触发器的方法,先删除旧触发器再创建新触发器 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"); @@ -287,6 +280,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); } + // 获取单例实例的方法,确保只有一个数据库辅助类实例 static synchronized NotesDatabaseHelper getInstance(Context context) { if (mInstance == null) { mInstance = new NotesDatabaseHelper(context); @@ -294,12 +288,14 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { return mInstance; } + // 当数据库创建时调用的方法,创建笔记表和数据记录表 @Override public void onCreate(SQLiteDatabase db) { createNoteTable(db); createDataTable(db); } + // 当数据库版本升级时调用的方法,根据旧版本进行相应的升级操作 @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { boolean reCreateTriggers = false; @@ -333,6 +329,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } } + // 升级到版本2的方法,删除旧表并重新创建笔记表和数据记录表 private void upgradeToV2(SQLiteDatabase db) { db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); @@ -340,6 +337,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { createDataTable(db); } + // 升级到版本3的方法,删除未使用的触发器,添加gtask_id列并创建回收站文件夹 private void upgradeToV3(SQLiteDatabase db) { // drop unused triggers db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert"); @@ -359,4 +357,4 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { 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/net/micode/notes/data/NotesProvider.java b/src/net/micode/notes/data/NotesProvider.java index edb0a60..eca135a 100644 --- a/src/net/micode/notes/data/NotesProvider.java +++ b/src/net/micode/notes/data/NotesProvider.java @@ -16,7 +16,6 @@ package net.micode.notes.data; - import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentUris; @@ -34,23 +33,27 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.NotesDatabaseHelper.TABLE; - +/** + * NotesProvider是应用的内容提供者,负责管理笔记数据的访问接口。 + * 它处理对笔记和数据的CRUD操作,并支持搜索功能。 + */ public class NotesProvider extends ContentProvider { + // URI匹配器,用于解析不同的URI请求 private static final UriMatcher mMatcher; - + // 数据库助手类实例 private NotesDatabaseHelper mHelper; - private static final String TAG = "NotesProvider"; - private static final int URI_NOTE = 1; - private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; - private static final int URI_DATA_ITEM = 4; - - private static final int URI_SEARCH = 5; - private static final int URI_SEARCH_SUGGEST = 6; + // URI匹配码常量 + private static final int URI_NOTE = 1; // 匹配所有笔记 + private static final int URI_NOTE_ITEM = 2; // 匹配单个笔记 + private static final int URI_DATA = 3; // 匹配所有数据 + private static final int URI_DATA_ITEM = 4; // 匹配单个数据 + private static final int URI_SEARCH = 5; // 匹配搜索请求 + private static final int URI_SEARCH_SUGGEST = 6; // 匹配搜索建议请求 static { + // 初始化URI匹配器 mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); @@ -62,8 +65,8 @@ public class NotesProvider extends ContentProvider { } /** - * x'0A' represents the '\n' character in sqlite. For title and content in the search result, - * we will trim '\n' and white space in order to show more information. + * 笔记搜索的投影列定义,用于搜索结果的格式化显示 + * 包含ID、搜索文本、图标和意图信息 */ private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," @@ -73,18 +76,28 @@ public class NotesProvider extends ContentProvider { + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + /** + * 笔记搜索的SQL查询语句,用于在笔记摘要中搜索关键词 + * 排除回收站中的笔记,只搜索普通笔记类型 + */ private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + /** + * 初始化内容提供者,获取数据库助手实例 + */ @Override public boolean onCreate() { mHelper = NotesDatabaseHelper.getInstance(getContext()); return true; } + /** + * 处理查询请求,根据不同的URI执行相应的数据库查询 + */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { @@ -93,25 +106,30 @@ public class NotesProvider extends ContentProvider { String id = null; switch (mMatcher.match(uri)) { case URI_NOTE: + // 查询所有笔记 c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, sortOrder); break; case URI_NOTE_ITEM: + // 查询单个笔记 id = uri.getPathSegments().get(1); c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; case URI_DATA: + // 查询所有数据 c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder); break; case URI_DATA_ITEM: + // 查询单个数据 id = uri.getPathSegments().get(1); c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; case URI_SEARCH: case URI_SEARCH_SUGGEST: + // 处理搜索和搜索建议请求 if (sortOrder != null || projection != null) { throw new IllegalArgumentException( "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); @@ -131,6 +149,7 @@ public class NotesProvider extends ContentProvider { } try { + // 执行模糊搜索 searchString = String.format("%%%s%%", searchString); c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, new String[] { searchString }); @@ -141,21 +160,27 @@ public class NotesProvider extends ContentProvider { default: throw new IllegalArgumentException("Unknown URI " + uri); } + // 设置内容观察者通知URI if (c != null) { c.setNotificationUri(getContext().getContentResolver(), uri); } return c; } + /** + * 处理插入请求,根据不同的URI插入相应的数据 + */ @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mHelper.getWritableDatabase(); long dataId = 0, noteId = 0, insertedId = 0; switch (mMatcher.match(uri)) { case URI_NOTE: + // 插入笔记 insertedId = noteId = db.insert(TABLE.NOTE, null, values); break; case URI_DATA: + // 插入数据,需关联笔记ID if (values.containsKey(DataColumns.NOTE_ID)) { noteId = values.getAsLong(DataColumns.NOTE_ID); } else { @@ -166,13 +191,12 @@ public class NotesProvider extends ContentProvider { default: throw new IllegalArgumentException("Unknown URI " + uri); } - // Notify the note uri + // 通知数据变化 if (noteId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); } - // Notify the data uri if (dataId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); @@ -181,6 +205,9 @@ public class NotesProvider extends ContentProvider { return ContentUris.withAppendedId(uri, insertedId); } + /** + * 处理删除请求,根据不同的URI删除相应的数据 + */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; @@ -189,15 +216,13 @@ public class NotesProvider extends ContentProvider { boolean deleteData = false; switch (mMatcher.match(uri)) { case URI_NOTE: + // 删除多个笔记,确保不删除系统文件夹 selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; count = db.delete(TABLE.NOTE, selection, selectionArgs); break; case URI_NOTE_ITEM: + // 删除单个笔记,不允许删除系统文件夹 id = uri.getPathSegments().get(1); - /** - * ID that smaller than 0 is system folder which is not allowed to - * trash - */ long noteId = Long.valueOf(id); if (noteId <= 0) { break; @@ -206,10 +231,12 @@ public class NotesProvider extends ContentProvider { NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; case URI_DATA: + // 删除多个数据 count = db.delete(TABLE.DATA, selection, selectionArgs); deleteData = true; break; case URI_DATA_ITEM: + // 删除单个数据 id = uri.getPathSegments().get(1); count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); @@ -218,6 +245,7 @@ public class NotesProvider extends ContentProvider { default: throw new IllegalArgumentException("Unknown URI " + uri); } + // 通知数据变化 if (count > 0) { if (deleteData) { getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); @@ -227,6 +255,9 @@ public class NotesProvider extends ContentProvider { return count; } + /** + * 处理更新请求,根据不同的URI更新相应的数据 + */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; @@ -235,20 +266,24 @@ public class NotesProvider extends ContentProvider { boolean updateData = false; switch (mMatcher.match(uri)) { case URI_NOTE: + // 更新多个笔记,并增加版本号 increaseNoteVersion(-1, selection, selectionArgs); count = db.update(TABLE.NOTE, values, selection, selectionArgs); break; case URI_NOTE_ITEM: + // 更新单个笔记,并增加版本号 id = uri.getPathSegments().get(1); increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; case URI_DATA: + // 更新多个数据 count = db.update(TABLE.DATA, values, selection, selectionArgs); updateData = true; break; case URI_DATA_ITEM: + // 更新单个数据 id = uri.getPathSegments().get(1); count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); @@ -258,6 +293,7 @@ public class NotesProvider extends ContentProvider { throw new IllegalArgumentException("Unknown URI " + uri); } + // 通知数据变化 if (count > 0) { if (updateData) { getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); @@ -267,10 +303,16 @@ public class NotesProvider extends ContentProvider { return count; } + /** + * 解析SQL选择条件,添加额外的AND条件 + */ private String parseSelection(String selection) { return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + /** + * 增加笔记的版本号,用于同步和冲突检测 + */ private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); @@ -279,6 +321,7 @@ public class NotesProvider extends ContentProvider { sql.append(NoteColumns.VERSION); sql.append("=" + NoteColumns.VERSION + "+1 "); + // 构建WHERE子句 if (id > 0 || !TextUtils.isEmpty(selection)) { sql.append(" WHERE "); } @@ -293,13 +336,16 @@ public class NotesProvider extends ContentProvider { sql.append(selectString); } + // 执行SQL语句 mHelper.getWritableDatabase().execSQL(sql.toString()); } + /** + * 返回URI对应的MIME类型,此处未实现 + */ @Override public String getType(Uri uri) { // TODO Auto-generated method stub return null; } - -} +} \ No newline at end of file