From 0348938fc0ddd8105faeee39829aee1306128fb3 Mon Sep 17 00:00:00 2001 From: pzvjlefpx <1290604840@qq.com> Date: Fri, 21 Mar 2025 16:08:06 +0800 Subject: [PATCH] annotation --- src/src/net/micode/notes/data/Contact.java | 12 ++ src/src/net/micode/notes/data/Notes.java | 8 ++ .../notes/data/NotesDatabaseHelper.java | 70 +++++++++- .../net/micode/notes/data/NotesProvider.java | 63 +++++++++ .../net/micode/notes/gtask/data/MetaData.java | 17 +++ src/src/net/micode/notes/gtask/data/Node.java | 5 + .../net/micode/notes/gtask/data/SqlData.java | 41 ++++++ .../net/micode/notes/gtask/data/SqlNote.java | 120 ++++++++++++++++++ src/src/net/micode/notes/gtask/data/Task.java | 23 ++++ 9 files changed, 356 insertions(+), 3 deletions(-) diff --git a/src/src/net/micode/notes/data/Contact.java b/src/src/net/micode/notes/data/Contact.java index d97ac5d..f16618e 100644 --- a/src/src/net/micode/notes/data/Contact.java +++ b/src/src/net/micode/notes/data/Contact.java @@ -26,9 +26,12 @@ import android.util.Log; import java.util.HashMap; public class Contact { + // 定义一个静态的HashMap,用于缓存联系人信息 private static HashMap sContactCache; + // 定义一个静态的字符串,用于标记日志信息 private static final String TAG = "Contact"; + // 定义一个静态的字符串,用于查询联系人信息的SQL语句 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 " @@ -36,17 +39,22 @@ public class Contact { + " FROM phone_lookup" + " WHERE min_match = '+')"; + // 根据电话号码获取联系人信息 public static String getContact(Context context, String phoneNumber) { + // 如果缓存为空,则创建一个新的HashMap if(sContactCache == null) { sContactCache = new HashMap(); } + // 如果缓存中已经存在该电话号码的联系人信息,则直接返回 if(sContactCache.containsKey(phoneNumber)) { return sContactCache.get(phoneNumber); } + // 替换SQL语句中的占位符,生成最终的查询语句 String selection = CALLER_ID_SELECTION.replace("+", PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + // 执行查询操作 Cursor cursor = context.getContentResolver().query( Data.CONTENT_URI, new String [] { Phone.DISPLAY_NAME }, @@ -54,18 +62,22 @@ public class Contact { new String[] { phoneNumber }, null); + // 如果查询结果不为空,则获取联系人信息并缓存 if (cursor != null && cursor.moveToFirst()) { try { 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; } finally { + // 关闭查询结果 cursor.close(); } } else { + // 如果没有匹配的联系人信息,则打印日志 Log.d(TAG, "No contact matched with number:" + phoneNumber); return null; } diff --git a/src/src/net/micode/notes/data/Notes.java b/src/src/net/micode/notes/data/Notes.java index f240604..c7b0e30 100644 --- a/src/src/net/micode/notes/data/Notes.java +++ b/src/src/net/micode/notes/data/Notes.java @@ -18,6 +18,7 @@ package net.micode.notes.data; import android.net.Uri; public class Notes { + // 定义Notes类的常量 public static final String AUTHORITY = "micode_notes"; public static final String TAG = "Notes"; public static final int TYPE_NOTE = 0; @@ -35,6 +36,7 @@ public class Notes { 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,10 +44,12 @@ 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"; + // 定义Widget的类型 public static final int TYPE_WIDGET_INVALIDE = -1; public static final int TYPE_WIDGET_2X = 0; public static final int TYPE_WIDGET_4X = 1; + // 定义DataConstants类 public static class DataConstants { public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; @@ -61,6 +65,7 @@ public class Notes { */ public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); + // 定义NoteColumns接口 public interface NoteColumns { /** * The unique ID for a row @@ -167,6 +172,7 @@ public class Notes { public static final String VERSION = "version"; } + // 定义DataColumns接口 public interface DataColumns { /** * The unique ID for a row @@ -241,6 +247,7 @@ public class Notes { public static final String DATA5 = "data5"; } + // 定义TextNote类 public static final class TextNote implements DataColumns { /** * Mode to indicate the text in check list mode or not @@ -257,6 +264,7 @@ public class Notes { public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); } + // 定义CallNote类 public static final class CallNote implements DataColumns { /** * Call date for this record diff --git a/src/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/src/net/micode/notes/data/NotesDatabaseHelper.java index ffe5d57..95ae279 100644 --- a/src/src/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/src/net/micode/notes/data/NotesDatabaseHelper.java @@ -28,20 +28,26 @@ 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; + // 表名接口 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; + // 创建note表的SQL语句 private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + @@ -63,6 +69,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")"; + // 创建data表的SQL语句 private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + @@ -78,6 +85,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + ")"; + // 创建data_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 + ");"; @@ -206,32 +214,54 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END"; + // 构造函数,用于初始化NotesDatabaseHelper对象 public NotesDatabaseHelper(Context context) { + // 调用父类的构造函数,传入上下文、数据库名称、游标工厂、数据库版本号 super(context, DB_NAME, null, DB_VERSION); } + // 创建note表 public void createNoteTable(SQLiteDatabase db) { + // 执行创建note表的SQL语句 db.execSQL(CREATE_NOTE_TABLE_SQL); + // 重新创建note表的触发器 reCreateNoteTableTriggers(db); + // 创建系统文件夹 createSystemFolder(db); + // 打印日志,note表已创建 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"); + // 删除减少文件夹计数触发器 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); } @@ -270,92 +300,126 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.insert(TABLE.NOTE, null, values); } + // 创建数据表 public void createDataTable(SQLiteDatabase db) { + // 执行创建数据表的SQL语句 db.execSQL(CREATE_DATA_TABLE_SQL); + // 重新创建数据表触发器 reCreateDataTableTriggers(db); + // 执行创建数据表索引的SQL语句 db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); + // 打印日志,表示数据表已经创建 Log.d(TAG, "data table has been created"); } + // 重新创建数据表触发器 private void reCreateDataTableTriggers(SQLiteDatabase db) { + // 删除update_note_content_on_insert触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); + // 删除update_note_content_on_update触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); + // 删除update_note_content_on_delete触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); + // 创建update_note_content_on_insert触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); + // 创建update_note_content_on_update触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); + // 创建update_note_content_on_delete触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); } + // 获取NotesDatabaseHelper实例 static synchronized NotesDatabaseHelper getInstance(Context context) { + // 如果mInstance为空,则创建一个新的NotesDatabaseHelper实例 if (mInstance == null) { mInstance = new NotesDatabaseHelper(context); } + // 返回mInstance return mInstance; } @Override public void onCreate(SQLiteDatabase db) { + // 创建Note表 createNoteTable(db); + // 创建Data表 createDataTable(db); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + // 定义两个布尔变量,用于判断是否需要重新创建触发器和是否跳过v2版本 boolean reCreateTriggers = false; boolean skipV2 = false; + // 如果旧版本是1,则升级到v2版本,并跳过v2版本 if (oldVersion == 1) { upgradeToV2(db); skipV2 = true; // this upgrade including the upgrade from v2 to v3 oldVersion++; } + // 如果旧版本是2且没有跳过v2版本,则升级到v3版本,并重新创建触发器 if (oldVersion == 2 && !skipV2) { upgradeToV3(db); reCreateTriggers = true; oldVersion++; } + // 如果旧版本是3,则升级到v4版本 if (oldVersion == 3) { upgradeToV4(db); oldVersion++; } + // 如果需要重新创建触发器,则重新创建触发器 if (reCreateTriggers) { reCreateNoteTableTriggers(db); reCreateDataTableTriggers(db); } + // 如果旧版本不等于新版本,则抛出异常 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion + "fails"); } } + // 升级数据库到V2版本 private void upgradeToV2(SQLiteDatabase db) { + // 删除旧版本的NOTE表 db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); + // 删除旧版本的DATA表 db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); + // 创建新版本的NOTE表 createNoteTable(db); + // 创建新版本的DATA表 createDataTable(db); } + // 升级到V3版本 private void upgradeToV3(SQLiteDatabase db) { - // drop unused triggers + + // 删除更新笔记修改日期的触发器 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"); - // add a column for gtask id + + // 在笔记表中添加GTASK_ID列 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''"); - // add a trash system folder + + // 创建一个垃圾桶文件夹 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); } + // 将数据库升级到V4版本 private void upgradeToV4(SQLiteDatabase db) { + // 执行SQL语句,向NOTE表中添加VERSION列,类型为INTEGER,默认值为0 db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0"); } diff --git a/src/src/net/micode/notes/data/NotesProvider.java b/src/src/net/micode/notes/data/NotesProvider.java index edb0a60..8f12ccd 100644 --- a/src/src/net/micode/notes/data/NotesProvider.java +++ b/src/src/net/micode/notes/data/NotesProvider.java @@ -36,12 +36,16 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE; public class NotesProvider extends ContentProvider { + // 定义UriMatcher private static final UriMatcher mMatcher; + // 定义数据库帮助类 private NotesDatabaseHelper mHelper; + // 定义日志标签 private static final String TAG = "NotesProvider"; + // 定义Uri匹配常量 private static final int URI_NOTE = 1; private static final int URI_NOTE_ITEM = 2; private static final int URI_DATA = 3; @@ -50,6 +54,7 @@ public class NotesProvider extends ContentProvider { private static final int URI_SEARCH = 5; private static final int URI_SEARCH_SUGGEST = 6; + // 静态代码块,初始化UriMatcher static { mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); @@ -65,6 +70,7 @@ 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. */ + // 定义搜索结果投影 private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," @@ -73,6 +79,7 @@ public class NotesProvider extends ContentProvider { + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + // 定义搜索查询语句 private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" @@ -81,6 +88,7 @@ public class NotesProvider extends ContentProvider { @Override public boolean onCreate() { + // 初始化数据库帮助类 mHelper = NotesDatabaseHelper.getInstance(getContext()); return true; } @@ -93,25 +101,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查询笔记 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查询数据 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"); @@ -149,13 +162,17 @@ public class NotesProvider extends ContentProvider { @Override public Uri insert(Uri uri, ContentValues values) { + // 获取可写的数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); long dataId = 0, noteId = 0, insertedId = 0; + // 根据传入的uri匹配对应的操作 switch (mMatcher.match(uri)) { case URI_NOTE: + // 插入笔记 insertedId = noteId = db.insert(TABLE.NOTE, null, values); break; case URI_DATA: + // 插入数据 if (values.containsKey(DataColumns.NOTE_ID)) { noteId = values.getAsLong(DataColumns.NOTE_ID); } else { @@ -183,16 +200,24 @@ public class NotesProvider extends ContentProvider { @Override public int delete(Uri uri, String selection, String[] selectionArgs) { + // 初始化删除计数器 int count = 0; + // 初始化ID String id = null; + // 获取可写数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); + // 初始化删除数据标志 boolean deleteData = false; + // 根据URI匹配删除操作 switch (mMatcher.match(uri)) { case URI_NOTE: + // 添加ID大于0的条件 selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; + // 删除符合条件的记录 count = db.delete(TABLE.NOTE, selection, selectionArgs); break; case URI_NOTE_ITEM: + // 获取URI中的ID id = uri.getPathSegments().get(1); /** * ID that smaller than 0 is system folder which is not allowed to @@ -229,76 +254,114 @@ public class NotesProvider extends ContentProvider { @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + // 定义更新条数 int count = 0; + // 定义id String id = null; + // 获取可写数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); + // 定义是否更新数据 boolean updateData = false; + // 根据uri匹配对应的操作 switch (mMatcher.match(uri)) { case URI_NOTE: + // 增加note版本号 increaseNoteVersion(-1, selection, selectionArgs); + // 更新note表 count = db.update(TABLE.NOTE, values, selection, selectionArgs); break; case URI_NOTE_ITEM: + // 获取id id = uri.getPathSegments().get(1); + // 增加note版本号 increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); + // 更新note表 count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; case URI_DATA: + // 更新data表 count = db.update(TABLE.DATA, values, selection, selectionArgs); + // 设置更新数据为true updateData = true; break; case URI_DATA_ITEM: + // 获取id id = uri.getPathSegments().get(1); + // 更新data表 count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); + // 设置更新数据为true updateData = true; break; default: + // 抛出异常 throw new IllegalArgumentException("Unknown URI " + uri); } + // 如果更新条数大于0 if (count > 0) { + // 如果更新数据为true if (updateData) { + // 通知note表改变 getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } + // 通知uri改变 getContext().getContentResolver().notifyChange(uri, null); } + // 返回更新条数 return count; } + // 解析selection字符串 private String parseSelection(String selection) { + // 如果selection不为空,则返回" AND (" + selection + ')',否则返回空字符串 return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + // 增加笔记版本号 private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { + // 创建一个StringBuilder对象,用于拼接SQL语句 StringBuilder sql = new StringBuilder(120); + // 拼接UPDATE语句 sql.append("UPDATE "); + // 拼接表名 sql.append(TABLE.NOTE); + // 拼接SET语句 sql.append(" SET "); + // 拼接版本号字段 sql.append(NoteColumns.VERSION); + // 拼接版本号增加1的语句 sql.append("=" + NoteColumns.VERSION + "+1 "); + // 如果id大于0或者selection不为空,则拼接WHERE语句 if (id > 0 || !TextUtils.isEmpty(selection)) { sql.append(" WHERE "); } + // 如果id大于0,则拼接id条件 if (id > 0) { sql.append(NoteColumns.ID + "=" + String.valueOf(id)); } + // 如果selection不为空,则拼接selection条件 if (!TextUtils.isEmpty(selection)) { + // 如果id大于0,则解析selection String selectString = id > 0 ? parseSelection(selection) : selection; + // 遍历selectionArgs,替换selection中的占位符 for (String args : selectionArgs) { selectString = selectString.replaceFirst("\\?", args); } + // 拼接selection条件 sql.append(selectString); } + // 执行SQL语句 mHelper.getWritableDatabase().execSQL(sql.toString()); } @Override public String getType(Uri uri) { // TODO Auto-generated method stub + // 获取Uri的类型 return null; } diff --git a/src/src/net/micode/notes/gtask/data/MetaData.java b/src/src/net/micode/notes/gtask/data/MetaData.java index 3a2050b..34b21ba 100644 --- a/src/src/net/micode/notes/gtask/data/MetaData.java +++ b/src/src/net/micode/notes/gtask/data/MetaData.java @@ -26,54 +26,71 @@ import org.json.JSONObject; public class MetaData extends Task { + // 定义一个常量,用于日志输出 private final static String TAG = MetaData.class.getSimpleName(); + // 定义一个私有变量,用于存储相关任务ID private String mRelatedGid = null; + // 设置元数据 public void setMeta(String gid, JSONObject metaInfo) { try { + // 将相关任务ID添加到元数据中 metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { + // 日志输出错误信息 Log.e(TAG, "failed to put related gid"); } + // 设置备注 setNotes(metaInfo.toString()); + // 设置名称 setName(GTaskStringUtils.META_NOTE_NAME); } + // 获取相关任务ID public String getRelatedGid() { return mRelatedGid; } + // 判断是否需要保存 @Override public boolean isWorthSaving() { return getNotes() != null; } + // 根据远程JSON设置内容 @Override public void setContentByRemoteJSON(JSONObject js) { super.setContentByRemoteJSON(js); if (getNotes() != null) { try { + // 将备注转换为JSON对象 JSONObject metaInfo = new JSONObject(getNotes().trim()); + // 获取相关任务ID mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); } catch (JSONException e) { + // 日志输出警告信息 Log.w(TAG, "failed to get related gid"); + // 将相关任务ID设置为null mRelatedGid = null; } } } + // 根据本地JSON设置内容 @Override public void setContentByLocalJSON(JSONObject js) { // this function should not be called throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); } + // 从内容中获取本地JSON @Override public JSONObject getLocalJSONFromContent() { throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); } + // 获取同步操作 @Override public int getSyncAction(Cursor c) { throw new IllegalAccessError("MetaData:getSyncAction should not be called"); diff --git a/src/src/net/micode/notes/gtask/data/Node.java b/src/src/net/micode/notes/gtask/data/Node.java index 63950e0..f486a50 100644 --- a/src/src/net/micode/notes/gtask/data/Node.java +++ b/src/src/net/micode/notes/gtask/data/Node.java @@ -47,10 +47,15 @@ public abstract class Node { private boolean mDeleted; + // 构造函数,初始化Node对象 public Node() { + // 初始化mGid为null mGid = null; + // 初始化mName为空字符串 mName = ""; + // 初始化mLastModified为0 mLastModified = 0; + // 初始化mDeleted为false mDeleted = false; } diff --git a/src/src/net/micode/notes/gtask/data/SqlData.java b/src/src/net/micode/notes/gtask/data/SqlData.java index d3ec3be..aea0e9b 100644 --- a/src/src/net/micode/notes/gtask/data/SqlData.java +++ b/src/src/net/micode/notes/gtask/data/SqlData.java @@ -36,41 +36,58 @@ 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 }; + // 定义一个常量,用于标识数据的ID列 public static final int DATA_ID_COLUMN = 0; + // 定义一个常量,用于标识数据的MIME类型列 public static final int DATA_MIME_TYPE_COLUMN = 1; + // 定义一个常量,用于标识数据的CONTENT列 public static final int DATA_CONTENT_COLUMN = 2; + // 定义一个常量,用于标识数据的DATA1列 public static final int DATA_CONTENT_DATA_1_COLUMN = 3; + // 定义一个常量,用于标识数据的DATA3列 public static final int DATA_CONTENT_DATA_3_COLUMN = 4; + // 定义一个ContentResolver对象,用于访问内容提供者 private ContentResolver mContentResolver; + // 定义一个布尔值,用于标识是否创建 private boolean mIsCreate; + // 定义一个长整型变量,用于存储数据的ID private long mDataId; + // 定义一个字符串变量,用于存储数据的MIME类型 private String mDataMimeType; + // 定义一个字符串变量,用于存储数据的CONTENT private String mDataContent; + // 定义一个长整型变量,用于存储数据的DATA1 private long mDataContentData1; + // 定义一个字符串变量,用于存储数据的DATA3 private String mDataContentData3; + // 定义一个ContentValues对象,用于存储数据的差异 private ContentValues mDiffDataValues; + // 构造函数,用于创建一个新的SqlData对象 public SqlData(Context context) { mContentResolver = context.getContentResolver(); mIsCreate = true; @@ -82,6 +99,7 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + // 构造函数,用于从Cursor中加载数据 public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); mIsCreate = false; @@ -89,6 +107,7 @@ public class SqlData { mDiffDataValues = new ContentValues(); } + // 从Cursor中加载数据 private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -97,6 +116,7 @@ public class SqlData { mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } + // 设置数据 public void setContent(JSONObject js) throws JSONException { long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; if (mIsCreate || mDataId != dataId) { @@ -130,6 +150,7 @@ public class SqlData { mDataContentData3 = dataContentData3; } + // 获取数据 public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); @@ -144,28 +165,43 @@ public class SqlData { return js; } + // 提交数据 + // 提交数据 public void commit(long noteId, boolean validateVersion, long version) { + // 如果是创建 if (mIsCreate) { + // 如果数据ID无效且数据值中包含ID列 if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { + // 移除ID列 mDiffDataValues.remove(DataColumns.ID); } + // 添加NOTE_ID列 mDiffDataValues.put(DataColumns.NOTE_ID, noteId); + // 插入数据 Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); try { + // 获取数据ID mDataId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { + // 打印错误日志 Log.e(TAG, "Get note id error :" + e.toString()); + // 抛出异常 throw new ActionFailureException("create note failed"); } } else { + // 如果数据值不为空 if (mDiffDataValues.size() > 0) { + // 更新结果 int result = 0; + // 如果不验证版本 if (!validateVersion) { + // 更新数据 result = mContentResolver.update(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); } else { + // 更新数据,验证版本 result = mContentResolver.update(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE @@ -173,16 +209,21 @@ public class SqlData { String.valueOf(noteId), String.valueOf(version) }); } + // 如果更新结果为0 if (result == 0) { + // 打印警告日志 Log.w(TAG, "there is no update. maybe user updates note when syncing"); } } } + // 清空数据值 mDiffDataValues.clear(); + // 设置为非创建 mIsCreate = false; } + // 获取数据的ID public long getId() { return mDataId; } diff --git a/src/src/net/micode/notes/gtask/data/SqlNote.java b/src/src/net/micode/notes/gtask/data/SqlNote.java index 79a4095..8aa46d6 100644 --- a/src/src/net/micode/notes/gtask/data/SqlNote.java +++ b/src/src/net/micode/notes/gtask/data/SqlNote.java @@ -122,105 +122,173 @@ public class SqlNote { private ArrayList mDataList; + // 构造函数,初始化SqlNote对象 public SqlNote(Context context) { + // 保存上下文 mContext = context; + // 获取ContentResolver mContentResolver = context.getContentResolver(); + // 标记为创建 mIsCreate = true; + // 初始化ID为无效ID mId = INVALID_ID; + // 初始化提醒日期为0 mAlertDate = 0; + // 获取默认背景颜色ID mBgColorId = ResourceParser.getDefaultBgId(context); + // 获取当前时间作为创建日期 mCreatedDate = System.currentTimeMillis(); + // 初始化是否有附件为0 mHasAttachment = 0; + // 获取当前时间作为修改日期 mModifiedDate = System.currentTimeMillis(); + // 初始化父ID为0 mParentId = 0; + // 初始化片段为空字符串 mSnippet = ""; + // 初始化类型为笔记 mType = Notes.TYPE_NOTE; + // 初始化小部件ID为无效ID mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; + // 初始化小部件类型为无效类型 mWidgetType = Notes.TYPE_WIDGET_INVALIDE; + // 初始化原始父ID为0 mOriginParent = 0; + // 初始化版本号为0 mVersion = 0; + // 初始化ContentValues对象 mDiffNoteValues = new ContentValues(); + // 初始化数据列表 mDataList = new ArrayList(); } + // 构造函数,用于从Cursor中加载SqlNote对象 public SqlNote(Context context, Cursor c) { + // 保存上下文 mContext = context; + // 获取ContentResolver mContentResolver = context.getContentResolver(); + // 标记为未创建 mIsCreate = false; + // 从Cursor中加载SqlNote对象 loadFromCursor(c); + // 初始化数据列表 mDataList = new ArrayList(); + // 如果类型为Notes.TYPE_NOTE,则加载内容 if (mType == Notes.TYPE_NOTE) loadDataContent(); + // 初始化ContentValues mDiffNoteValues = new ContentValues(); } + // 构造函数,传入上下文和id public SqlNote(Context context, long id) { + // 保存上下文 mContext = context; + // 获取内容解析器 mContentResolver = context.getContentResolver(); + // 标记为未创建 mIsCreate = false; + // 从游标中加载 loadFromCursor(id); + // 创建数据列表 mDataList = new ArrayList(); + // 如果类型为笔记,则加载内容 if (mType == Notes.TYPE_NOTE) loadDataContent(); + // 创建内容值 mDiffNoteValues = new ContentValues(); } + // 从游标中加载数据 private void loadFromCursor(long id) { + // 声明游标变量 Cursor c = null; try { + // 从ContentResolver中查询数据 c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", new String[] { String.valueOf(id) }, null); + // 如果游标不为空 if (c != null) { + // 将游标移动到下一行 c.moveToNext(); + // 从游标中加载数据 loadFromCursor(c); } else { + // 如果游标为空,则输出警告日志 Log.w(TAG, "loadFromCursor: cursor = null"); } } finally { + // 关闭游标 if (c != null) c.close(); } } + // 从游标中加载数据 private void loadFromCursor(Cursor c) { + // 获取ID mId = c.getLong(ID_COLUMN); + // 获取提醒日期 mAlertDate = c.getLong(ALERTED_DATE_COLUMN); + // 获取背景颜色ID mBgColorId = c.getInt(BG_COLOR_ID_COLUMN); + // 获取创建日期 mCreatedDate = c.getLong(CREATED_DATE_COLUMN); + // 获取是否有附件 mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN); + // 获取修改日期 mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN); + // 获取父ID mParentId = c.getLong(PARENT_ID_COLUMN); + // 获取片段 mSnippet = c.getString(SNIPPET_COLUMN); + // 获取类型 mType = c.getInt(TYPE_COLUMN); + // 获取小部件ID mWidgetId = c.getInt(WIDGET_ID_COLUMN); + // 获取小部件类型 mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); + // 获取版本 mVersion = c.getLong(VERSION_COLUMN); } + // 加载数据内容 private void loadDataContent() { + // 声明游标 Cursor c = null; + // 清空数据列表 mDataList.clear(); try { + // 查询数据 c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, "(note_id=?)", new String[] { String.valueOf(mId) }, null); + // 如果游标不为空 if (c != null) { + // 如果游标中没有数据 if (c.getCount() == 0) { + // 打印警告日志 Log.w(TAG, "it seems that the note has not data"); return; } + // 遍历游标 while (c.moveToNext()) { + // 创建SqlData对象 SqlData data = new SqlData(mContext, c); + // 将数据添加到数据列表中 mDataList.add(data); } } else { + // 打印警告日志 Log.w(TAG, "loadDataContent: cursor = null"); } } finally { + // 关闭游标 if (c != null) c.close(); } @@ -228,7 +296,9 @@ public class SqlNote { public boolean setContent(JSONObject js) { try { + // 获取note对象 JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + // 如果note的类型是系统文件夹,则不能设置 if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { Log.w(TAG, "cannot set system folder"); } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { @@ -359,51 +429,82 @@ public class SqlNote { return true; } + // 获取内容 public JSONObject getContent() { try { + // 创建一个JSONObject对象 JSONObject js = new JSONObject(); + // 如果mIsCreate为true,说明还没有在数据库中创建 if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } + // 创建一个JSONObject对象 JSONObject note = new JSONObject(); + // 如果mType为Notes.TYPE_NOTE if (mType == Notes.TYPE_NOTE) { + // 将mId放入note中 note.put(NoteColumns.ID, mId); + // 将mAlertDate放入note中 note.put(NoteColumns.ALERTED_DATE, mAlertDate); + // 将mBgColorId放入note中 note.put(NoteColumns.BG_COLOR_ID, mBgColorId); + // 将mCreatedDate放入note中 note.put(NoteColumns.CREATED_DATE, mCreatedDate); + // 将mHasAttachment放入note中 note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment); + // 将mModifiedDate放入note中 note.put(NoteColumns.MODIFIED_DATE, mModifiedDate); + // 将mParentId放入note中 note.put(NoteColumns.PARENT_ID, mParentId); + // 将mSnippet放入note中 note.put(NoteColumns.SNIPPET, mSnippet); + // 将mType放入note中 note.put(NoteColumns.TYPE, mType); + // 将mWidgetId放入note中 note.put(NoteColumns.WIDGET_ID, mWidgetId); + // 将mWidgetType放入note中 note.put(NoteColumns.WIDGET_TYPE, mWidgetType); + // 将mOriginParent放入note中 note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent); + // 将note放入js中 js.put(GTaskStringUtils.META_HEAD_NOTE, note); + // 创建一个JSONArray对象 JSONArray dataArray = new JSONArray(); + // 遍历mDataList for (SqlData sqlData : mDataList) { + // 获取sqlData的内容 JSONObject data = sqlData.getContent(); + // 如果data不为空 if (data != null) { + // 将data放入dataArray中 dataArray.put(data); } } + // 将dataArray放入js中 js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); + // 如果mType为Notes.TYPE_FOLDER或Notes.TYPE_SYSTEM } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { + // 将mId放入note中 note.put(NoteColumns.ID, mId); + // 将mType放入note中 note.put(NoteColumns.TYPE, mType); + // 将mSnippet放入note中 note.put(NoteColumns.SNIPPET, mSnippet); + // 将note放入js中 js.put(GTaskStringUtils.META_HEAD_NOTE, note); } + // 返回js return js; } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); } + // 返回null return null; } @@ -441,53 +542,72 @@ public class SqlNote { } public void commit(boolean validateVersion) { + // 如果是创建 if (mIsCreate) { + // 如果id为无效id且mDiffNoteValues中包含NoteColumns.ID if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { + // 从mDiffNoteValues中移除NoteColumns.ID mDiffNoteValues.remove(NoteColumns.ID); } + // 插入数据到Notes.CONTENT_NOTE_URI,返回uri Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues); try { + // 从uri中获取id mId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { + // 如果获取id失败,打印错误日志,抛出ActionFailureException Log.e(TAG, "Get note id error :" + e.toString()); throw new ActionFailureException("create note failed"); } + // 如果id为0,抛出IllegalStateException if (mId == 0) { throw new IllegalStateException("Create thread id failed"); } + // 如果类型为Notes.TYPE_NOTE if (mType == Notes.TYPE_NOTE) { + // 遍历mDataList,调用commit方法 for (SqlData sqlData : mDataList) { sqlData.commit(mId, false, -1); } } } else { + // 如果id小于等于0且id不是Notes.ID_ROOT_FOLDER和Notes.ID_CALL_RECORD_FOLDER if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { + // 打印错误日志,抛出IllegalStateException Log.e(TAG, "No such note"); throw new IllegalStateException("Try to update note with invalid id"); } + // 如果mDiffNoteValues不为空 if (mDiffNoteValues.size() > 0) { + // 版本号加1 mVersion ++; int result = 0; + // 如果不验证版本号 if (!validateVersion) { + // 更新数据 result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + NoteColumns.ID + "=?)", new String[] { String.valueOf(mId) }); } else { + // 更新数据,验证版本号 result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "(" + NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)", new String[] { String.valueOf(mId), String.valueOf(mVersion) }); } + // 如果没有更新,打印警告日志 if (result == 0) { Log.w(TAG, "there is no update. maybe user updates note when syncing"); } } + // 如果类型为Notes.TYPE_NOTE if (mType == Notes.TYPE_NOTE) { + // 遍历mDataList,调用commit方法 for (SqlData sqlData : mDataList) { sqlData.commit(mId, validateVersion, mVersion); } diff --git a/src/src/net/micode/notes/gtask/data/Task.java b/src/src/net/micode/notes/gtask/data/Task.java index 6a19454..217d80e 100644 --- a/src/src/net/micode/notes/gtask/data/Task.java +++ b/src/src/net/micode/notes/gtask/data/Task.java @@ -33,18 +33,25 @@ import org.json.JSONObject; public class Task extends Node { + // 定义一个常量,用于打印日志 private static final String TAG = Task.class.getSimpleName(); + // 定义一个布尔变量,表示任务是否完成 private boolean mCompleted; + // 定义一个字符串变量,用于存储任务的备注 private String mNotes; + // 定义一个JSONObject变量,用于存储任务的元信息 private JSONObject mMetaInfo; + // 定义一个Task变量,用于存储任务的前一个兄弟任务 private Task mPriorSibling; + // 定义一个TaskList变量,用于存储任务的父任务列表 private TaskList mParent; + // 构造函数,初始化任务 public Task() { super(); mCompleted = false; @@ -54,6 +61,7 @@ public class Task extends Node { mMetaInfo = null; } + // 获取创建任务的JSON对象 public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -103,6 +111,7 @@ public class Task extends Node { return js; } + // 获取更新任务的JSON对象 public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -135,6 +144,7 @@ public class Task extends Node { return js; } + // 根据远程JSON设置任务内容 public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -175,6 +185,7 @@ public class Task extends Node { } } + // 根据本地JSON设置任务内容 public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { @@ -204,6 +215,7 @@ public class Task extends Node { } } + // 获取本地JSON对象 public JSONObject getLocalJSONFromContent() { String name = getName(); try { @@ -247,6 +259,7 @@ public class Task extends Node { } } + // 设置任务的元信息 public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { @@ -258,6 +271,7 @@ public class Task extends Node { } } + // 获取同步动作 public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; @@ -311,39 +325,48 @@ public class Task extends Node { return SYNC_ACTION_ERROR; } + // 判断任务是否值得保存 public boolean isWorthSaving() { return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) || (getNotes() != null && getNotes().trim().length() > 0); } + // 设置任务是否完成 public void setCompleted(boolean completed) { this.mCompleted = completed; } + // 设置任务的备注 public void setNotes(String notes) { this.mNotes = notes; } + // 设置任务的前一个兄弟任务 public void setPriorSibling(Task priorSibling) { this.mPriorSibling = priorSibling; } + // 设置任务的父任务列表 public void setParent(TaskList parent) { this.mParent = parent; } + // 获取任务是否完成 public boolean getCompleted() { return this.mCompleted; } + // 获取任务的备注 public String getNotes() { return this.mNotes; } + // 获取任务的前一个兄弟任务 public Task getPriorSibling() { return this.mPriorSibling; } + // 获取任务的父任务列表 public TaskList getParent() { return this.mParent; }