diff --git a/doc/实践模板-开源软件泛读、标注和维护报告文档.docx b/doc/实践模板-开源软件泛读、标注和维护报告文档.docx new file mode 100644 index 0000000..bb1ee6b Binary files /dev/null and b/doc/实践模板-开源软件泛读、标注和维护报告文档.docx differ diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/data/Contact.java b/src/xiaomi/Notes-master/src/net/micode/notes/data/Contact.java index d97ac5d..f43b896 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/data/Contact.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/data/Contact.java @@ -25,19 +25,39 @@ import android.util.Log; import java.util.HashMap; +/** + * @Package: net.micode.notes.data + * @ClassName: Contact + * @Description: + * Contact类是一个用于获取联系人信息的工具类,包含有一个方法getContact,通过给定的电话号码来实现获取联系人信息的功能。 + * 并且使用缓存和错误日志记录功能来提高程序的稳定性和效率。 + * @Author: Dong Jiaqi + * @CreateDate: 12/21/2023 19:31 PM + */ public class Contact { - private static HashMap sContactCache; - private static final String TAG = "Contact"; + + private static HashMap sContactCache;//定义了一个静态的HashMap变量sContactCache + private static final String TAG = "Contact";//定义了一个静态的字符串常量TAG 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 = '+')"; + /* + *声明了一个字符串常量CALLER_ID_SELECTION, + *其中使用了函数调用PHONE_NUMBERS_EQUAL用来匹配电话号码,同时还使用了条件语句限制数据类型为电话号码联系人ID. + */ + /** + * 该方法定义了一个getContact,通过给定的电话号码实现获取联系人信息的功能。 + * getContact中有2个输入参数分别是context和phoneNumber,其中前者是一个Context对象,提供了访问应用程序的信息和资源的环境;后者就是给定输入的电话号码 + * 有3种返回结果,其中返回sContactCache.get(phoneNumber)代表通过sContactCache这一个HashMap对象获取并且返回电话号码对应的联系人的名字 + * 返回 name则是直接返回联系人的名字;返回 null表示发生了IndexOutOfBoundsException异常; + */ public static String getContact(Context context, String phoneNumber) { - if(sContactCache == null) { + if(sContactCache == null) {//确保HashMap对象不会空,始终指向一个实例化的HashMap对象 sContactCache = new HashMap(); } @@ -46,21 +66,36 @@ public class Contact { } String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); //获取电话号码的最小匹配形式,比如字母换数字,然后用replace方发将CALLER_ID_SELECTION中的"+"替换为最小匹配后的电话号码 Cursor cursor = context.getContentResolver().query( Data.CONTENT_URI, new String [] { Phone.DISPLAY_NAME }, selection, new String[] { phoneNumber }, null); + /* + *context.getContentResolver()获取应用的内容解析器对象,然后调用query()方法进行查询, + *接受了Data.CONTENT_URI等参数,其中Data.CONTENT_URI表示联系人数据的URI; + *new String []{Phone.DISPLAY_NAME}表示联系人的显示名称; + *selection表示查询的条件; + *new String[] {phoneNumber}表示替换前的原始电话号码,也是查询的参数; + *null表示没有排序方式 + */ + //如果查询结果不为空,将第一个结果的显示名称存储在缓存中,并返回该名称;否则,记录到错误日志并返回null。 if (cursor != null && cursor.moveToFirst()) { + /* + * 语句块功能:是尝试获取联系人的名称,并且存储在name变量中,再将电话号码和对应联系人名字放到sContactCache缓存中去 + * 如果获取失败,发生IndexOutOfBoundsException报错,那么把错误信息按照错误级别写进日志,有利于debug的进行。 + * 为什么:通过使用缓存和try-catch-finally语句块,可以确保在获取联系人姓名时不会因为异常而导致程序崩溃,并且在结束查询后及时释放资源,提高了程序的稳定性和效率。 + * 同时错误信息被写进日志文件,可以有助于开发人员调试和故障排除时找到问题所在。 + */ try { String name = cursor.getString(0); sContactCache.put(phoneNumber, name); return name; } catch (IndexOutOfBoundsException e) { - Log.e(TAG, " Cursor get string error " + e.toString()); + Log.e(TAG, " Cursor get string error " + e.toString());//调用Log.e()方法,把错误信息写到日志。 return null; } finally { cursor.close(); diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/data/Notes.java b/src/xiaomi/Notes-master/src/net/micode/notes/data/Notes.java index f240604..10cb934 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/data/Notes.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/data/Notes.java @@ -17,6 +17,18 @@ package net.micode.notes.data; import android.net.Uri; +/** + * @Package: net.micode.notes.data + * @ClassName: Notes + * @Description: + * Notes类是一个笔记应用的数据类,用于定义笔记和文件夹的属性和操作。它包括一些常量定义、URI定义和接口定义,以及文本笔记和通话记录笔记的数据列定义。 + * 在这个类中,定义了一些常量用来标记; + * 还定义了一些 常量,用于传递数据。 + * 以及一些数据列的定义,包括笔记和文件夹的 ID、创建日期、修改日期、提醒日期、内容摘要、小部件 ID、小部件类型、背景颜色ID等。 + * 这个类的功能是定义了笔记应用中笔记和文件夹的数据结构,并提供了相关的常量、URI 和接口定义,以及文本笔记和通话记录笔记的数据列定义,方便应用程序对这些数据进行操作和管理。 + * @Author: Dong Jiaqi + * @CreateDate: 12/22/2023 0:53 AM + */ public class Notes { public static final String AUTHORITY = "micode_notes"; public static final String TAG = "Notes"; @@ -46,6 +58,7 @@ public class Notes { public static final int TYPE_WIDGET_2X = 0; public static final int TYPE_WIDGET_4X = 1; + //定义了一个静态内部类DataConstants,包含2个变量NOTE和CALL_NOTE,前者用于表示数据类型为文本笔记类型;后者用于表示数据类型为通话类型 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 +74,10 @@ 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 +184,10 @@ public class Notes { public static final String VERSION = "version"; } + /** + * 定义了一个接口DataColumns,其中包含了一些用来表示笔记和文件及的数据列的常量 + * 这些常量可以用于在应用程序当中访问和操作笔记和文件夹的相关数据。通过使用这些常量,我们可以方便地获取和更新笔记当中的信息和数据列。 + */ public interface DataColumns { /** * The unique ID for a row @@ -241,28 +262,34 @@ public class Notes { public static final String DATA5 = "data5"; } + /** + * TextNote是一个静态内部类,实现了接口DataColumns,定义了一些常量和方法来表示文本笔记的属性和操作 + */ 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 String MODE = DATA1;//表示文本笔记的模式,用来指示是否处于检查模式当中,值为1表示检查模式,为0表示普通模式 - public static final int MODE_CHECK_LIST = 1; + 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 Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");//表示文本笔记的内容URI,用来访问和操作笔记中的数,值是两者拼合成的URI } + /** + * CallNote是一个静态内部类,实现了接口DataColumns,定义了一些常量和方法来表示通话笔记的属性和操作 + */ public static final class CallNote implements DataColumns { /** * Call date for this record *

Type: INTEGER (long)

*/ - public static final String CALL_DATE = DATA1; + public static final String CALL_DATE = DATA1;//表示通话笔记的通话日期 /** * Phone number for this record diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java index ffe5d57..50c84e5 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesDatabaseHelper.java @@ -26,7 +26,17 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; - +/** + * @Package: net.micode.notes.data + * @ClassName: NotesDatabaseHelper + * @Description: + * 这是一个用于管理小米便签的数据库类NotesDatabaseHelper,这个类继承自SQLiteOpenHelper + * ,用于创建和管理小米便签所需要用到的数据库以及表结构。 + * 类当中包含了5大部分,分别是常量的定义,表结构的创建,触发器的创建,系统文件夹创建以及数据库表的创建 + * 该类是整个小米便签软件中用于数据库管理的核心类。 + * @Author: Dong Jiaqi + * @CreateDate: 12/23/2023 0:44 AM + */ public class NotesDatabaseHelper extends SQLiteOpenHelper { private static final String DB_NAME = "note.db"; @@ -61,7 +71,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + - ")"; + ")";//这是用于创建便签表的SQL语句,定义了便签表的结构,包含便签各种属性和字段,存储了用户创建的所有便签的信息。 private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + @@ -76,14 +86,14 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + - ")"; + ")";//这是用于定义数据表结构的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 + * 当将便签移动到文件夹时,通过增加文件夹的便签数量来实现 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER increase_folder_count_on_update "+ @@ -95,7 +105,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Decrease folder's note count when move note from folder + * 将便签从文件夹中移出时,通过减少文件夹的便签数量来实现 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + @@ -108,7 +118,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Increase folder's note count when insert new note to the folder + * 当向文件夹中插入新的便签时,通过增加文件夹的便签数量来实现 */ private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + @@ -120,7 +130,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Decrease folder's note count when delete note from the folder + * 当从文件夹中删除便签时,通过减少文件夹的便签数量来实现 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + @@ -133,7 +143,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when insert data with type {@link DataConstants#NOTE} + * 当插入新的数据类型时,需要更新便签的内容{@link DataConstants#NOTE} */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + @@ -172,7 +182,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Delete datas belong to note which has been deleted + * 删除已经被删除的便签所关联的数据 */ private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + @@ -183,7 +193,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Delete notes belong to folder which has been deleted + * 删除已经被删除的文件夹所包含的便签 */ private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + @@ -194,7 +204,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Move notes belong to folder which has been moved to trash folder + * 将已经被移动到回收站文件夹的文件夹中的便签也一并移动到回收站文件夹 */ private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + @@ -210,6 +220,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { super(context, DB_NAME, null, DB_VERSION); } + /** + * 创建便签表、重新创建触发器并创建系统文件夹 + * @param: 一个SQLiteDatabase对象db,表示要创建便签的数据库 + */ public void createNoteTable(SQLiteDatabase db) { db.execSQL(CREATE_NOTE_TABLE_SQL); reCreateNoteTableTriggers(db); @@ -217,6 +231,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { Log.d(TAG, "note table has been created"); } + /** + * 重新创建和便签表相关的触发器,会在数据库中对触发器进行设置,以便在特定操作时自动执行相应的处理过程。 + * @param: db + */ 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 +253,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); } + /** + * 初始化数据库中的系统文件夹,确保在数据库中存在且具有特定的属性和类型标识。 + * @param: db + */ private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); @@ -277,6 +299,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { Log.d(TAG, "data table has been created"); } + /** + * 重新创建一个和数据表相关的触发器,先删除3个已经存在的触发器,再一次创建3个新的触发器 + * @param db + */ 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 +313,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); } + /** + * 这个方法确保了在整个应用程序当中只创建了一个NotesDatabaseHelper实例 + * 并且提供了一个全局访问点,让其他部分可以方便地获取该实例并且使用数据库功能,提供了对数据库的统一管理和访问 + * @param context Context是一个表示当前应用程序的环境的类,包含了应用程序全局信息。 + * 在这个方法中,Context context参数用于创建NoteDatabaseHelper实例时所需的环境信息, + * 传入参数确保正确地获取了应用程序的环境信息。 + * @return mInstance是一个实例,如果为null表示还没有创建这个类的实例,会创建一个新的实例并且赋值给它。 + * 无论是新建的实例或者是已经存在的实例按照mInstance返回。避免了多个实例的创建和内存的浪费。 + */ static synchronized NotesDatabaseHelper getInstance(Context context) { if (mInstance == null) { mInstance = new NotesDatabaseHelper(context); @@ -300,11 +335,21 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { createDataTable(db); } + /** + * 这个方法的功能是根据新旧版本号,依次来执行相应的数据库升级操作,从而确保数据库的结构和内容能够与新版本要求相匹配。 + * @param db 表示要升级的数据库对象 + * @param oldVersion 表示当前数据库的旧版本号 + * @param newVersion 表示需要升级到的新版本号 + */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { boolean reCreateTriggers = false; boolean skipV2 = false; + /** + * 该语句块是一个数据库升级的逻辑处理,它的功能是按照旧版本号和新版本号的要求执行相应的数据库升级操作,并进行相关的标记和检查。 + * 这个语句块的目的是实现数据库版本升级,通过这样的逻辑判断,可以保证数据库的顺序升级,并在每个升级阶段进行必要的操作和标记,以确保升级的正确性和完整性。 + */ if (oldVersion == 1) { upgradeToV2(db); skipV2 = true; // this upgrade including the upgrade from v2 to v3 diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java index edb0a60..d7b3880 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/data/NotesProvider.java @@ -34,7 +34,15 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.NotesDatabaseHelper.TABLE; - +/** + * @Package: net.micode.notes.data + * @ClassName: NotesProvider + * @Description: + * 这个类是对ContentProvider类的扩展,功能是提供小米便签应用程序的数据, + * 在类当中实现了数据库的增添删减修改查找操作,并且可以处理与搜索有关的查询。 + * @Author: Dong Jiaqi + * @CreateDate: 12/23/2023 23:27 PM + */ public class NotesProvider extends ContentProvider { private static final UriMatcher mMatcher; @@ -50,6 +58,10 @@ public class NotesProvider extends ContentProvider { private static final int URI_SEARCH = 5; private static final int URI_SEARCH_SUGGEST = 6; + /** + * 定义了一个静态代码块,初始化UriMatcher对象并且添加匹配规则 + * 调用了addURI()方法,向mMatcher这一个UriMatcher对象中添加了一系列匹配规则 + */ static { mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); @@ -79,18 +91,36 @@ public class NotesProvider extends ContentProvider { + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + /** + * onCreate()方法的功能是在应用程序启动时进行初始化数据库帮助类 + * @return 返回true表示创建成功 + */ @Override public boolean onCreate() { mHelper = NotesDatabaseHelper.getInstance(getContext()); return true; } + /** + * query()方法用于执行查询操作,根据传入的URI参数,选择执行不同的查询语句返回 + * @param uri 要查询数据的URI,用来确定要操作的表和行 + * @param projection 表示查询返回的列的数组,可以指定查询结果中包含的列 + * @param selection 表示用于筛选的条件 + * @param selectionArgs 表示selection中的占位符的值 + * @param sortOrder 表示查询结果的排序顺序 + * @return 返回查询结果的游标(Cursor)对象(c) + */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor c = null; SQLiteDatabase db = mHelper.getReadableDatabase(); String id = null; + /** + * 这是一个switch语句块,用来针对不同的URI进行不同的操作。 + * 对于3种类型的URI,进行了不同的操作,如果URI不匹配这任何一种情况,就视为ILLegalArgumentException异常,表示URI不被支持或不合法 + * 这个语句块的目的是为了处理不同类型的URI,并且根据URI类型执行相应的数据库查询操作,属于典型的Android ContentProvider的逻辑处理代码 + */ switch (mMatcher.match(uri)) { case URI_NOTE: c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, @@ -130,6 +160,11 @@ public class NotesProvider extends ContentProvider { return null; } + /** + * 这个语句块是在处理 URI_SEARCH 和 URI_SEARCH_SUGGEST 的情况下执行的,主要功能是执行数据库的原始查询(rawQuery)操作,用于搜索符合指定条件的数据,并将结果存储在 Cursor 对象中。 + * 如果在执行数据库查询时发生 IllegalStateException 异常,那么异常信息会被捕获,并通过 Log.e() 方法记录下来,方便在日志中进行查看和分析。 + * 目的是为了在执行数据库查询时,确保搜索关键词被正确地格式化并传入查询语句中,同时也确保在出现数据库查询异常时能够进行相应的异常处理和记录。 + */ try { searchString = String.format("%%%s%%", searchString); c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, @@ -147,6 +182,12 @@ public class NotesProvider extends ContentProvider { return c; } + /** + * 用于执行插入操作,根据传入的URI参数,选择在不同的表中进行插入 + * @param uri 传入数据的URI,用来确定要操作的表和行 + * @param values 表示要插入的数据集合 + * @return 返回插入数据的URI,即ContentUris.withAppendedId(uri, insertedId) + */ @Override public Uri insert(Uri uri, ContentValues values) { SQLiteDatabase db = mHelper.getWritableDatabase(); @@ -181,6 +222,13 @@ public class NotesProvider extends ContentProvider { return ContentUris.withAppendedId(uri, insertedId); } + /** + * 执行删除操作,根据传入URI参数,选择在不同的表中执行删除操作 + * @param uri 传入数据的URI,用来确定要操作的表和行 + * @param selection 表示删除的条件 + * @param selectionArgs 表示selection中的占位符的值 + * @return 返回收到影响的内容行数 + */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; @@ -227,12 +275,25 @@ public class NotesProvider extends ContentProvider { return count; } + /** + * 执行更新操作,根据传入URI参数,在不同的表中进行更新 + * @param uri 传入数据的URI,用来确定要操作的表和行 + * @param values 表示要更新的数据集合 + * @param selection 表示用于筛选的条件 + * @param selectionArgs 表示selection中的占位符的值 + * @return 返回收到影响的行数 + */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; String id = null; SQLiteDatabase db = mHelper.getWritableDatabase(); boolean updateData = false; + /** + * 这个语句块根据传入的 URI(Uniform Resource Identifier)进行匹配,并执行相应的操作。 + * 目的是根据传入的 URI 执行相应的数据库更新操作。根据不同的 URI,可以实现对不同表和记录的更新操作。 + * 通过 switch-case 结构,可以清晰地处理不同的情况,并执行相应的操作,同时也提供了一个默认的处理方式来处理未知的 URI。 + */ switch (mMatcher.match(uri)) { case URI_NOTE: increaseNoteVersion(-1, selection, selectionArgs); @@ -267,10 +328,21 @@ public class NotesProvider extends ContentProvider { return count; } + /** + * 用于解析查询条件,将其转换为SQL语句中的WHERE子句 + * @param selection 表示用来解析的条件 + * @return 返回转换后的字符串 + */ private String parseSelection(String selection) { return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + /** + * 用于增加便签的版本号 + * @param id 要增加版本号的便签的ID + * @param selection 查询选择条件,用来筛选要增加版本号的便签 + * @param selectionArgs 表示占位符参数 + */ private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); @@ -296,6 +368,10 @@ public class NotesProvider extends ContentProvider { mHelper.getWritableDatabase().execSQL(sql.toString()); } + /** + * 该方法根据需要自行补充实现,给开源后其他软件工程师留下了增添空间 + * @param uri 数据的URI + */ @Override public String getType(Uri uri) { // TODO Auto-generated method stub diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java index 3a2050b..1699caa 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/MetaData.java @@ -24,13 +24,33 @@ import net.micode.notes.tool.GTaskStringUtils; import org.json.JSONException; import org.json.JSONObject; - +/** + * @Package: net.micode.notes.gtask.data + * @ClassName: MetaData + * @Description: + * MetaData类继承自 Task 类。它用于处理任务的元数据信息,并封装了一些操作元数据的方法。 + * 这个类用于管理任务的元数据信息,包括相关的 GID,在设置和获取元数据的同时,还提供了判断任务是否值得保存的方法,以及根据远程 JSON 数据设置任务内容的方法。 + * 同时,限制了部分方法的访问,以确保其按照预期的方式被使用。 + * @Author: Dong Jiaqi + * @CreateDate: 12/24/2023 9:53 AM + */ public class MetaData extends Task { private final static String TAG = MetaData.class.getSimpleName(); private String mRelatedGid = null; + /** + * 作用是将给定的 GID 和其他元数据信息添加到任务的注释信息中,并设置任务的名称为固定的值。 + * @param gid 表示任务的全局唯一标识符(Global Task ID),是一个字符串类型的参数。 + * @param metaInfo 表示元数据信息,是一个 JSONObject 对象,包含任务的其他相关信息。 + */ public void setMeta(String gid, JSONObject metaInfo) { + /** + * 这个语句块作用是向 metaInfo 这个 JSONObject 对象中添加一个键值对,其中键是 GTaskStringUtils.META_HEAD_GTASK_ID,值是变量 gid。 + * 使用了 try-catch 块来捕获可能抛出的 JSONException 异常。 + * 为什么要这么写呢: + * 因为在 Java 中,JSONObject 的 put 方法声明了可能抛出 JSONException 异常。这意味着在调用 put 方法时,需要进行异常处理,否则会导致编译错误。因此,为了保证程序的健壮性,开发者通常会在调用可能会引发异常的方法时使用 try-catch 块进行异常处理,以防止程序异常终止。 + */ try { metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { @@ -40,19 +60,29 @@ public class MetaData extends Task { setName(GTaskStringUtils.META_NOTE_NAME); } + //作用是获取任务的相关 GID,并返回其字符串形式。 public String getRelatedGid() { - return mRelatedGid; + return mRelatedGid;//返回值是一个字符串类型的变量 mRelatedGid,表示相关 GID(Global Task ID)。mRelatedGid 是一个成员变量,它保存了在任务的元数据信息中提取出来的相关 GID。 } + //作用是判断任务是否值得保存。它通过检查任务的注释信息是否为null来确定任务是否值得保存。 @Override public boolean isWorthSaving() { - return getNotes() != null; + return getNotes() != null;//如果注释信息不为null,则返回true,表示任务值得保存;反之,如果注释信息为null,则返回false,表示任务不值得保存。 } + /** + * 功能是从远程 JSON 对象中获取任务的内容,包括基本的任务属性和元数据信息,并将其存储到当前的 Task 对象中。 + * @param js JSONObject 对象,表示从远程服务器获取的任务信息。 + */ @Override public void setContentByRemoteJSON(JSONObject js) { super.setContentByRemoteJSON(js); if (getNotes() != null) { + /** + * 这个语句块作用是从任务的注释信息中提取相关 GID,并将其保存到变量 mRelatedGid 中。 + * 使用try-catch块是为了处理可能抛出的异常,确保程序稳定性 + */ try { JSONObject metaInfo = new JSONObject(getNotes().trim()); mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); @@ -66,7 +96,7 @@ public class MetaData extends Task { @Override public void setContentByLocalJSON(JSONObject js) { // this function should not be called - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); + throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");//抛出一个IllegalAccessError异常,并且提供异常的详细描述信息 } @Override diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java index 63950e0..c2a5253 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Node.java @@ -20,24 +20,33 @@ import android.database.Cursor; import org.json.JSONObject; +/** + * @Package: net.micode.notes.gtask.data + * @ClassName: Node + * @Description: + * Node类是一个抽象类,定义了一些常量字段以及一些方法,还定义了节点对象的基本属性和操作, + * * 同时提供了抽象方法来处理节点内容的设置和同步操作的创建按,以及普通方法来设置和获取节点的属性。 + * @Author: Dong Jiaqi + * @CreateDate: 12/24/2023 10:23 AM + */ public abstract class Node { - public static final int SYNC_ACTION_NONE = 0; + public static final int SYNC_ACTION_NONE = 0;//表示没有同步操作。 - public static final int SYNC_ACTION_ADD_REMOTE = 1; + public static final int SYNC_ACTION_ADD_REMOTE = 1;//表示远程添加操作。 - public static final int SYNC_ACTION_ADD_LOCAL = 2; + 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_REMOTE = 3;//表示远程删除操作。 - public static final int SYNC_ACTION_DEL_LOCAL = 4; + 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_REMOTE = 5;//表示远程更新操作。 - public static final int SYNC_ACTION_UPDATE_LOCAL = 6; + public static final int SYNC_ACTION_UPDATE_LOCAL = 6;//表示本地更新操作。 - public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; + public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;//表示更新冲突操作。 - public static final int SYNC_ACTION_ERROR = 8; + public static final int SYNC_ACTION_ERROR = 8;//表示同步错误操作。 private String mGid; @@ -66,34 +75,66 @@ public abstract class Node { public abstract int getSyncAction(Cursor c); + /** + * 设置节点对象的全局唯一标识符(gid)。 + * @param gid 表示要设置的全局唯一标识符,它是一个字符串类型的参数。可以是任意有效的字符串,用于对节点进行唯一标识和区分。 + */ public void setGid(String gid) { this.mGid = gid; } + /** + * 设置节点对象的名称。它通过将传入的字符串参数 name 赋值给节点对象的成员变量 mName 来实现。 + * @param name 表示要设置的节点名称,它是一个字符串类型的参数。可以是任意有效的字符串,用于标识节点的名称或描述。 + */ public void setName(String name) { this.mName = name; } + /** + * 设置节点对象的最后修改时间。它通过将传入的长整型参数 lastModified 赋值给节点对象的成员变量 mLastModified 来实现。 + * @param lastModified 表示要设置的节点的最后修改时间,它是一个长整型参数,用来记录节点对象的最后修改时间 + */ public void setLastModified(long lastModified) { this.mLastModified = lastModified; } + /** + * 设置节点对象的删除状态。它通过将传入的布尔类型参数 deleted 赋值给节点对象的成员变量 mDeleted 来实现。 + * @param deleted 表示要设置的节点的删除状态,它是一个布尔类型的参数。当该参数为 true 时,表示节点被标记为已删除;当该参数为 false 时,表示节点未被删除。 + */ public void setDeleted(boolean deleted) { this.mDeleted = deleted; } + /** + * 获取节点对象的全局唯一标识符(gid)。它通过返回节点对象的成员变量 mGid 的值来实现。 + * @return this.mGid表示节点的全局唯一标识符。这是一个字符串类型的返回值,用于表示节点对象的唯一标识符。 + */ public String getGid() { return this.mGid; } + /** + * 获取节点对象的名称。它通过返回节点对象的成员变量 mName 的值来实现。 + * @return this.mName表示节点的名称。这是一个字符串类型的返回值,用于表示节点对象的名称或描述。 + */ public String getName() { return this.mName; } + /** + * 获取节点对象的最后修改时间。它通过返回节点对象的成员变量 mLastModified 的值来实现。 + * @return this.mLastModified表示节点的最后修改时间。这是一个长整型的返回值 + */ public long getLastModified() { return this.mLastModified; } + /** + * 获取节点对象的删除状态。它通过返回节点对象的成员变量 mDeleted 的布尔值来实现。 + * @return 表示节点的删除状态。当返回值为 true 时,表示节点已被标记为已删除;当返回值为 false 时,表示节点未被删除。 + */ public boolean getDeleted() { return this.mDeleted; } diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java index d3ec3be..60f3022 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlData.java @@ -34,26 +34,33 @@ import net.micode.notes.gtask.exception.ActionFailureException; import org.json.JSONException; import org.json.JSONObject; - +/** + * @Package: net.micode.notes.gtask.data + * @ClassName: SqlData + * @Description: + * 封装了对数据库中数据的读取、更新和提交操作,可以用于管理和操作数据库中的数据。 + * @Author: Dong Jiaqi + * @CreateDate: 12/24/2023 10:58 AM + */ public class SqlData { private static final String TAG = SqlData.class.getSimpleName(); - private static final int INVALID_ID = -99999; + private static final int INVALID_ID = -99999;//定义了一个名为 INVALID_ID 的私有静态整型常量,并赋值为 -99999,被用来表示无效的 ID 值。 public static final String[] PROJECTION_DATA = new String[] { DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, DataColumns.DATA3 - }; + };//定义了一个名为 PROJECTION_DATA 的字符串数组,其中包含了一组列名 - public static final int DATA_ID_COLUMN = 0; + public static final int DATA_ID_COLUMN = 0;//表示数据的 ID 在数据列中的索引位置,即第一列。 - public static final int DATA_MIME_TYPE_COLUMN = 1; + public static final int DATA_MIME_TYPE_COLUMN = 1;//表示数据的 MIME 类型在数据列中的索引位置,即第二列。 - public static final int DATA_CONTENT_COLUMN = 2; + 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_1_COLUMN = 3;//表示数据的内容数据1在数据列中的索引位置,即第四列。 - public static final int DATA_CONTENT_DATA_3_COLUMN = 4; + public static final int DATA_CONTENT_DATA_3_COLUMN = 4;//表示数据的内容数据3在数据列中的索引位置,即第五列。 private ContentResolver mContentResolver; @@ -71,36 +78,54 @@ public class SqlData { private ContentValues mDiffDataValues; + /** + * 构造函数,接收一个Context对象作为参数,并初始化成员变量。 + * @param context 用于获取应用程序的上下文信息,以便后续操作数据库。 + */ public SqlData(Context context) { - mContentResolver = context.getContentResolver(); + mContentResolver = context.getContentResolver();//这是构造方法的定义,表明这是一个公共的构造方法,并且接受一个 Context 类型的参数。 mIsCreate = true; mDataId = INVALID_ID; mDataMimeType = DataConstants.NOTE; - mDataContent = ""; + mDataContent = "";//成员变量初始化 mDataContentData1 = 0; mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); + mDiffDataValues = new ContentValues();//创建新的ContentValues对象 } + /** + * 构造函数,接收一个Context对象和一个Cursor对象作为参数,并根据Cursor对象加载成员变量的值。 + * @param context 用于获取应用程序的上下文信息,以便后续操作数据库; + * @param c Cursor 对象用于获取数据库中的数据。 + */ public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); mIsCreate = false; - loadFromCursor(c); + loadFromCursor(c);//调用 loadFromCursor() 方法,将传入的 Cursor 对象作为参数,以从 Cursor 对象中加载数据库中的数据到 SqlData 对象的成员变量中。 mDiffDataValues = new ContentValues(); } + /** + * 从传入的 Cursor 对象中加载数据,并将数据赋值给 SqlData 对象的各个成员变量。 + * @param c Cursor 对象用于获取数据库中的数据 + */ private void loadFromCursor(Cursor c) { - mDataId = c.getLong(DATA_ID_COLUMN); - mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); + mDataId = c.getLong(DATA_ID_COLUMN);//从 Cursor 对象中获取指定列索引为 DATA_ID_COLUMN 的长整型数据,并赋值给 mDataId 成员变量。 + mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);//从 Cursor 对象中获取指定列索引为 DATA_MIME_TYPE_COLUMN 的字符串数据,并赋值给 mDataMimeType 成员变量。 mDataContent = c.getString(DATA_CONTENT_COLUMN); mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } + /** + * 根据传入的JSON对象设置成员变量的值。根据JSON对象中的字段值判断是否需要更新成员变量,并将需要更新的值存储在mDiffDataValues对象中。 + * @param js JSONObject对象用于获取数据 + * @throws JSONException 抛出的异常 + */ public void setContent(JSONObject js) throws JSONException { - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; - if (mIsCreate || mDataId != dataId) { - mDiffDataValues.put(DataColumns.ID, dataId); + long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;//检查 JSON 对象 js 中是否包含名为 DataColumns.ID 的字段,如果包含则将其转换为 long 类型并赋给 dataId,否则将 INVALID_ID 赋给 dataId。 + if (mIsCreate || mDataId != dataId) {//检查是否正在创建新数据(mIsCreate 为 true),或者已有数据的 dataId 是否与新获取的 dataId 不同。 + mDiffDataValues.put(DataColumns.ID, dataId);//如果满足条件,则将 DataColumns.ID 和对应的 dataId 放入 mDiffDataValues 中。 } mDataId = dataId; @@ -130,42 +155,53 @@ public class SqlData { mDataContentData3 = dataContentData3; } + /** + * 将成员变量的值转换为JSON对象并返回。 + * @return JSONObject 对象包含了 SqlData 对象中各个成员变量的值,使用相应的键值表示。如果当前对象是新创建的,则打印错误日志并返回 null。 + * @throws JSONException 抛出的异常 + */ public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } JSONObject js = new JSONObject(); - js.put(DataColumns.ID, mDataId); - js.put(DataColumns.MIME_TYPE, mDataMimeType); + js.put(DataColumns.ID, mDataId);//将类的成员变量 mDataId 的值存储到 js 对象中,使用键名 DataColumns.ID。 + js.put(DataColumns.MIME_TYPE, mDataMimeType);//将类的成员变量 mDataMimeType 的值存储到 js 对象中,使用键名 DataColumns.MIME_TYPE js.put(DataColumns.CONTENT, mDataContent); js.put(DataColumns.DATA1, mDataContentData1); js.put(DataColumns.DATA3, mDataContentData3); return js; } + /** + * 提交数据的更改到数据库中。如果是新创建的数据,则将数据插入数据库并获取其ID;如果是已存在的数据,则根据mDiffDataValues对象中的差异字段值更新数据库中对应的记录。 + * @param noteId 便签的ID,表示要提交数据的便签的ID + * @param validateVersion 布尔值,表示是否需要验证版本号 + * @param version 长整型数,表示版本号 + */ public void commit(long noteId, boolean validateVersion, long version) { - if (mIsCreate) { + 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); + mDiffDataValues.put(DataColumns.NOTE_ID, noteId); //设置便签的ID + 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"); } - } else { + } else {//如果不是新创建的数据 if (mDiffDataValues.size() > 0) { int result = 0; - if (!validateVersion) { + if (!validateVersion) {//如果不用验证版本,直接更新数据 result = mContentResolver.update(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); - } else { + } else {//如果要验证版本,根据版本号更新数据 result = mContentResolver.update(ContentUris.withAppendedId( Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE @@ -179,10 +215,14 @@ public class SqlData { } } - mDiffDataValues.clear(); + mDiffDataValues.clear();//提交后清空数据 mIsCreate = false; } + /** + * 返回成员变量mDataId的值。 + * @return 成员信息的ID + */ public long getId() { return mDataId; } diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java index 79a4095..d2ebbd3 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/SqlNote.java @@ -37,7 +37,14 @@ import org.json.JSONObject; import java.util.ArrayList; - +/** + * @Package: net.micode.notes.gtask.data + * @ClassName: SqlNote + * @Description: + * SqlNote类包含用于处理小米便签的数据库操作,是一个用于管理便签数据的工具类 + * @Author: Dong Jiaqi + * @CreateDate: 12/24/2023 17:18 PM + */ public class SqlNote { private static final String TAG = SqlNote.class.getSimpleName(); @@ -52,9 +59,9 @@ public class SqlNote { NoteColumns.VERSION }; - public static final int ID_COLUMN = 0; + public static final int ID_COLUMN = 0;//便签的ID列的索引为0 - public static final int ALERTED_DATE_COLUMN = 1; + public static final int ALERTED_DATE_COLUMN = 1;//提醒日期列的索引为1 public static final int BG_COLOR_ID_COLUMN = 2; @@ -120,8 +127,12 @@ public class SqlNote { private ContentValues mDiffNoteValues; - private ArrayList mDataList; + private ArrayList mDataList;//用Java中的ArrayList类定义了一个SqlData对象 mDataList,用于存储从数据库查询中返回的便签数据 + /** + * 构造方法,用来创建一个新的SqlNote对象,初始化新的 SqlNote 对象,并将其成员变量设置为默认值。 + * @param context 要使用到的上下文对象 + */ public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -143,6 +154,11 @@ public class SqlNote { mDataList = new ArrayList(); } + /** + * 另外一个构造方法,用于创建一个新的 SqlNote 对象,并从给定的 Cursor 中加载数据。 + * @param context 要使用的上下文对象 + * @param c 要加载数据的游标对象 + */ public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -154,6 +170,11 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); } + /** + * 另一个构造方法,用于创建一个新的 SqlNote 对象,并从给定的 ID 加载数据。 + * @param context 要使用的上下文对象 + * @param id 要加载数据的便签的ID + */ public SqlNote(Context context, long id) { mContext = context; mContentResolver = context.getContentResolver(); @@ -166,8 +187,17 @@ public class SqlNote { } + /** + * 通过笔记 ID 从数据库中加载便签数据,并将其存储在 SqlNote 对象的成员变量中 + * @param id 要加载数据的便签 ID + */ private void loadFromCursor(long id) { Cursor c = null; + /** + * try-finally语句块 用于在加载笔记数据后正确地关闭游标,以确保资源的释放。 + * 这么写是为了避免在发生异常或错误时,游标未被关闭而导致资源泄漏。 + * 通过在 finally 块中关闭游标,可以确保无论查询是否成功,都会正确地释放资源。 + */ try { c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)", new String[] { @@ -185,6 +215,10 @@ public class SqlNote { } } + /** + * 从游标中加载便签数据,并将其存储在 SqlNote 对象的成员变量中。 + * @param c 要从中加载数据的游标 + */ private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); @@ -200,9 +234,17 @@ public class SqlNote { mVersion = c.getLong(VERSION_COLUMN); } + /** + * 根据特定笔记 ID 加载与之关联的数据内容,并将其存储在数据列表中供进一步操作和展示。 + * 通过查询数据库,遍历游标并创建相应的数据对象,可以方便地加载数据内容并进行后续处理。 + */ private void loadDataContent() { Cursor c = null; mDataList.clear(); + /** + * 从数据库中查询与指定笔记 ID 相关联的数据内容,并将查询结果存储在 mDataList 列表中。 + * 这种写法可以保证在出现异常时,也能正确地关闭游标,避免资源泄露和其他问题。 + */ try { c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA, "(note_id=?)", new String[] { @@ -226,7 +268,19 @@ public class SqlNote { } } + + /** + * 根据传入的JSONObject对象设置内容。 + * 根据JSONObject中的不同字段值更新类中的属性,并将差异值存储在mDiffNoteValues中。 + * @param js 包含要设置的内容的JSONObject对象。 + * @return 如果成功设置内容,则返回true;否则返回false + */ public boolean setContent(JSONObject js) { + /** + * try块中的代码用于解析JSON对象并获取其中的数据。如果解析过程中发生了JSONException异常,那么程序会跳转到catch块中,并执行其中的代码。 + * catch块中的代码主要用于打印异常信息并返回一个布尔值false,以表示解析失败。 + * 这样能够通过捕获异常并进行适当的处理,可以避免程序崩溃或产生不可预料的结果。 + */ try { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { @@ -237,14 +291,14 @@ public class SqlNote { .getString(NoteColumns.SNIPPET) : ""; if (mIsCreate || !mSnippet.equals(snippet)) { mDiffNoteValues.put(NoteColumns.SNIPPET, snippet); - } + }//判断是否需要更新笔记的摘要(snippet)。它通过比较当前对象的mSnippet属性和传入的参数snippet,如果两者不相等,则将新的摘要值存储在mDiffNoteValues中。 mSnippet = snippet; int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE) : Notes.TYPE_NOTE; if (mIsCreate || mType != type) { mDiffNoteValues.put(NoteColumns.TYPE, type); - } + }//检查是否正在创建新的笔记(mIsCreate为true),或者当前笔记的类型与传入的类型值不相等(mType != type)。如果满足其中一个条件,就会将新的类型值存储在mDiffNoteValues中。 mType = type; } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); @@ -359,6 +413,10 @@ public class SqlNote { return true; } + /** + * 将当前对象的属性值转换为一个JSON对象并返回。 + * @return 返回转换后的JSONObject对象作为结果 + */ public JSONObject getContent() { try { JSONObject js = new JSONObject(); @@ -407,39 +465,74 @@ public class SqlNote { return null; } + /** + * 设置当前对象的父级ID属性,并将该属性的值存储到mDiffNoteValues中。 + * @param id long类型,表示要设置的父级ID + */ public void setParentId(long id) { mParentId = id; mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } + /** + * 将指定的Google Tasks任务的ID(gid)放入mDiffNoteValues中,以便后续判断属性变化时进行处理。 + * @param gid 字符串类型,表示要设置的Google Tasks任务的ID + */ public void setGtaskId(String gid) { mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } + /** + * 将指定的同步ID(syncId)放入mDiffNoteValues中,以便后续判断属性变化时进行处理。 + * @param syncId long类型,表示要设置的同步ID + */ public void setSyncId(long syncId) { mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); } + /** + * 将当前对象的本地修改状态重置为未修改。 + */ public void resetLocalModified() { mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); } + /** + * 获取当前对象ID属性值,将其作为结果返回 + * @return 当前对象的ID属性值 + */ public long getId() { return mId; } + /** + * 获取当前对象的父级ID属性值,并返回该值。 + * @return 当前对象的父级ID属性值 + */ public long getParentId() { return mParentId; } + /** + * 获取当前对象的摘要属性值,并返回该值。 + * @return 当前对象的摘要属性值 + */ public String getSnippet() { return mSnippet; } + /** + * 判断当前对象是否为“便签”类型。 + * @return 布尔类型的数据,表示当前对象是否为“便签”类型。如果是便签类型,则返回true;否则返回false。 + */ public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } + /** + * 将当前对象所代表的笔记或文件夹信息提交到数据库中进行保存,并更新当前对象的属性值。 + * @param validateVersion 布尔类型的数据,表示是否需要验证版本信息。如果为true,则在更新时需要比较版本号;否则不需要比较版本号。 + */ public void commit(boolean validateVersion) { if (mIsCreate) { if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java index 6a19454..4fd9506 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/Task.java @@ -31,7 +31,16 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; - +/** + * @Package: net.micode.notes.gtask.data + * @ClassName: Task + * @Description: + * Task类继承自Node类。该类用于表示一个任务,在Google任务管理系统中使用。 + * 它包含了一些任务的属性和方法,例如任务是否已完成、笔记内容、元数据等。 + * 另外,该类还提供了一些用于生成和解析JSON格式数据的方法,以便与Google任务管理系统进行交互。 + * @Author: Dong Jiaqi + * @CreateDate: 12/24/2023 19:48 PM + */ public class Task extends Node { private static final String TAG = Task.class.getSimpleName(); @@ -45,17 +54,27 @@ public class Task extends Node { private TaskList mParent; + /** + * 构造方法在对象创建时被调用,用于初始化对象的属性。 + * 所有属性都被初始化为初始值或者null。 + */ public Task() { - super(); - mCompleted = false; - mNotes = null; - mPriorSibling = null; - mParent = null; - mMetaInfo = null; + super();//调用父类Node的构造方法确保父类的属性得到正确初始化 + mCompleted = false;//任务完成状态设置为未完成 + mNotes = null;//暂时没有便签笔记 + mPriorSibling = null;//当前任务没有前节点 + mParent = null;//当前任务没有父节点 + mMetaInfo = null;//当前任务没有元数据信息 } + /** + * 用于生成一个表示创建任务操作的JSON对象。 + * 如果在生成JSON对象的过程中发生异常,将会抛出一个ActionFailureException异常,并打印错误信息。 + * @param actionId 表示操作的唯一标识符。 + * @return 生成的JSONObject对象,包含了表示创建任务操作的各个字段和对应的值。 + */ public JSONObject getCreateAction(int actionId) { - JSONObject js = new JSONObject(); + JSONObject js = new JSONObject();//创建一个空的JSONObject对象。 try { // action_type @@ -97,12 +116,17 @@ public class Task extends Node { } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("fail to generate task-create jsonobject"); + throw new ActionFailureException("fail to generate task-create jsonobject");//抛出异常 } return js; } + /** + * 用于生成一个表示更新任务操作的JSON对象。 + * @param actionId 表示操作的唯一标识符。 + * @return 生成的JSONObject对象,包含了表示更新任务操作的各个字段和对应的值。 + */ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -135,6 +159,11 @@ public class Task extends Node { return js; } + /** + * 用于根据传入的JSONObject对象设置任务的各个字段值。 + * 保持任务对象的状态与传入的JSON数据一致。 + * @param js 表示一个JSONObject对象,包含了任务的各个字段和对应的值。 + */ public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -175,17 +204,25 @@ public class Task extends Node { } } + /** + * 用于根据传入的本地JSONObject对象设置任务的名称,从而与本地数据保持一致。 + * @param js 包含了本地数据的各个字段和对应的值。 + */ public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); } + /** + * 根据传入的JSONObject对象解析任务的名称字段,并将其设置为任务对象的名称。 + * 同时,还会检查便签的类型,只有当类型为普通便签时才会继续设置任务名称。 + */ try { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { + if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {//检查便签类型是不是普通便签 Log.e(TAG, "invalid type"); return; } @@ -204,6 +241,11 @@ public class Task extends Node { } } + /** + * 根据任务对象的内容生成一个本地的JSONObject对象。 + * @return 对于新创建的任务:返回构造好的JSONObject对象js。 + * 对于已同步的任务:返回mMetaInfo对象本身。 + */ public JSONObject getLocalJSONFromContent() { String name = getName(); try { @@ -247,6 +289,10 @@ public class Task extends Node { } } + /** + * 设置任务的元数据。 + * @param metaData MetaData对象,表示任务的元数据。 + */ public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { @@ -258,6 +304,16 @@ public class Task extends Node { } } + /** + * 根据传入的Cursor对象和任务的元数据判断同步操作的类型。 + * @param c Cursor对象c,用于查询本地数据库中的任务数据。 + * @return 整数,表示同步操作的类型 + * SYNC_ACTION_NONE:无需同步 + * SYNC_ACTION_UPDATE_LOCAL:需要更新本地任务 + * SYNC_ACTION_UPDATE_REMOTE:需要更新远程任务 + * SYNC_ACTION_UPDATE_CONFLICT:存在冲突,需要解决 + * SYNC_ACTION_ERROR:同步出错 + */ public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; @@ -311,39 +367,80 @@ public class Task extends Node { return SYNC_ACTION_ERROR; } + /** + * 判断当前任务是否值得保存。 + * @return 类型为boolean,true表示任务值得保存,false表示任务不值得保存。 + */ public boolean isWorthSaving() { return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) || (getNotes() != null && getNotes().trim().length() > 0); } + /** + * 设置当前任务的完成状态。 + * 调用这个方法,可以更新当前任务的完成状态,以便在应用程序中进行相应的展示或处理。 + * @param completed boolean类型的参数,用来表示当前任务的完成状态。 + */ public void setCompleted(boolean completed) { this.mCompleted = completed; } + /** + * 设置当前任务的备注信息。 + * 调用这个方法,可以更新当前任务的备注信息,以便在应用程序中进行相应的展示或处理。 + * @param notes String类型的参数,用来表示当前任务的备注信息。 + */ public void setNotes(String notes) { this.mNotes = notes; } + /** + * 设置当前任务的前一个兄弟任务。 + * 调用这个方法,可以建立任务之间的关联关系,例如设置任务的顺序、父子关系等。 + * @param priorSibling Task类型的参数,表示当前任务的前一个兄弟任务。 + */ public void setPriorSibling(Task priorSibling) { this.mPriorSibling = priorSibling; } + /** + * 设置当前任务的父任务列表。 + * 调用这个方法,可以建立任务之间的关联关系,例如设置任务的层级结构、父子关系等。 + * @param parent TaskList类型的参数,表示当前任务所属的父任务列表。 + */ public void setParent(TaskList parent) { this.mParent = parent; } + /** + * 获取当前任务的完成状态。 + * 调用这个方法,可以获取当前任务是否已经完成,以便在应用程序中进行相应的展示或处理。 + * @return 类型为boolean,true表示任务已完成,false表示任务未完成。 + */ public boolean getCompleted() { return this.mCompleted; } + /** + * 获取当前任务的备注信息。 + * @return 类型为String,表示当前任务的备注信息。如果任务没有备注信息,则返回一个空字符串。 + */ public String getNotes() { return this.mNotes; } + /** + * 获取当前任务的前一个兄弟任务。 + * @return 类型为Task,表示当前任务的前一个兄弟任务。如果当前任务没有前一个兄弟任务,则返回null。 + */ public Task getPriorSibling() { return this.mPriorSibling; } + /** + * 获取当前任务所属的父任务列表。 + * @return 类型为TaskList,表示当前任务所属的父任务列表。如果当前任务没有父任务列表,则返回null。 + */ public TaskList getParent() { return this.mParent; } diff --git a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java index 4ea21c5..b3d810b 100644 --- a/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java +++ b/src/xiaomi/Notes-master/src/net/micode/notes/gtask/data/TaskList.java @@ -30,19 +30,36 @@ import org.json.JSONObject; import java.util.ArrayList; +/** + * @Package: net.micode.notes.gtask.data + * @ClassName: TaskList + * @Description: + * TaskList继承自Node类。该类表示一个任务列表,具有管理任务列表及其子任务的功能。 + * 提供了创建、更新、删除任务列表以及管理子任务的方法,可以通过JSON对象进行远程和本地数据的转换,并提供了一系列对子任务进行操作的方法。 + * @Author: Dong Jiaqi + * @CreateDate: 12/24/2023 20:48 PM + */ public class TaskList extends Node { - private static final String TAG = TaskList.class.getSimpleName(); + private static final String TAG = TaskList.class.getSimpleName();//私有静态常量,用于在日志和调试中标识类名。 - private int mIndex; + private int mIndex;//私有整型变量,表示任务列表的索引。 - private ArrayList mChildren; + private ArrayList mChildren;//私有ArrayList,存储Task对象,表示该任务列表下的子任务列表。 + /** + * 构造方法,初始化一个空的任务列表,初始化mChildren为一个空的Task列表,将mIndex设置为1。 + */ public TaskList() { super(); mChildren = new ArrayList(); mIndex = 1; } + /** + * 根据给定的actionId创建一个用于创建任务列表的JSONObject对象。 + * @param actionId 整型参数,表示操作的ID。 + * @return 表示创建操作的JSONObject对象。 + */ public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -74,6 +91,11 @@ public class TaskList extends Node { return js; } + /** + * 根据给定的actionId创建一个用于更新任务列表的JSONObject对象。 + * @param actionId 整型参数,表示操作的ID。 + * @return 表示更新操作的JSONObject对象。 + */ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -103,6 +125,10 @@ public class TaskList extends Node { return js; } + /** + * 根据远程传入的JSON对象设置任务列表的内容。 + * @param js 表示从远程服务器返回的JSONObject对象,包含了任务列表的属性。 + */ public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -129,6 +155,10 @@ public class TaskList extends Node { } } + /** + * 根据本地JSON对象设置任务列表的内容。 + * @param js 表示从远程服务器返回的JSONObject对象,包含了任务列表的属性。 + */ public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); @@ -157,6 +187,10 @@ public class TaskList extends Node { } } + /** + * 根据任务列表的内容生成本地JSON对象。 + * @return 表示本地的JSONObject对象,包含了任务列表的属性信息。 + */ public JSONObject getLocalJSONFromContent() { try { JSONObject js = new JSONObject(); @@ -183,6 +217,17 @@ public class TaskList extends Node { } } + /** + * 根据数据库游标中的信息确定同步操作的类型。 + * @param c 表示一个Cursor对象,包含了当前任务列表的属性信息。 + * @return 表示同步操作的代码 + * SYNC_ACTION_NONE(不执行任何操作) + * SYNC_ACTION_UPDATE_LOCAL(更新本地) + * SYNC_ACTION_ERROR(同步操作出错) + * SYNC_ACTION_UPDATE_REMOTE(当前任务列表的同步ID是否与最后修改时间相同,更新远程) + * SYNC_ACTION_UPDATE_REMOTE(当前任务列表的同步ID是否与最后修改时间不相同,更新远程) + * SYNC_ACTION_ERROR(同步操作出错) + */ public int getSyncAction(Cursor c) { try { if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { @@ -216,10 +261,19 @@ public class TaskList extends Node { return SYNC_ACTION_ERROR; } + /** + * 获取子任务的数量。 + * @return 子任务的数量 + */ public int getChildTaskCount() { return mChildren.size(); } + /** + * 向任务列表中添加一个子任务。 + * @param task 表示要添加的子任务 + * @return boolean:表示是否成功将子任务添加到当前任务中,如果添加成功则返回true,否则返回false + */ public boolean addChildTask(Task task) { boolean ret = false; if (task != null && !mChildren.contains(task)) { @@ -234,6 +288,12 @@ public class TaskList extends Node { return ret; } + /** + * 在指定位置添加一个子任务。 + * @param task 表示要插入的子任务。 + * @param index 表示要插入的位置索引,从0开始计数。 + * @return boolean:表示是否成功将子任务插入到当前任务中的指定位置,如果插入成功则返回true,否则返回false。 + */ public boolean addChildTask(Task task, int index) { if (index < 0 || index > mChildren.size()) { Log.e(TAG, "add child task: invalid index"); @@ -260,6 +320,11 @@ public class TaskList extends Node { return true; } + /** + * 从任务列表中移除一个子任务。 + * @param task 表示要移除的子任务 + * @return boolean:表示是否成功从当前任务中移除了指定的子任务,如果移除成功则返回true,否则返回false。 + */ public boolean removeChildTask(Task task) { boolean ret = false; int index = mChildren.indexOf(task); @@ -281,6 +346,12 @@ public class TaskList extends Node { return ret; } + /** + * 移动指定子任务到新的位置。 + * @param task 表示要移动的子任务 + * @param index 表示要移动到的位置索引,从0开始计数。 + * @return boolean:表示是否成功将子任务移动到指定位置,如果移动成功则返回true,否则返回false + */ public boolean moveChildTask(Task task, int index) { if (index < 0 || index >= mChildren.size()) { @@ -299,6 +370,11 @@ public class TaskList extends Node { return (removeChildTask(task) && addChildTask(task, index)); } + /** + * 根据全局唯一标识符查找子任务。 + * @param gid 表示要查找的子任务的gid(全局唯一标识符) + * @return Task:如果找到具有匹配gid的子任务,则返回该子任务对象;如果未找到匹配的子任务,则返回null + */ public Task findChildTaskByGid(String gid) { for (int i = 0; i < mChildren.size(); i++) { Task t = mChildren.get(i); @@ -309,10 +385,20 @@ public class TaskList extends Node { return null; } + /** + * 获取指定子任务在任务列表中的索引。 + * @param task 表示要获取索引位置的子任务对象。 + * @return int:表示指定子任务在当前任务的子任务列表中的索引位置,如果子任务存在于列表中则返回其索引位置(从0开始计数),如果子任务不存在于列表中则返回-1。 + */ public int getChildTaskIndex(Task task) { return mChildren.indexOf(task); } + /** + * 根据索引获取子任务。 + * @param index 表示要获取子任务的索引位置,从0开始计数。 + * @return Task:表示位于指定索引位置的子任务对象,如果索引位置有效则返回该子任务对象,否则返回null。 + */ public Task getChildTaskByIndex(int index) { if (index < 0 || index >= mChildren.size()) { Log.e(TAG, "getTaskByIndex: invalid index"); @@ -321,6 +407,11 @@ public class TaskList extends Node { return mChildren.get(index); } + /** + * 根据全局唯一标识符获取子任务。 + * @param gid 表示要查找的子任务的gid + * @return Task:如果找到具有匹配gid的子任务,则返回匹配的子任务对象;如果未找到匹配的子任务,则返回null + */ public Task getChilTaskByGid(String gid) { for (Task task : mChildren) { if (task.getGid().equals(gid)) @@ -329,14 +420,26 @@ public class TaskList extends Node { return null; } + /** + * 获取任务列表的子任务列表。 + * @return ArrayList:表示当前任务的子任务列表,即包含所有子任务的ArrayList对象。 + */ public ArrayList getChildTaskList() { return this.mChildren; } + /** + * 设置任务列表的索引。 + * @param index 表示要设置的索引值 + */ public void setIndex(int index) { this.mIndex = index; } + /** + * 获取任务列表的索引。 + * @return 表示当前对象的索引值 + */ public int getIndex() { return this.mIndex; }