diff --git a/.idea/workspace.xml b/.idea/workspace.xml index de96205..7fb321c 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -10,6 +10,7 @@ +<<<<<<< HEAD <<<<<<< remotes/origin/cyx_branch @@ -85,13 +86,37 @@ ======= >>>>>>> local +======= + + + + + + + + + + + + + + + + + + + + + + +>>>>>>> 97f59e709a754d9ac92f018b602c051baead5aac - + @@ -119,7 +144,7 @@ "RunOnceActivity.cidr.known.project.marker": "true", "SHARE_PROJECT_CONFIGURATION_FILES": "true", "cidr.known.project.marker": "true", - "last_opened_file_path": "D:/softwareengineering/Notes-master", + "last_opened_file_path": "D:/TOUGE/gitProject", "project.structure.last.edited": "Modules", "project.structure.proportion": "0.17", "project.structure.side.proportion": "0.2", @@ -181,9 +206,7 @@ \ No newline at end of file diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java index e6a6be8..04001de 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java +++ b/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java @@ -45,6 +45,13 @@ public class SqlData { DataColumns.DATA3 }; /*这是一个Java类,名称为SqlData,其中定义了一些静态变量和常量,用于在类内和类外引用。 +<<<<<<< HEAD +第一行定义了一个名为TAG的静态常量字符串,用于在日志中标识该类。这个字符串的值是SqlData类的简单名称。 +第二行定义了一个名为INVALID_ID的私有静态常量整数,用于表示无效的ID。该值被设置为-99999。 +第三行定义了一个名为PROJECTION_DATA的公共静态常量字符串数组,用于定义一个查询所需返回的列。这些列包括DataColumns类中定义的ID、MIME_TYPE、CONTENT、DATA1和DATA3。 +这些变量和常量都被声明为静态的,这意味着它们属于类本身,而不是类的实例。因此,它们可以在类的所有实例之间共享和访问。 +这些变量和常量的使用可以提高代码的可读性和可维护性,并避免在代码中多次重复相同的值。*/ +======= 第一行定义了一个名为TAG的静态常量字符串,用于在日志中标识该类。这个字符串的值是SqlData类的简单名称。 @@ -53,6 +60,7 @@ public class SqlData { 第三行定义了一个名为PROJECTION_DATA的公共静态常量字符串数组,用于定义一个查询所需返回的列。这些列包括DataColumns类中定义的ID、MIME_TYPE、CONTENT、DATA1和DATA3。 这些变量和常量都被声明为静态的,这意味着它们属于类本身,而不是类的实例。因此,它们可以在类的所有实例之间共享和访问。这些变量和常量的使用可以提高代码的可读性和可维护性,并避免在代码中多次重复相同的值。*/ +>>>>>>> 25eb5a04c09307c5edd9569e8d491a90234c9d82 public static final int DATA_ID_COLUMN = 0; public static final int DATA_MIME_TYPE_COLUMN = 1; diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java b/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java index 79a4095..ec251ec 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java +++ b/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java @@ -51,7 +51,28 @@ public class SqlNote { NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID, NoteColumns.VERSION }; - +/*定义了一个名为SqlNote的类。这个类包含了一些静态常量和一个名为PROJECTION_NOTE的公共静态字符串数组,该数组包含了用于查询笔记数据的列名。 + +具体来说,PROJECTION_NOTE数组包含了以下列名: + +ID: 笔记的唯一标识符 +ALERTED_DATE: 笔记提醒的日期 +BG_COLOR_ID: 笔记背景颜色的标识符 +CREATED_DATE: 笔记创建的日期 +HAS_ATTACHMENT: 笔记是否有附件 +MODIFIED_DATE: 笔记最后修改的日期 +NOTES_COUNT: 笔记下的子笔记数量 +PARENT_ID: 父笔记的唯一标识符 +片段: 笔记的摘要 +类型: 笔记的类型 +WIDGET_ID: 关联的小部件的唯一标识符 +WIDGET_TYPE: 关联的小部件的类型 +SYNC_ID: 与笔记相关的同步服务的唯一标识符 +LOCAL_MODIFIED: 笔记是否在本地被修改过 +ORIGIN_PARENT_ID: 笔记的原始父笔记的唯一标识符 +GTASK_ID: 与Google Tasks相关的唯一标识符 +版本: 笔记的版本号 +这些列名可以用于查询笔记数据,并且在SqlNote类中被定义为静态常量,以便在整个应用程序中使用。*/ public static final int ID_COLUMN = 0; public static final int ALERTED_DATE_COLUMN = 1; @@ -85,7 +106,9 @@ public class SqlNote { public static final int GTASK_ID_COLUMN = 15; public static final int VERSION_COLUMN = 16; - +/*这是SqlNote类中定义的一些静态常量,它们表示在PROJECTION_NOTE数组中每个列名的索引位置。 +这些常量被用于访问查询结果中特定列的值。 + */ private Context mContext; private ContentResolver mContentResolver; @@ -121,7 +144,28 @@ public class SqlNote { private ContentValues mDiffNoteValues; private ArrayList mDataList; - +/*这是SqlNote类中的一些成员变量,它们被用于存储笔记的数据。下面是每个变量的含义: +mContext: 上下文对象,用于访问应用程序的资源和服务。 +mContentResolver: 内容解析器对象,用于访问应用程序的数据。 +mIsCreate: 表示这个对象是否代表一个新创建的笔记。 +mId: 笔记的唯一标识符。 +mAlertDate: 笔记提醒的日期。 +mBgColorId: 笔记背景颜色的标识符。 +mCreatedDate: 笔记创建的日期。 +mHasAttachment: 表示笔记是否有附件。 +mModifiedDate: 笔记最后修改的 +mParentId: 父笔记的唯一标识符。 +mSnippet: 笔记的摘要。 +mType: 笔记的类型。 +mWidgetId: 关联的小部件的唯一标识符。 +mWidgetType: 关联的小部件的类型。 +mOriginParent: 笔记的原始父笔记的唯一标识符。 +mVersion: 笔记的版本号。 +mDiffNoteValues: 一个ContentValues对象,包含了与这个笔记相关的差异数据。 +mDataList: 一个ArrayList对象,包含了这个笔记的子笔记数据。 +这些成员变量被用于存储SqlNote对象的状态,并且可以用于从数据库中读取和写入笔记数据。 +其中一些成员变量还可以用于在应用程序中显示笔记的相关信息。 + */ public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -142,7 +186,26 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } - +/*这是SqlNote类的构造函数,它用于创建一个新的SqlNote对象。在构造函数中,SqlNote对象的所有成员变量都被初始化为它们的默认值。具体来说,它们的初始值如下: +mContext: 传入的上下文对象。 +mContentResolver: 从上下文对象中获取的内容解析器对象。 +mIsCreate: 设置为true,表示这是一个新创建 +mId: 设置为INVALID_ID,表示这个笔记还没有在数据库中分配一个有效的唯一标识符。 +mAlertDate: 设置为0,表示这个笔记没有提醒日期。 +mBgColorId: 设置为应用程序的默认背景颜色。 +mCreatedDate: 设置为当前时间的毫秒数,表示这个笔记的创建日期。 +mHasAttachment: 设置为0,表示这个笔记没有附件。 +mModifiedDate: 设置为当前时间的毫秒数,表示这个笔记的最后修改日期。 +mParentId: 设置为0,表示这个笔记没有父笔记。 +mSnippet: 设置为空字符串,表示这个笔记没有摘要。 +mType: 设置为Notes.TYPE_NOTE,表示这个笔记是一个普通笔记。 +mWidgetId: 设置为AppWidgetManager.INVALID_APPWIDGET_ID,表示这个笔记没有关联的小部件。 +mWidgetType: 设置为Notes.TYPE_WIDGET_INVALIDE,表示这个笔记没有关联的小部件类型。 +mOriginParent: 设置为0,表示这个笔记没有原始父笔记。 +mVersion: 设置为0,表示这个笔记的版本号为0。 +mDiffNoteValues: 创建一个新的ContentValues对象,用于存储这个笔记的差异数据。 +mDataList: 创建一个新的ArrayList对象,用于存储这个笔记的子笔记数据。 +在构造函数中,所有的成员变量都被初始化为它们的默认值,因此这个SqlNote对象代表了一个刚刚创建的新笔记。*/ public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -153,7 +216,15 @@ public class SqlNote { loadDataContent(); mDiffNoteValues = new ContentValues(); } - +/*这是SqlNote类的另一个构造函数,用于从数据库游标中加载已有的SqlNote对象。在构造函数中,SqlNote对象的所有成员变量都被初始化为它们从数据库中读取的值。具体来说: +mContext: 传入的 +mContentResolver: 从上下文对象中获取的内容解析器 +mIsCreate: 设置为false,表示这个SqlNote对象代表的是一个已经存在于数据库中的笔记。 +loadFromCursor(c): 调用loadFromCursor()方法,从游标c中加载所有的笔记数据,包括笔记的标题、内容、创建日期、修改日期等等。 +mDataList: 创建一个新的ArrayList对象,用于存储 +loadDataContent(): 如果这个笔记是一个普通笔记,则调用loadDataContent()方法,从数据库中加载笔记的内容。 +mDiffNoteValues: 创建一个新的ContentValues对象,用于存储这个笔记的差异数据。 +通过这个构造函数,SqlNote对象可以从数据库中读取已有的笔记数据,并在内存中表示这个笔记。*/ public SqlNote(Context context, long id) { mContext = context; mContentResolver = context.getContentResolver(); @@ -165,7 +236,15 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); } - +/*这是SqlNote类的另一个构造函数,用于从数据库中加载指定id的SqlNote对象。在构造函数中,SqlNote对象的所有成员变量都被初始化为它们从数据库中读取的值。具体来说: +mContext: 传入的上下文对象。 +mContentResolver: 从上下文对象中获取的内容解析器对象。 +mIsCreate: 设置为false,表示这个SqlNote对象代表的是一个已经存在于 +loadFromCursor(id): 调用loadFromCursor()方法,从数据库中加载指定id的笔记数据,包括笔记的标题、内容、创建日期、修改日期等等。 +mDataList: 创建一个新的ArrayList对象,用于存储这个笔记的子笔记数据。 +loadDataContent(): 如果这个笔记是一个普通笔记,则调用loadDataContent()方法,从数据库中加载笔记的内容。 +mDiffNoteValues: 创建一个新的ContentValues对象,用于存储这个笔记的差异数据。 +通过这个构造函数,SqlNote对象可以从数据库中读取指定id的笔记数据,并在内存中表示这个笔记。*/ private void loadFromCursor(long id) { Cursor c = null; try { @@ -184,7 +263,11 @@ public class SqlNote { c.close(); } } - +/*这是SqlNote类的一个私有方法,用于从数据库中加载指定id的笔记数据。具体来说: +首先,通过查询内容提供器Notes.CONTENT_NOTE_URI获取指定ID +然后,如果游标不为null,将游标移到第一条记录,并调用loadFromCursor(Cursor c)方法,将游标中的所有记录加载到SqlNote对象中。 +最后,关闭游标对象。 +通过这个方法,SqlNote对象可以从数据库中查询指定id的笔记数据,并在内存中表示这个笔记。需要注意的是,在加载数据之后一定要及时关闭游标对象,以释放资源。*/ private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); @@ -199,7 +282,22 @@ public class SqlNote { mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); mVersion = c.getLong(VERSION_COLUMN); } - +/*这是SqlNote类的一个私有方法,用于从游标中加载笔记数据。具体来说: +通过游标对象c获取每个属性的值,并将其赋值给SqlNote对象的对应成员变量。 +其中,这些属性的含义如下: +mId: 笔记的唯一标识符。 +mAlertDate: 笔记提醒时间,以毫秒为单位。 +mBgColorId: 笔记背景颜色的标识符。 +mCreatedDate: 笔记创建时间,以毫秒为单位。 +mHasAttachment: 笔记是否有附件(0表示没有,1表示有)。 +mModifiedDate: 笔记最近修改时间,以毫秒为单位。 +mParentId: 笔记的父笔记的唯一标识符。 +mSnippet: 笔记的摘要。 +mType: 笔记的类型,可以是普通笔记、清单笔记、便签等。 +mWidgetId: 笔记所关联的小部件的唯一标识符。 +mWidgetType: 笔记所关联的小部件的类型。 +m版本: 笔记的 +通过这个方法,SqlNote对象可以从游标中加载所有的笔记数据,并在内存中表示这个笔记。*/ private void loadDataContent() { Cursor c = null; mDataList.clear(); @@ -225,13 +323,24 @@ public class SqlNote { c.close(); } } - +/*这是SqlNote类的一个私有方法,用于从数据库中加载笔记的数据内容。具体来说: +首先,通过查询内容提供器Notes.CONTENT_DATA_URI获取指定笔记ID的所有 +然后,清空数据列表mDataList。 +接着,如果游标不为null,遍历游标中的所有记录,并使用SqlData对象将每条记录转换成一个数据对象。将这些数据对象添加到数据列表mDataList中。 +最后,关闭游标对象。 +通过这个方法,SqlNote对象可以从数据库中查询指定笔记id的所有数据,将其转换成数据对象,并存储在内存中。需要注意的是,在加载数据之后一定要及时关闭游标对象,以释放资源。*/ public boolean setContent(JSONObject js) { try { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_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) { + } + /*这是SqlNote类的一个公有方法,用于设置笔记的内容。具体来说: + 首先,从Json对象js中获取笔记的元数据信息,即note对象。 + 然后,判断获取的笔记类型是否为系统类型(Notes.TYPE_SYSTEM),如果是则输出警告信息并返回false。 + 如果不是系统类型,则继续执行以下步骤。 + 在这个方法中,对于非法的系统类型的笔记,将输出警告信息并返回false,不会更改SqlNote对象的内容。对于合法的笔记,该方法将根据传入的Json对象设置笔记的内容。但是,这个方法的具体实现并没有展示出来,需要查看该方法的后续代码才能了解更多信息。*/ + else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { // for folder we can only update the snnipet and type String snippet = note.has(NoteColumns.SNIPPET) ? note .getString(NoteColumns.SNIPPET) : ""; @@ -246,42 +355,60 @@ public class SqlNote { mDiffNoteValues.put(NoteColumns.TYPE, type); } mType = type; - } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { + } + /*如果获取的笔记类型是文件夹类型(Notes.TYPE_FOLDER),则该方法只能更新文件夹的片段(NoteColumns.SNIPPET)和类型(NoteColumns.TYPE)属性。 + 如果传入的Json对象中包含片段属性(NoteColumns.SNIPPET),则将其值赋给片段变量,否则将其设置为空字符串。 + 如果 SqlNote + 将当前的片段值(mSnippet)设置为获取的片段值(snippet)。 + 如果传入的Json对象中包含类型属性(NoteColumns.TYPE),则将其值赋给type变量,否则将其设置为Notes.TYPE_NOTE(默认值)。 + 如果 SqlNote + 将当前的类型值(mType)设置为获取的类型值(type)。 + 通过这个方法,SqlNote对象可以根据传入的Json对象更新笔记的片段和类型属性。需要注意的是,对于文件夹类型的笔记,只能更新片段和类型属性,其他属性不能更改。*/ + else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) { JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID; if (mIsCreate || mId != id) { mDiffNoteValues.put(NoteColumns.ID, id); } mId = id; - + /*代码检索到JSONArray叫dataArray从命名的 JSON 对象js. + 然后,代码检查是否 + 如果mIsCreate为 true 或当前注释 ID 为mId不等于检索到的 ID,则代码将 ID 放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.ID常量作为键和检索到的 ID作为值。*/ long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note .getLong(NoteColumns.ALERTED_DATE) : 0; if (mIsCreate || mAlertDate != alertDate) { mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate); } mAlertDate = alertDate; - + /*通过调用has()方法上的方法NoteColumns.ALERTED_DATE不断。如果注释有警报日期,则警报日期通过调用getLong()方法上NoteColumns.ALERTED_DATE不断。否则,它将警报日期设置为 0。 + 如果mIsCreate为 true 或当前警报日期mAlertDate不等于检索到的警报日期,则代码将警报日期放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.ALERTED_DATE常量作为键,检索到的警报日期作为值。 + 最后,代码将检索到的警报日期分配给名为mAlertDate.仅从此代码块中不清楚此变量的用途,但它可以在程序的其他地方使用。*/ int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note .getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext); if (mIsCreate || mBgColorId != bgColorId) { mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId); } mBgColorId = bgColorId; - + /*代码检查 + 如果mIsCreate为 true 或当前背景颜色 ID 为 truemBgColorId不等于检索到的背景颜色 ID,则代码将背景颜色 ID 放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.BG_COLOR_ID常量作为键和检索到的背景色标识为 + 最后,代码将检索到的背景颜色 ID 分配给名为mBgColorId.仅从此代码块中不清楚此变量的用途,但它可以在程序的其他地方使用。*/ long createDate = note.has(NoteColumns.CREATED_DATE) ? note .getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis(); if (mIsCreate || mCreatedDate != createDate) { mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate); } mCreatedDate = createDate; - + /*调用has()方法上的方法NoteColumns.CREATED_DATE不断。如果注释具有创建日期,代码通过调用getLong()方法上NoteColumns.CREATED_DATE不断。否则,它将创建日期设置为当前系统时间以毫秒为单位,通过调用System.currentTimeMillis()方法。 + 如果是mIsCreatemCreatedDate不等于检索到的创建日期,则代码将创建日期放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.CREATED_DATE常量作为键,检索到的创建日期作为值。 + 最后,代码将检索到的创建日期分配给名为mCreatedDate.*/ int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note .getInt(NoteColumns.HAS_ATTACHMENT) : 0; if (mIsCreate || mHasAttachment != hasAttachment) { mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment); } mHasAttachment = hasAttachment; - + /*检查注释是否具有附件。如果注释具有附件,则代码通过对常量调用方法来检索值。否则,它将值设置为 0。 + 如果为 true,或者如果 的当前值不等于检索到的值,则代码使用以常量为键,检索到的值作为值的方法将值放入调用中。*/ long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note .getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis(); if (mIsCreate || mModifiedDate != modifiedDate) { @@ -323,14 +450,22 @@ public class SqlNote { mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType); } mWidgetType = widgetType; - + /*这段代码在一个笔记应用中用于更新笔记的不同属性。下面是每个段的注释: + 首先检查笔记对象中是否包含最后修改日期属性,如果是则获取该属性的值,否则将当前时间作为最后修改日期。如果笔记对象是新创建的或最后修改日期与之前不同,则将其放入待更新的笔记属性集合中。最后将最后修改日期赋值给实例变量mModifiedDate。 + 然后检查笔记对象中是否包含父笔记ID属性,如果是则获取该属性的值,否则将0作为父笔记ID。如果笔记对象是新创建的或父笔记ID与之前不同,则将其放入待更新的笔记属性集合中。最后将父笔记ID赋值给实例变量mParentId。 + 接下来检查笔记对象中是否包含摘要属性,如果是则获取该属性的值,否则将空字符串作为摘要。如果笔记对象是新创建的或摘要与之前不同,则将其放入待更新的笔记属性集合中。最后将摘要赋值给实例变量mSnippet。 + 然后检查笔记对象中是否包含类型属性,如果是则获取该属性的值,否则将默认类型Note作为类型。如果笔记对象是新创建的或类型与之前不同,则将其放入待更新的笔记属性集合中。最后将类型赋值给实例变量mType。 + 接着检查笔记对象中是否包含小部件ID属性,如果是则获取该属性的值,否则将无效的小部件ID作为小部件ID。如果笔记对象是新创建的或小部件ID与之前不同,则将其放入待更新的笔记属性集合中。最后将小部件ID赋值给实例变量mWidgetId。 + 最后检查笔记对象中是否包含小部件类型属性,如果是则获取该属性的值,否则将无效的小部件类型作为小部件类型。如果笔记对象是新创建的或小部件类型与之前不同,则将其放入待更新的笔记属性集合中。最后将小部件类型赋值给实例变量mWidgetType。*/ long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note .getLong(NoteColumns.ORIGIN_PARENT_ID) : 0; if (mIsCreate || mOriginParent != originParent) { mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent); } mOriginParent = originParent; - + /*首先检查笔记对象中是否包含原始父笔记ID属性,如果是则获取该属性的值,否则将0作为原始父笔记ID + 如果笔记对象是新创建的或原始父笔记ID与之前不同,则将其放入待更新的笔记属性集合中。 + 最后将原始父笔记ID赋值给实例变量mOriginParent。*/ for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); SqlData sqlData = null; @@ -342,12 +477,15 @@ public class SqlNote { } } } - + /*首先,使用for循环遍历数据数组中的每个JSON对象。 + 然后,检查JSON对象是否具有ID属性。如果有,将其与数据列表中的每个SqlData对象进行比较,以查找具有相同ID的SqlData对象。如果找到了匹配的SqlData对象,则将其赋值给sqlData变量。 + 如果未找到匹配项,则sqlData变量将保持为null。*/ if (sqlData == null) { sqlData = new SqlData(mContext); mDataList.add(sqlData); } - + /*如果在数据列表中未找到具有与JSON对象相同ID的SqlData对象,则创建一个新的SqlData对象,并将其添加到数据列表中。 + 如果找到了匹配的SqlData对象,则sqlData变量已经被赋值为该对象,不需要进行其他处理。*/ sqlData.setContent(data); } } @@ -358,7 +496,9 @@ public class SqlNote { } return true; } - +/*如果找到了具有与JSON对象相同ID的SqlData对象,则调用该对象的setContent方法,并将JSON对象作为参数传递给该方法。该方法将使用JSON对象更新SqlData对象的属性值。如果未找到匹配的SqlData对象,则不需要进行任何处理。 +最后,try-catch语句用于捕获可能的JSONException异常,并在发生异常时打印错误信息。 +如果没有发生异常,则返回值为true。*/ public JSONObject getContent() { try { JSONObject js = new JSONObject(); @@ -367,7 +507,10 @@ public class SqlNote { Log.e(TAG, "it seems that we haven't created this in database yet"); return null; } - +/*首先创建一个新的JSONObject对象。然后检查mIsCreate属性的值。 +如果为true,则表示该SqlData对象尚未被创建到数据库中,此时将打印一个错误信息,并返回null。 +否则,将使用put方法将SqlData对象的属性值逐个添加到JSONObject对象中。 +最后,返回包含SqlData对象属性值的JSONObject对象。*/ JSONObject note = new JSONObject(); if (mType == Notes.TYPE_NOTE) { note.put(NoteColumns.ID, mId); @@ -392,7 +535,11 @@ public class SqlNote { } } js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); - } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { + } + /*首先创建一个新的JSONObject对象note,并使用put方法将SqlData对象的属性值逐个添加到该对象中。然后,将note对象添加到新创建的JSONObject对象js中,并使用put方法将其作为GTaskStringUtils.META_HEAD_NOTE键的值。 + 接下来,创建一个新的JSONArray对象dataArray,并使用for循环遍历mDataList列表中的每个SqlData对象。对于每个SqlData对象,调用其getContent方法获取一个JSON对象,并检查该对象是否为null。如果不为null,则将其添加到dataArray数组中。 + 最后,将dataArray数组添加到js对象中,并使用put方法将其作为GTaskStringUtils.META_HEAD_DATA键的值。如果mType属性不等于Notes.TYPE_NOTE,则不会将任何数据添加到js对象中。*/ + else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) { note.put(NoteColumns.ID, mId); note.put(NoteColumns.TYPE, mType); note.put(NoteColumns.SNIPPET, mSnippet); @@ -406,7 +553,9 @@ public class SqlNote { } return null; } - + /*如果mType属性等于Notes.TYPE_FOLDER或Notes.TYPE_SYSTEM,则创建一个新的JSONObject对象note,并使用put方法将SqlData对象的属性值逐个添加到该对象中。然后,将note对象添加到新创建的JSONObject对象js中,并使用put方法将其作为GTaskStringUtils.META_HEAD_NOTE键的值。 + 如果发生JSONException异常,则在控制台中打印错误信息,并返回null。如果没有发生异常,则返回包含SqlData对象属性值的JSONObject对象。js + 总的来说,这段代码的作用是将SqlData对象的属性值转换为JSON格式,并将其添加到新创建的JSONObject对象中。*/ public void setParentId(long id) { mParentId = id; mDiffNoteValues.put(NoteColumns.PARENT_ID, id); @@ -439,7 +588,14 @@ public class SqlNote { public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } - + /*setParentId(long id): 将id参数值赋给mParentId属性,并使用put方法将NoteColumns.PARENT_ID和id添加到mDiffNoteValues对象中。 + setGtaskId(String gid): 使用put方法将NoteColumns.GTASK_ID和gid添加到mDiffNoteValues对象中。 + setSyncId(long syncId): 使用put方法将NoteColumns.SYNC_ID和syncId添加到mDiffNoteValues对象中。 + resetLocalModified(): 使用put方法将和0添加到NoteColumns.LOCAL_MODIFIEDmDiffNoteValues对象中。该方法用于重置SqlData对象的本地修改标志。 + getId(): 返回mId属性的值。 + getParentId(): 返回mParentId属性的值。 + getSnippet(): 返回mSnippet属性的值。 + isNoteType(): 如果mType属性等于,则返回Notes.TYPE_NOTEtrue,否则返回false。该方法用于判断该SqlData对象是否是一个笔记类型的对象。*/ public void commit(boolean validateVersion) { if (mIsCreate) { if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { @@ -462,7 +618,11 @@ public class SqlNote { sqlData.commit(mId, false, -1); } } - } else { + } + /*如果mIsCreate属性为true,则表示该SqlData对象是新创建的,需要将其写入数据库。如果mId属性的值等于INVALID_ID(即-1)并且mDiffNoteValues对象中包含NoteColumns.ID键,那么将该键从mDiffNoteValues对象中移除。然后,使用insert方法将mDiffNoteValues对象中的属性值添加到Notes.CONTENT_NOTE_URI中,并将返回的Uri对象赋给uri变量。 + 接下来,使用getPathSegments方法获取uri对象中的路径段,并将第二个路径段(即路径中的第二个元素)转换为long类型,并将其赋给mId属性。如果在转换过程中发生NumberFormatException异常,则在控制台中打印错误信息并抛出ActionFailureException异常。如果mId属性的值等于0,则抛出IllegalStateException异常。 + 如果属性等于,则表示该mTypeNotes.TYPE_NOTESqlData对象是一个笔记类型的对象,并且它包含一个mDataList列表,该列表中包含其他SqlData对象。在这种情况下,需要递归调用每个SqlData对象的commit方法,并将mId的值作为参数传递给该方法,以便将这些子对象插入到数据库中。*/ + else { if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) { Log.e(TAG, "No such note"); throw new IllegalStateException("Try to update note with invalid id"); @@ -503,3 +663,8 @@ public class SqlNote { mIsCreate = false; } } +/*如果mIsCreate属性为false,则表示该SqlData对象是已存在于数据库中的对象,需要更新其属性值。首先,需要检查mId属性的值是否为有效值。如果mId属性的值小于等于0且不等于Notes.ID_ROOT_FOLDER和Notes.ID_CALL_RECORD_FOLDER,则表示该笔记不存在,会打印错误信息并抛出IllegalStateException异常。然后,检查mDiffNoteValues对象是否包含要更新的属性值,如果包含,则需要更新笔记的版本号mVersion,并使用update方法将更改后的属性值写入数据库中。 +如果参数为validateVersiontrue,则表示需要验证版本号。在这种情况下,会将笔记的版本号mVersion作为参数传递给update方法,并在WHERE子句中添加一个条件,以确保要更新的笔记版本号小于等于当前版本号。如果validateVersion参数为false,则不需要验证版本号。 +如果更新操作成功,则方法会返回受影响的行数。如果返回值为0,则表示更新操作没有修改任何行,会在控制台中打印警告信息。update +如果mType属性等于Notes.TYPE_NOTE,则表示该SqlData对象是一个笔记类型的对象,并且它包含一个mDataList列表,该列表中包含其他SqlData对象。在这种情况下,需要递归调用每个SqlData对象的commit方法,并将mId和validateVersion的值作为参数传递给该方法。 +最后,刷新本地信息,清空mDiffNoteValues对象中的属性值,将mIsCreate属性设置为false,并完成方法的执行。*/ \ No newline at end of file diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/Task.java b/src/app/src/main/java/net/micode/notes/gtask/data/Task.java index 6a19454..71cff3f 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/data/Task.java +++ b/src/app/src/main/java/net/micode/notes/gtask/data/Task.java @@ -53,10 +53,22 @@ public class Task extends Node { mParent = null; mMetaInfo = null; } - +/*这是一个名为Task的Java类,它继承自Node类。Task类有以下成员变量: +mCompleted:表示任务是否已完成,类型为布尔值。 +mNotes:表示任务的笔记,类型为字符串。 +mMetaInfo:表示任务的元信息,类型为JSONObject对象。 +mPriorSibling:表示前一个同级任务,类型为Task对象。 +mParent:表示任务所属的任务列表,类型为TaskList对象。 +Task类还有一个无参数构造函数,它会将mCompleted、mNotes、、mPriorSiblingmParent和mMetaInfo都初始化为null或false。 +继承自Node类的成员变量和方法没有在这个代码片段中给出,但是可以推测出Node类是一个表示树节点的基类,TaskList类是一个表示任务列表的类。在Task类中,mPriorSibling和mParent成员变量用于表示任务在任务列表中的位置,mMetaInfo成员变量用于存储一些其他的任务信息。*/ public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); - +/*该方法返回一个JSONObject对象,用于表示创建一个动作的操作。 +该方法有一个整数类型的参数actionId,用于指定要创建的动作的ID。 +方法主体中,首先创建一个空的JSONObject对象js。 +然后,会往该对象中添加一个表示要执行的操作类型的键值对,该键值对的键为"type",值为"action"。 +接着,会添加一个表示要创建的动作ID的键值对,该键值对的键为"action_id",值为actionId参数的值。 +最后,将js对象返回。*/ try { // action_type js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, @@ -74,6 +86,12 @@ public class Task extends Node { entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, GTaskStringUtils.GTASK_JSON_TYPE_TASK); + /*在上述代码中,getCreateAction方法中的JSONObject js对象被初始化之后,首先向其中添加一个表示操作类型的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_ACTION_TYPE,值为GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE。 + 接着,会添加一个表示要创建的动作ID的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_ACTION_ID,值为actionId参数的值。 + 然后,会添加一个表示任务在任务列表中的位置的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_INDEX,值为当前任务在其父任务列表中的位置,通过调用mParent.getChildTaskIndex(this)方法获得。 + 最后,会添加一个表示任务实体的键值对,该键值对的键为"entity_delta",值为一个新的JSONObject对象entity。entity对象中包含三个键值对,分别为任务名称、创建者ID和任务类型。 + 其中,任务名称通过getName()方法获取,创建者ID为"null",任务类型为GTaskStringUtils.GTASK_JSON_TYPE_TASK。 + 最终,js对象中包含了所有要创建动作所需的信息,并将其返回。*/ if (getNotes() != null) { entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); } @@ -88,7 +106,11 @@ public class Task extends Node { // list_id js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); - + /*在上述代码中,如果当前任务存在笔记,则会向entity对象中添加一个表示笔记内容的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_NOTES,值为当前任务的笔记内容,通过调用getNotes()方法获取。然后,将entity对象添加为js对象的一个子对象,键为GTaskStringUtils.GTASK_JSON_ENTITY_DELTA。 + 接着,会添加一个表示当前任务所属的任务列表ID的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_PARENT_ID,值为当前任务所属任务列表的GID,通过调用mParent.getGid()方法获取。 + 然后,会添加一个表示当前任务所属的任务列表类型的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,值为GTaskStringUtils.GTASK_JSON_TYPE_GROUP,表示当前任务所属的任务列表是一个组。 + 最后,会添加一个表示当前任务所属的任务列表ID的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_LIST_ID,值为当前任务所属任务列表的GID。 + 最终,js对象中包含了所有创建动作所需的信息,并将其返回。*/ // prior_sibling_id if (mPriorSibling != null) { js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); @@ -101,69 +123,75 @@ public class Task extends Node { } return js; - } + }/*添加一个表示当前任务的前一个兄弟任务ID的键值对。 + 如果当前任务的前一个兄弟任务不为空,则会向 js 对象中添加一个表示前一个兄弟任务ID的键值对,该键值对的键为 GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID,值为前一个兄弟任务的 GID,通过调用 mPriorSibling.getGid() 方法获取。 + 这个键值对表示当前任务是前一个兄弟任务的下一个兄弟任务,也就是将当前任务插入到前一个兄弟任务后面。如果添加键值对时出现 JSONException 异常,则会打印异常信息,并抛出 ActionFailureException 异常。 + 最后,返回表示创建任务的动作的 JSONObject 对象。*/ public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); try { - // action_type + // 将 action_type 字段设置为 GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); - // action_id + // 将 action_id 字段设置为传入的 actionId 参数 js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); - // id + // 将 id 字段设置为当前任务的 GID js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); - // entity_delta + // 将 entity_delta 字段设置为一个 JSONObject 对象, + // 该对象表示要更新的任务的属性和值 JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - if (getNotes() != null) { + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称 + if (getNotes() != null) { // 如果任务的注释不为空,则添加注释字段 entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); } - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); + entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 任务是否被删除 js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); } catch (JSONException e) { + // 如果出现 JSONException 异常,则打印异常信息,并抛出 ActionFailureException 异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to generate task-update jsonobject"); } + // 返回表示更新任务的动作的 JSONObject 对象 return js; } public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { - // id + // 解析 id 字段,将其设置为本地任务对象的 GID if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); } - // last_modified + // 解析 last_modified 字段,将其设置为本地任务对象的最后修改时间 if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); } - // name + // 解析 name 字段,将其设置为本地任务对象的名称 if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); } - // notes + // 解析 notes 字段,将其设置为本地任务对象的注释 if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); } - // deleted + // 解析 deleted 字段,将其设置为本地任务对象的删除状态 if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); } - // completed + // 解析 completed 字段,将其设置为本地任务对象的完成状态 if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); } @@ -182,14 +210,19 @@ public class Task extends Node { } try { + // 解析任务的注释信息 JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + + // 解析任务的数据信息 JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + // 检查任务的类型是否为 Notes.TYPE_NOTE if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { Log.e(TAG, "invalid type"); return; } + // 解析任务的名称 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { @@ -206,14 +239,16 @@ public class Task extends Node { public JSONObject getLocalJSONFromContent() { String name = getName(); + try { if (mMetaInfo == null) { - // new task created from web + // 如果当前任务对象没有元信息,则表示该任务是从 Web 创建的 if (name == null) { Log.w(TAG, "the note seems to be an empty one"); return null; } + // 创建一个新的 JSONObject,并将任务的名称添加到其中 JSONObject js = new JSONObject(); JSONObject note = new JSONObject(); JSONArray dataArray = new JSONArray(); @@ -225,10 +260,11 @@ public class Task extends Node { js.put(GTaskStringUtils.META_HEAD_NOTE, note); return js; } else { - // synced task + // 如果当前任务对象有元信息,则表示该任务是同步过来的 JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + // 遍历任务的数据信息,找到 MIME_TYPE 为 DataConstants.NOTE 的 JSONObject,并将其 CONTENT 字段设置为任务的名称 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { @@ -237,6 +273,7 @@ public class Task extends Node { } } + // 将任务的类型设置为 Notes.TYPE_NOTE,并返回元信息对象 note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); return mMetaInfo; } @@ -247,9 +284,11 @@ public class Task extends Node { } } + public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { + // 将元数据对象的 notes 字段转换为 JSONObject 对象,并存储在当前对象的 mMetaInfo 变量中 mMetaInfo = new JSONObject(metaData.getNotes()); } catch (JSONException e) { Log.w(TAG, e.toString()); @@ -261,45 +300,49 @@ public class Task extends Node { public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; + // 从 mMetaInfo 变量中获取笔记的元数据信息 if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); } if (noteInfo == null) { + // 如果笔记的元数据信息不存在,则需要更新远程数据 Log.w(TAG, "it seems that note meta has been deleted"); return SYNC_ACTION_UPDATE_REMOTE; } if (!noteInfo.has(NoteColumns.ID)) { + // 如果笔记的元数据信息中没有 ID 字段,则需要更新本地数据 Log.w(TAG, "remote note id seems to be deleted"); return SYNC_ACTION_UPDATE_LOCAL; } - // validate the note id now + // 检查笔记的 ID 是否匹配 if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { Log.w(TAG, "note id doesn't match"); return SYNC_ACTION_UPDATE_LOCAL; } if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update + // 如果本地没有修改笔记,则比较修改时间来判断是否需要更新数据 if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side + // 本地和远程都没有修改,无需同步 return SYNC_ACTION_NONE; } else { - // apply remote to local + // 将远程数据应用到本地 return SYNC_ACTION_UPDATE_LOCAL; } } else { - // validate gtask id + // 如果本地有修改笔记,则需要比较修改时间和 GTask ID 来判断同步操作 if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { Log.e(TAG, "gtask id doesn't match"); return SYNC_ACTION_ERROR; } if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only + // 只有本地有修改,将本地数据更新到远程 return SYNC_ACTION_UPDATE_REMOTE; } else { + // 本地和远程都有修改,需要解决冲突 return SYNC_ACTION_UPDATE_CONFLICT; } } @@ -312,39 +355,49 @@ public class Task extends Node { } public boolean isWorthSaving() { - return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) - || (getNotes() != null && getNotes().trim().length() > 0); + // 判断对象是否值得保存 + return mMetaInfo != null // 如果 mMetaInfo 不为空 + || (getName() != null && getName().trim().length() > 0) // 或者 name 不为空且去除空格后长度大于 0 + || (getNotes() != null && getNotes().trim().length() > 0); // 或者 notes 不为空且去除空格后长度大于 0 } public void setCompleted(boolean completed) { + // 设置对象的 mCompleted 变量为给定的布尔值 this.mCompleted = completed; } public void setNotes(String notes) { + // 设置对象的 mNotes 变量为给定的字符串 this.mNotes = notes; } public void setPriorSibling(Task priorSibling) { + // 设置对象的 mPriorSibling 变量为给定的 Task 对象 this.mPriorSibling = priorSibling; } public void setParent(TaskList parent) { + // 设置对象的 mParent 变量为给定的 TaskList 对象 this.mParent = parent; } public boolean getCompleted() { + // 返回对象的 mCompleted 变量 return this.mCompleted; } public String getNotes() { + // 返回对象的 mNotes 变量 return this.mNotes; } public Task getPriorSibling() { + // 返回对象的 mPriorSibling 变量,其中 mPriorSibling 是一个 Task 对象 return this.mPriorSibling; } public TaskList getParent() { + // 返回对象的 mParent 变量,其中 mParent 是一个 TaskList 对象 return this.mParent; } diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java b/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java index 4ea21c5..579f8f8 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java +++ b/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java @@ -31,180 +31,189 @@ import java.util.ArrayList; public class TaskList extends Node { + // 定义一个 TaskList 类,继承自 Node 类 + private static final String TAG = TaskList.class.getSimpleName(); + // 定义一个 TAG 常量,类型为字符串,值为 TaskList 类的简单名称 private int mIndex; + // 定义一个整型变量 mIndex,用于存储任务列表的索引值 private ArrayList mChildren; + // 定义一个 ArrayList 类型的 mChildren 变量,用于存储该任务列表的子任务列表 public TaskList() { + // 默认构造方法 + super(); + // 调用父类的默认构造方法 + mChildren = new ArrayList(); + // 初始化 mChildren 变量为一个新的空的 ArrayList + mIndex = 1; + // 初始化 mIndex 变量为 1 } public JSONObject getCreateAction(int actionId) { - JSONObject js = new JSONObject(); + JSONObject js = new JSONObject(); // 创建一个新的 JSONObject 对象 try { // action_type js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); // 添加 action_type 键值对,值为 "create" // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 添加 action_id 键值对,值为传入的参数 actionId // index - js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); + js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); // 添加 index 键值对,值为成员变量 mIndex 的值 // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); + JSONObject entity = new JSONObject(); // 创建一个新的 JSONObject 对象,用于表示实体的 delta + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 添加 name 键值对,值为 getName() 方法的返回值 + entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 添加 creator_id 键值对,值为 "null" entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE, - GTaskStringUtils.GTASK_JSON_TYPE_GROUP); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // 添加 entity_type 键值对,值为 "GROUP" + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加 entity_delta 键值对,值为上面创建的 entity 对象 - } catch (JSONException e) { - Log.e(TAG, e.toString()); + } catch (JSONException e) { // 如果在添加键值对的过程中出现 JSONException 异常 + Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息 e.printStackTrace(); - throw new ActionFailureException("fail to generate tasklist-create jsonobject"); + throw new ActionFailureException("fail to generate tasklist-create jsonobject"); // 抛出一个自定义异常 ActionFailureException,并传递一个异常信息字符串 } - return js; + return js; // 返回创建的 JSONObject 对象 } public JSONObject getUpdateAction(int actionId) { - JSONObject js = new JSONObject(); + JSONObject js = new JSONObject(); // 创建一个新的 JSONObject 对象 try { // action_type js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); // 添加 action_type 键值对,值为 "update" // action_id - js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); + js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 添加 action_id 键值对,值为传入的参数 actionId // id - js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); + js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); // 添加 id 键值对,值为调用 getGid() 方法的返回值,表示任务列表的全局唯一标识符 // entity_delta - JSONObject entity = new JSONObject(); - entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); - entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); - js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); + JSONObject entity = new JSONObject(); // 创建一个新的 JSONObject 对象,用于表示实体的 delta + entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 添加 name 键值对,值为 getName() 方法的返回值,表示任务列表的名称 + entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 添加 deleted 键值对,值为 getDeleted() 方法的返回值,表示任务列表是否被删除 + js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加 entity_delta 键值对,值为上面创建的 entity 对象 - } catch (JSONException e) { - Log.e(TAG, e.toString()); + } catch (JSONException e) { // 如果在添加键值对的过程中出现 JSONException 异常 + Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息 e.printStackTrace(); - throw new ActionFailureException("fail to generate tasklist-update jsonobject"); + throw new ActionFailureException("fail to generate tasklist-update jsonobject"); // 抛出一个自定义异常 ActionFailureException,并传递一个异常信息字符串 } - return js; + return js; // 返回创建的 JSONObject 对象 } public void setContentByRemoteJSON(JSONObject js) { - if (js != null) { + if (js != null) { // 如果传入的 JSONObject 对象不为 null try { // id - if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { - setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); + if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { // 如果 JSONObject 对象中包含 id 键值对 + setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); // 将 id 键对应的值作为参数调用 setGid() 方法,将任务列表的全局唯一标识符设置为该值 } // last_modified - if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { - setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); + if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { // 如果 JSONObject 对象中包含 last_modified 键值对 + setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); // 将 last_modified 键对应的值作为参数调用 setLastModified() 方法,将任务列表的最后修改时间设置为该值 } // name - if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { - setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); + if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { // 如果 JSONObject 对象中包含 name 键值对 + setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); // 将 name 键对应的值作为参数调用 setName() 方法,将任务列表的名称设置为该值 } - } catch (JSONException e) { - Log.e(TAG, e.toString()); + } catch (JSONException e) { // 如果在读取键值对的过程中出现 JSONException 异常 + Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息 e.printStackTrace(); - throw new ActionFailureException("fail to get tasklist content from jsonobject"); + throw new ActionFailureException("fail to get tasklist content from jsonobject"); // 抛出一个自定义异常 ActionFailureException,并传递一个异常信息字符串 } } } public void setContentByLocalJSON(JSONObject js) { - if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { - Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); + if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { // 如果传入的 JSONObject 对象为 null,或者它不包含 META_HEAD_NOTE 键值对 + Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); // 打印一条警告日志,表示没有可用的信息 } try { - JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - - if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { - String name = folder.getString(NoteColumns.SNIPPET); - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); - } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { - if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); - else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) - setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE); + JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // 获取 META_HEAD_NOTE 键对应的值,该值应该是一个 JSON 对象,表示笔记的元信息 + + if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { // 如果元信息中的 TYPE 键对应的值为 TYPE_FOLDER,表示这是一个文件夹笔记 + String name = folder.getString(NoteColumns.SNIPPET); // 获取元信息中的 SNIPPET 键对应的值,该值应该是文件夹的名称 + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); // 将文件夹名称加上一个前缀字符串,作为任务列表的名称 + } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { // 如果元信息中的 TYPE 键对应的值为 TYPE_SYSTEM,表示这是一个系统笔记 + if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) // 如果元信息中的 ID 键对应的值为 ID_ROOT_FOLDER,表示这是根文件夹笔记 + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); // 将默认的任务列表名称设置为 MIUI_FOLDER_PREFFIX + FOLDER_DEFAULT + else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) // 如果元信息中的 ID 键对应的值为 ID_CALL_RECORD_FOLDER,表示这是一条来电记录笔记 + setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE); // 将来电记录的任务列表名称设置为 MIUI_FOLDER_PREFFIX + FOLDER_CALL_NOTE else - Log.e(TAG, "invalid system folder"); + Log.e(TAG, "invalid system folder"); // 如果元信息中的 TYPE 和 ID 值都不符合要求,打印一条错误日志 } else { - Log.e(TAG, "error type"); + Log.e(TAG, "error type"); // 如果元信息中的 TYPE 键对应的值既不是 TYPE_FOLDER,也不是 TYPE_SYSTEM,打印一条错误日志 } - } catch (JSONException e) { - Log.e(TAG, e.toString()); + } catch (JSONException e) { // 如果在读取元信息的过程中出现 JSONException 异常 + Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息 e.printStackTrace(); } } public JSONObject getLocalJSONFromContent() { try { - JSONObject js = new JSONObject(); - JSONObject folder = new JSONObject(); - - String folderName = getName(); - if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) - folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), - folderName.length()); - folder.put(NoteColumns.SNIPPET, folderName); - if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) - || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) - folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); + JSONObject js = new JSONObject(); // 创建一个新的 JSONObject 对象 + JSONObject folder = new JSONObject(); // 创建一个新的 JSONObject 对象,表示笔记的元信息 + + String folderName = getName(); // 获取任务列表名称 + if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) // 如果任务列表名称以 MIUI_FOLDER_PREFFIX 开头 + folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), folderName.length()); // 将 MIUI_FOLDER_PREFFIX 从任务列表名称中去掉 + folder.put(NoteColumns.SNIPPET, folderName); // 将去掉 MIUI_FOLDER_PREFFIX 的任务列表名称存入元信息中的 SNIPPET 键 + + if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) // 如果任务列表名称是默认任务列表或来电记录任务列表 + folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 将元信息中的 TYPE 键设置为 TYPE_SYSTEM else - folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); + folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); // 否则将元信息中的 TYPE 键设置为 TYPE_FOLDER - js.put(GTaskStringUtils.META_HEAD_NOTE, folder); + js.put(GTaskStringUtils.META_HEAD_NOTE, folder); // 将元信息对象存入 js 对象中,以 META_HEAD_NOTE 键为键名 - return js; - } catch (JSONException e) { - Log.e(TAG, e.toString()); + return js; // 返回创建好的 JSONObject 对象 + } catch (JSONException e) { // 如果在创建 JSONObject 对象的过程中出现异常 + Log.e(TAG, e.toString()); // 打印异常信息 e.printStackTrace(); - return null; + return null; // 返回 null } } public int getSyncAction(Cursor c) { try { - if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { - // there is no local update - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // no update both side + if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { // 如果本地没有更新 + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { // 如果本地最后一次修改时间与云端最后一次修改时间相同 + // 两边都没有更新 return SYNC_ACTION_NONE; } else { - // apply remote to local + // 将云端的修改应用到本地 return SYNC_ACTION_UPDATE_LOCAL; } - } else { - // validate gtask id + } else { // 如果本地有更新 + // 验证 gtask id 是否匹配 if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) { Log.e(TAG, "gtask id doesn't match"); return SYNC_ACTION_ERROR; } - if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { - // local modification only + if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { // 如果本地最后一次修改时间与云端最后一次修改时间相同 + // 只有本地修改 return SYNC_ACTION_UPDATE_REMOTE; } else { - // for folder conflicts, just apply local modification + // 对于文件夹冲突,只应用本地修改 return SYNC_ACTION_UPDATE_REMOTE; } } @@ -213,38 +222,37 @@ public class TaskList extends Node { e.printStackTrace(); } - return SYNC_ACTION_ERROR; + return SYNC_ACTION_ERROR; // 如果在执行过程中出现异常,返回 SYNC_ACTION_ERROR } public int getChildTaskCount() { return mChildren.size(); - } + }//返回一个私有成员变量mChildren中存储的子任务数量 public boolean addChildTask(Task task) { boolean ret = false; - if (task != null && !mChildren.contains(task)) { - ret = mChildren.add(task); + if (task != null && !mChildren.contains(task)) { // 如果任务不为空且不包含在子任务列表中 + ret = mChildren.add(task); // 添加任务到子任务列表中 if (ret) { - // need to set prior sibling and parent - task.setPriorSibling(mChildren.isEmpty() ? null : mChildren - .get(mChildren.size() - 1)); - task.setParent(this); + // 需要设置前一个兄弟和父任务 + task.setPriorSibling(mChildren.isEmpty() ? null : mChildren.get(mChildren.size() - 1)); // 设置前一个兄弟,如果子任务列表为空,则前一个兄弟为 null + task.setParent(this); // 设置父任务为当前任务 } } return ret; } public boolean addChildTask(Task task, int index) { - if (index < 0 || index > mChildren.size()) { - Log.e(TAG, "add child task: invalid index"); + if (index < 0 || index > mChildren.size()) { // 如果索引位置小于 0 或大于子任务列表的大小 + Log.e(TAG, "add child task: invalid index"); // 打印错误日志 return false; } - int pos = mChildren.indexOf(task); - if (task != null && pos == -1) { - mChildren.add(index, task); + int pos = mChildren.indexOf(task); // 获取任务在子任务列表中的位置 + if (task != null && pos == -1) { // 如果任务不为空且不在子任务列表中 + mChildren.add(index, task); // 在指定索引位置添加任务 - // update the task list + // 更新任务列表 Task preTask = null; Task afterTask = null; if (index != 0) @@ -252,9 +260,9 @@ public class TaskList extends Node { if (index != mChildren.size() - 1) afterTask = mChildren.get(index + 1); - task.setPriorSibling(preTask); + task.setPriorSibling(preTask); // 设置前一个兄弟任务 if (afterTask != null) - afterTask.setPriorSibling(task); + afterTask.setPriorSibling(task); // 设置后一个兄弟任务的前一个兄弟任务为当前任务 } return true; @@ -262,16 +270,16 @@ public class TaskList extends Node { public boolean removeChildTask(Task task) { boolean ret = false; - int index = mChildren.indexOf(task); - if (index != -1) { - ret = mChildren.remove(task); + int index = mChildren.indexOf(task); // 获取任务在子任务列表中的位置 + if (index != -1) { // 如果任务在子任务列表中 + ret = mChildren.remove(task); // 从子任务列表中移除任务 if (ret) { - // reset prior sibling and parent + // 重置前一个兄弟任务和父任务 task.setPriorSibling(null); task.setParent(null); - // update the task list + // 更新任务列表 if (index != mChildren.size()) { mChildren.get(index).setPriorSibling( index == 0 ? null : mChildren.get(index - 1)); @@ -282,62 +290,61 @@ public class TaskList extends Node { } public boolean moveChildTask(Task task, int index) { - - if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "move child task: invalid index"); + if (index < 0 || index >= mChildren.size()) { // 如果索引位置小于 0 或大于等于子任务列表的大小 + Log.e(TAG, "move child task: invalid index"); // 打印错误日志 return false; } - int pos = mChildren.indexOf(task); - if (pos == -1) { - Log.e(TAG, "move child task: the task should in the list"); + int pos = mChildren.indexOf(task); // 获取任务在子任务列表中的位置 + if (pos == -1) { // 如果任务不在子任务列表中 + Log.e(TAG, "move child task: the task should in the list"); // 打印错误日志 return false; } if (pos == index) return true; - return (removeChildTask(task) && addChildTask(task, index)); + return (removeChildTask(task) && addChildTask(task, index)); // 先将任务从原位置移除,再将其移动到新位置 } public Task findChildTaskByGid(String gid) { - for (int i = 0; i < mChildren.size(); i++) { + for (int i = 0; i < mChildren.size(); i++) { // 遍历子任务列表 Task t = mChildren.get(i); - if (t.getGid().equals(gid)) { - return t; + if (t.getGid().equals(gid)) { // 如果找到了 GID 匹配的任务 + return t; // 返回该任务 } } - return null; + return null; // 如果没有找到匹配的任务,则返回 null } public int getChildTaskIndex(Task task) { - return mChildren.indexOf(task); + return mChildren.indexOf(task); // 获取指定任务在子任务列表中的位置 } public Task getChildTaskByIndex(int index) { - if (index < 0 || index >= mChildren.size()) { - Log.e(TAG, "getTaskByIndex: invalid index"); + if (index < 0 || index >= mChildren.size()) { // 如果索引位置小于 0 或大于等于子任务列表的大小 + Log.e(TAG, "getTaskByIndex: invalid index"); // 打印错误日志 return null; } - return mChildren.get(index); + return mChildren.get(index); // 返回指定位置的任务 } public Task getChilTaskByGid(String gid) { - for (Task task : mChildren) { - if (task.getGid().equals(gid)) - return task; + for (Task task : mChildren) { // 遍历子任务列表中的所有任务 + if (task.getGid().equals(gid)) // 如果找到了 GID 匹配的任务 + return task; // 返回该任务 } - return null; + return null; // 如果没有找到匹配的任务,则返回 null } public ArrayList getChildTaskList() { - return this.mChildren; + return this.mChildren; // 返回子任务列表 } public void setIndex(int index) { - this.mIndex = index; + this.mIndex = index; // 设置任务列表的索引位置 } public int getIndex() { - return this.mIndex; + return this.mIndex; // 获取任务列表的索引位置 } } diff --git a/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java b/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java index 15504be..3579e44 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java +++ b/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java @@ -17,17 +17,18 @@ package net.micode.notes.gtask.exception; public class ActionFailureException extends RuntimeException { + private static final long serialVersionUID = 4425249765923293627L; public ActionFailureException() { - super(); + super(); // 调用父类的构造函数 } public ActionFailureException(String paramString) { - super(paramString); + super(paramString); // 调用父类的构造函数,并传入异常信息 } public ActionFailureException(String paramString, Throwable paramThrowable) { - super(paramString, paramThrowable); + super(paramString, paramThrowable); // 调用父类的构造函数,并传入异常信息和原始异常 } } diff --git a/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java b/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java index b08cfb1..c6a2691 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java +++ b/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java @@ -17,17 +17,18 @@ package net.micode.notes.gtask.exception; public class NetworkFailureException extends Exception { + private static final long serialVersionUID = 2107610287180234136L; public NetworkFailureException() { - super(); + super(); // 调用父类的构造函数 } public NetworkFailureException(String paramString) { - super(paramString); + super(paramString); // 调用父类的构造函数,并传入异常信息 } public NetworkFailureException(String paramString, Throwable paramThrowable) { - super(paramString, paramThrowable); + super(paramString, paramThrowable); // 调用父类的构造函数,并传入异常信息和原始异常 } } diff --git a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java index 2315ef1..c88aef0 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -37,82 +37,82 @@ public class GTaskASyncTask extends AsyncTask { void onComplete(); } - private Context mContext; + private Context mContext; // 上下文对象 - private NotificationManager mNotifiManager; + private NotificationManager mNotifiManager; // 通知管理器对象 - private GTaskManager mTaskManager; + private GTaskManager mTaskManager; // GTask 管理器对象 - private OnCompleteListener mOnCompleteListener; + private OnCompleteListener mOnCompleteListener; // 异步任务完成后的回调接口 public GTaskASyncTask(Context context, OnCompleteListener listener) { - mContext = context; - mOnCompleteListener = listener; + mContext = context; // 初始化上下文对象 + mOnCompleteListener = listener; // 初始化回调接口 mNotifiManager = (NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE); - mTaskManager = GTaskManager.getInstance(); + .getSystemService(Context.NOTIFICATION_SERVICE); // 初始化通知管理器对象 + mTaskManager = GTaskManager.getInstance(); // 获取 GTask 管理器对象的单例 } public void cancelSync() { - mTaskManager.cancelSync(); + mTaskManager.cancelSync(); // 取消 GTask 同步 } public void publishProgess(String message) { publishProgress(new String[] { - message - }); + message + }); // 向主线程发布进度更新 } private void showNotification(int tickerId, String content) { Notification notification = new Notification(R.drawable.notification, mContext - .getString(tickerId), System.currentTimeMillis()); - notification.defaults = Notification.DEFAULT_LIGHTS; - notification.flags = Notification.FLAG_AUTO_CANCEL; + .getString(tickerId), System.currentTimeMillis()); // 创建通知 + notification.defaults = Notification.DEFAULT_LIGHTS; // 设置默认的通知灯光 + notification.flags = Notification.FLAG_AUTO_CANCEL; // 设置通知被点击后自动取消 PendingIntent pendingIntent; - if (tickerId != R.string.ticker_success) { + if (tickerId != R.string.ticker_success) { // 如果是同步失败的通知 pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesPreferenceActivity.class), 0); + NotesPreferenceActivity.class), 0); // 点击通知后打开 NotesPreferenceActivity - } else { + } else { // 如果是同步成功的通知 pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, - NotesListActivity.class), 0); + NotesListActivity.class), 0); // 点击通知后打开 NotesListActivity } //notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - // pendingIntent); - mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); + // pendingIntent); // 设置通知的标题、内容和点击后的操作 + mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); // 发送通知 } @Override protected Integer doInBackground(Void... unused) { publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity - .getSyncAccountName(mContext))); - return mTaskManager.sync(mContext, this); + .getSyncAccountName(mContext))); // 向主线程发布进度更新,显示正在登录的提示信息 + return mTaskManager.sync(mContext, this); // 开始 GTask 同步,并返回同步结果 } @Override protected void onProgressUpdate(String... progress) { - showNotification(R.string.ticker_syncing, progress[0]); + showNotification(R.string.ticker_syncing, progress[0]); // 显示同步进度的通知 if (mContext instanceof GTaskSyncService) { - ((GTaskSyncService) mContext).sendBroadcast(progress[0]); + ((GTaskSyncService) mContext).sendBroadcast(progress[0]); // 向 GTaskSyncService 发送广播,以便更新 UI } } @Override protected void onPostExecute(Integer result) { - if (result == GTaskManager.STATE_SUCCESS) { + if (result == GTaskManager.STATE_SUCCESS) { // 如果同步成功 showNotification(R.string.ticker_success, mContext.getString( - R.string.success_sync_account, mTaskManager.getSyncAccount())); - NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); - } else if (result == GTaskManager.STATE_NETWORK_ERROR) { - showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); - } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { - showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); - } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { + R.string.success_sync_account, mTaskManager.getSyncAccount())); // 显示同步成功的通知 + NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); // 更新最后同步时间 + } else if (result == GTaskManager.STATE_NETWORK_ERROR) { // 如果网络错误 + showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); // 显示同步失败的通知,提示网络错误 + } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { // 如果内部错误 + showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); // 显示同步失败的通知,提示内部错误 + } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { // 如果同步被取消 showNotification(R.string.ticker_cancel, mContext - .getString(R.string.error_sync_cancelled)); + .getString(R.string.error_sync_cancelled)); // 显示同步被取消的通知 } - if (mOnCompleteListener != null) { - new Thread(new Runnable() { + if (mOnCompleteListener != null) { // 如果设置了 OnCompleteListener + new Thread(new Runnable() { // 在新线程中执行 OnCompleteListener public void run() { mOnCompleteListener.onComplete(); @@ -120,4 +120,4 @@ public class GTaskASyncTask extends AsyncTask { }).start(); } } -} +} \ No newline at end of file diff --git a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java index c67dfdf..91314f8 100644 --- a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java +++ b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java @@ -64,50 +64,52 @@ import java.util.zip.InflaterInputStream; public class GTaskClient { private static final String TAG = GTaskClient.class.getSimpleName(); - private static final String GTASK_URL = "https://mail.google.com/tasks/"; + private static final String GTASK_URL = "https://mail.google.com/tasks/"; // GTask 的基础 URL - private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; + private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; // 获取 GTask 数据的 URL - private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; + private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; // 提交 GTask 数据的 URL - private static GTaskClient mInstance = null; + private static GTaskClient mInstance = null; // 单例模式,保存 GTaskClient 的唯一实例 - private DefaultHttpClient mHttpClient; + private DefaultHttpClient mHttpClient; // HTTP 客户端 - private String mGetUrl; + private String mGetUrl; // 获取 GTask 数据的完整 URL - private String mPostUrl; + private String mPostUrl; // 提交 GTask 数据的完整 URL - private long mClientVersion; + private long mClientVersion; // 客户端版本号 - private boolean mLoggedin; + private boolean mLoggedin; // 是否已登录 - private long mLastLoginTime; + private long mLastLoginTime; // 上次登录时间 - private int mActionId; + private int mActionId; // 操作 ID - private Account mAccount; - - private JSONArray mUpdateArray; + private Account mAccount; // GTask 帐户 + private JSONArray mUpdateArray; // 待更新的 GTask 数据 private GTaskClient() { - mHttpClient = null; - mGetUrl = GTASK_GET_URL; - mPostUrl = GTASK_POST_URL; - mClientVersion = -1; - mLoggedin = false; - mLastLoginTime = 0; - mActionId = 1; - mAccount = null; - mUpdateArray = null; - } + mHttpClient = null; // 初始化 HTTP 客户端为 null + mGetUrl = GTASK_GET_URL; // 初始化获取 GTask 数据的 URL + mPostUrl = GTASK_POST_URL; // 初始化提交 GTask 数据的 URL + mClientVersion = -1; // 初始化客户端版本号为 -1 + mLoggedin = false; // 初始化登录状态为 false + mLastLoginTime = 0; // 初始化上次登录时间为 0 + mActionId = 1; // 初始化操作 ID 为 1 + mAccount = null; // 初始化 GTask 帐户为 null + mUpdateArray = null; // 初始化待更新的 GTask 数据为 null + }/*该构造方法用于创建GTaskClient的实例,其中将mHttpClient、mAccount、mUpdateArray等成员变量初始化为 null 或默认值,将mGetUrl和mPostUrl初始化为 GTask 的默认 URL,将mClientVersion初始化为 -1,将mLoggedin初始化为 false,将mLastLoginTime初始化为 0,将mActionId初始化为 1。 + 这里使用了默认访问控制符private,意味着该构造方法只能在GTaskClient类内部使用,不能在其他类中创建GTaskClient的实例。*/ public static synchronized GTaskClient getInstance() { - if (mInstance == null) { - mInstance = new GTaskClient(); + if (mInstance == null) { // 如果唯一实例不存在 + mInstance = new GTaskClient(); // 则创建一个新实例 } - return mInstance; - } + return mInstance; // 返回唯一实例 + }/*该方法是单例模式的实现,用于获取GTaskClient的唯一实例。在该方法内部,首先判断唯一实例是否已经存在,如果不存在则创建一个新实例,并将其赋值给mInstance。最后返回唯一实例。 + 由于该方法可能被多个线程同时调用,所以使用了synchronized关键字来保证在同一时刻只有一个线程能够访问该方法。 + 同时,该方法返回的是静态成员变量mInstance,因此可以通过GTaskClient.getInstance()的方式在任意位置获取GTaskClient的唯一实例。*/ public boolean login(Activity activity) { // we suppose that the cookie would expire after 5 minutes @@ -120,38 +122,38 @@ public class GTaskClient { // need to re-login after account switch if (mLoggedin && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity - .getSyncAccountName(activity))) { + .getSyncAccountName(activity))) { mLoggedin = false; } - if (mLoggedin) { + if (mLoggedin) { // 如果已登录,则直接返回 Log.d(TAG, "already logged in"); return true; } - mLastLoginTime = System.currentTimeMillis(); - String authToken = loginGoogleAccount(activity, false); - if (authToken == null) { + mLastLoginTime = System.currentTimeMillis(); // 记录登录时间 + String authToken = loginGoogleAccount(activity, false); // 登录 Google 帐户,获取授权令牌 + if (authToken == null) { // 如果登录失败,则返回 false Log.e(TAG, "login google account failed"); return false; } // login with custom domain if necessary if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() - .endsWith("googlemail.com"))) { - StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); + .endsWith("googlemail.com"))) { // 如果不是 Gmail 或 Googlemail 帐户,则使用自定义域名登录 + StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); // 构造自定义域名的 URL int index = mAccount.name.indexOf('@') + 1; String suffix = mAccount.name.substring(index); url.append(suffix + "/"); - mGetUrl = url.toString() + "ig"; - mPostUrl = url.toString() + "r/ig"; + mGetUrl = url.toString() + "ig"; // 更新获取 GTask 数据的 URL + mPostUrl = url.toString() + "r/ig"; // 更新提交 GTask 数据的 URL - if (tryToLoginGtask(activity, authToken)) { - mLoggedin = true; + if (tryToLoginGtask(activity, authToken)) { // 尝试登录 GTask + mLoggedin = true; // 登录成功 } } - // try to login with google official url + // 如果自定义域名登录失败,则使用 Google 官方 URL 登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -160,30 +162,35 @@ public class GTaskClient { } } - mLoggedin = true; + mLoggedin = true; // 登录成功 return true; - } + }/*该方法用于登录 GTask,首先检查上次登录时间是否超过 5 分钟,如果超过则需要重新登录,将mLoggedin设置为 false。 + 然后判断当前帐户是否发生切换,如果发生切换也需要重新登录,同样将mLoggedin设置为 false。 + 如果已经登录,则直接返回 true。否则,记录本次登录时间,然后使用loginGoogleAccount()方法登录 Google 帐户,获取授权令牌。 + 如果登录失败,则返回 false。接下来,如果当前帐户不是 Gmail 或 Googlemail 帐户,则使用自定义域名登录,更新获取 GTask 数据和提交 GTask 数据的 URL,然后尝试登录 GTask。 + 如果自定义域名登录失败,则使用 Google 官方 URL 登录。 + 无论使用哪种方式登录成功,最后将mLoggedin设置为 true,表示已经登录成功。*/ private String loginGoogleAccount(Activity activity, boolean invalidateToken) { String authToken; - AccountManager accountManager = AccountManager.get(activity); - Account[] accounts = accountManager.getAccountsByType("com.google"); + AccountManager accountManager = AccountManager.get(activity); // 获取 AccountManager 实例 + Account[] accounts = accountManager.getAccountsByType("com.google"); // 获取所有 Google 帐户 - if (accounts.length == 0) { + if (accounts.length == 0) { // 如果没有可用的 Google 帐户,则返回 null Log.e(TAG, "there is no available google account"); return null; } - String accountName = NotesPreferenceActivity.getSyncAccountName(activity); + String accountName = NotesPreferenceActivity.getSyncAccountName(activity); // 获取设置中的同步帐户名称 Account account = null; for (Account a : accounts) { - if (a.name.equals(accountName)) { + if (a.name.equals(accountName)) { // 如果找到同名帐户,则使用该帐户 account = a; break; } } if (account != null) { - mAccount = account; + mAccount = account; // 更新当前使用的帐户 } else { Log.e(TAG, "unable to get an account with the same name in the settings"); return null; @@ -191,39 +198,48 @@ public class GTaskClient { // get the token now AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, - "goanna_mobile", null, activity, null, null); + "goanna_mobile", null, activity, null, null); // 获取 token try { Bundle authTokenBundle = accountManagerFuture.getResult(); - authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); - if (invalidateToken) { - accountManager.invalidateAuthToken("com.google", authToken); - loginGoogleAccount(activity, false); + authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); // 从 Bundle 中获取 token + if (invalidateToken) { // 如果需要使 token 失效 + accountManager.invalidateAuthToken("com.google", authToken); // 使 token 失效 + loginGoogleAccount(activity, false); // 重新登录 } - } catch (Exception e) { + } catch (Exception e) { // 获取 token 失败 Log.e(TAG, "get auth token failed"); authToken = null; } - return authToken; + return authToken; // 返回 token } + /*该方法的作用是获取 Google 帐户的 token,以用于访问 Google 服务。 + 它首先获取所有的 Google 帐户,然后根据设置中的同步帐户名称选择使用哪个帐户。 + 接着,它使用AccountManager获取该帐户的 token,并返回该 token。 + 如果invalidateToken参数为true,则该方法会使 token 失效,并重新登录,以获取新的 token。 + */ private boolean tryToLoginGtask(Activity activity, String authToken) { - if (!loginGtask(authToken)) { + if (!loginGtask(authToken)) { // 如果登录 GTask 失败 // maybe the auth token is out of date, now let's invalidate the // token and try again - authToken = loginGoogleAccount(activity, true); - if (authToken == null) { + authToken = loginGoogleAccount(activity, true); // 使 token 失效并重新登录 + if (authToken == null) { // 如果重新登录失败,则返回 false Log.e(TAG, "login google account failed"); return false; } - if (!loginGtask(authToken)) { + if (!loginGtask(authToken)) { // 如果重新登录 GTask 仍然失败,则返回 false Log.e(TAG, "login gtask failed"); return false; } } - return true; + return true; // 登录 GTask 成功,返回 true } + /*该方法的作用是尝试登录 GTask,它接收一个authToken参数,该参数是通过loginGoogleAccount()方法获取的 Google 帐户的 token。 + 如果登录 GTask 失败,则会使 token 失效并重新登录,再次尝试登录 GTask。 + 如果重新登录失败,则返回false,否则返回true。 + */ private boolean loginGtask(String authToken) { int timeoutConnection = 10000; @@ -231,6 +247,8 @@ public class GTaskClient { HttpParams httpParameters = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); + + // 设置 HttpClient 的参数 mHttpClient = new DefaultHttpClient(httpParameters); BasicCookieStore localBasicCookieStore = new BasicCookieStore(); mHttpClient.setCookieStore(localBasicCookieStore); @@ -239,11 +257,10 @@ public class GTaskClient { // login gtask try { String loginUrl = mGetUrl + "?auth=" + authToken; - HttpGet httpGet = new HttpGet(loginUrl); - HttpResponse response = null; - response = mHttpClient.execute(httpGet); + HttpGet httpGet = new HttpGet(loginUrl); // 创建 HTTP GET 请求 + HttpResponse response = mHttpClient.execute(httpGet); // 执行请求 - // get the cookie now + // 获取 cookie List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -255,7 +272,7 @@ public class GTaskClient { Log.w(TAG, "it seems that there is no auth cookie"); } - // get the client version + // 获取客户端版本 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -279,49 +296,63 @@ public class GTaskClient { return true; } + /*该方法的作用是使用给定的authToken登录 GTask。 + 它创建了一个 HTTP GET 请求,并将authToken添加到 URL 末尾,然后执行该请求并获取响应。 + 它还获取了响应中包含的 cookie,并将客户端版本存储在mClientVersion中。 + 如果登录成功,则返回true,否则返回false。如果发生异常,则返回false。 + */ private int getActionId() { - return mActionId++; + return mActionId++; // 返回下一个 action ID,并将 mActionId 加 1 } private HttpPost createHttpPost() { - HttpPost httpPost = new HttpPost(mPostUrl); - httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); - httpPost.setHeader("AT", "1"); - return httpPost; - } + HttpPost httpPost = new HttpPost(mPostUrl); // 创建一个 HTTP POST 请求 + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); // 设置请求头的 Content-Type + httpPost.setHeader("AT", "1"); // 设置请求头的 AT 字段为 1 + return httpPost; // 返回创建的 HTTP POST 请求 + }/*getActionId()的作用是获取下一个 action ID,每次调用它都会将mActionId加 1,并返回加 1 后的值。 + createHttpPost()的作用是创建一个 HTTP POST 请求,并设置请求头的 Content-Type 为application/x-www-form-urlencoded;charset=utf-8,设置请求头的 AT 字段为 1。 + 它返回创建的 HTTP POST 请求对象。 + */ private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; if (entity.getContentEncoding() != null) { - contentEncoding = entity.getContentEncoding().getValue(); + contentEncoding = entity.getContentEncoding().getValue(); // 获取响应内容的编码方式 Log.d(TAG, "encoding: " + contentEncoding); } - InputStream input = entity.getContent(); + InputStream input = entity.getContent(); // 获取响应内容的输入流 if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { - input = new GZIPInputStream(entity.getContent()); + input = new GZIPInputStream(entity.getContent()); // 如果响应内容被 gzip 压缩了,则创建一个 GZIPInputStream 解压缩 } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { Inflater inflater = new Inflater(true); - input = new InflaterInputStream(entity.getContent(), inflater); + input = new InflaterInputStream(entity.getContent(), inflater); // 如果响应内容被 deflate 压缩了,则创建一个 InflaterInputStream 解压缩 } try { - InputStreamReader isr = new InputStreamReader(input); - BufferedReader br = new BufferedReader(isr); - StringBuilder sb = new StringBuilder(); + InputStreamReader isr = new InputStreamReader(input); // 创建一个 InputStreamReader 对象 + BufferedReader br = new BufferedReader(isr); // 创建一个 BufferedReader 对象 + StringBuilder sb = new StringBuilder(); // 创建一个 StringBuilder 对象 while (true) { - String buff = br.readLine(); + String buff = br.readLine(); // 逐行读取响应内容 if (buff == null) { - return sb.toString(); + return sb.toString(); // 如果读到了末尾,则返回读取到的响应内容 } - sb = sb.append(buff); + sb = sb.append(buff); // 将读取到的响应内容追加到 StringBuilder 对象中 } } finally { - input.close(); + input.close(); // 关闭输入流 } } + /*getResponseContent(HttpEntity entity)的作用是从HttpEntity对象中获取响应内容,并将其解压(如果响应内容被压缩了)。它返回解压后的响应内容。 + 首先获取响应内容的编码方式,然后根据编码方式创建对应的输入流。 + 如果响应内容被 gzip 压缩了,则创建一个 GZIPInputStream 对象解压缩;如果响应内容被 deflate 压缩了,则创建一个 InflaterInputStream 对象解压缩。 + 接着使用 InputStreamReader 和 BufferedReader 逐行读取响应内容,并将其追加到 StringBuilder 对象中。 + 最后返回读取到的响应内容,并关闭输入流。 + */ private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { @@ -329,17 +360,17 @@ public class GTaskClient { throw new ActionFailureException("not logged in"); } - HttpPost httpPost = createHttpPost(); + HttpPost httpPost = createHttpPost(); // 创建 HTTP POST 请求 try { LinkedList list = new LinkedList(); - list.add(new BasicNameValuePair("r", js.toString())); - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); - httpPost.setEntity(entity); + list.add(new BasicNameValuePair("r", js.toString())); // 将传入的 JSONObject 对象转为字符串,并添加到请求参数中 + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); // 创建一个 UrlEncodedFormEntity 对象,用于封装请求参数 + httpPost.setEntity(entity); // 将 UrlEncodedFormEntity 对象设置为 HTTP POST 请求的实体 // execute the post - HttpResponse response = mHttpClient.execute(httpPost); - String jsString = getResponseContent(response.getEntity()); - return new JSONObject(jsString); + HttpResponse response = mHttpClient.execute(httpPost); // 执行 HTTP POST 请求 + String jsString = getResponseContent(response.getEntity()); // 获取响应内容,并将其解压(如果响应内容被压缩了),然后转为字符串 + return new JSONObject(jsString); // 将响应内容转为 JSONObject 对象 } catch (ClientProtocolException e) { Log.e(TAG, e.toString()); @@ -359,25 +390,30 @@ public class GTaskClient { throw new ActionFailureException("error occurs when posting request"); } } - + /*postRequest(JSONObject js)的作用是向服务器发送 HTTP POST 请求,并将响应内容转为JSONObject对象返回。 + 首先检查用户是否已经登录,如果没有登录则抛出异常。然后创建一个 HTTP POST 请求,并将传入的 JSONObject 对象转为字符串,并添加到请求参数中。接着,创建一个 UrlEncodedFormEntity 对象,用于封装请求参数,并将其设置为 HTTP POST 请求的实体。 + 执行 HTTP POST 请求,并获取响应内容。将响应内容解压(如果响应内容被压缩了),然后将其转为字符串,并通过 JSONObject 构造方法将其转为 JSONObject 对象。如果转换失败,则抛出异常。 + 如果在执行 HTTP POST 请求或转换响应内容为 JSONObject 对象时出现异常,则抛出相应的异常。 + */ public void createTask(Task task) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 提交所有未提交的更新操作 + try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); + JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象 + JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储操作列表 // action_list - actionList.put(task.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + actionList.put(task.getCreateAction(getActionId())); // 将新增任务的操作添加到操作列表中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将操作列表添加到 JSONObject 对象中 // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中 // post - JSONObject jsResponse = postRequest(jsPost); + JSONObject jsResponse = postRequest(jsPost); // 向服务器发送 HTTP POST 请求,并获取响应内容 JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); + GTaskStringUtils.GTASK_JSON_RESULTS).get(0); // 从响应内容中获取结果列表,并获取第一个结果 + task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); // 获取新任务的 ID,并将其设置为 Task 对象的 gid 属性 } catch (JSONException e) { Log.e(TAG, e.toString()); @@ -385,25 +421,30 @@ public class GTaskClient { throw new ActionFailureException("create task: handing jsonobject failed"); } } - + /*createTask(Task task)的作用是创建新任务。首先调用commitUpdate()方法提交所有未提交的更新操作。 + 然后创建一个新的 JSONObject 对象,并创建一个新的 JSONArray 对象,用于存储操作列表。将新增任务的操作添加到操作列表中,并将操作列表添加到 JSONObject 对象中。将客户端版本号也添加到 JSONObject 对象中。 + 向服务器发送 HTTP POST 请求,并获取响应内容。从响应内容中获取结果列表,并获取第一个结果。从结果中获取新任务的 ID,并将其设置为 Task 对象的 gid 属性。 + 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。 + */ public void createTaskList(TaskList tasklist) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 提交所有未提交的更新操作 + try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); + JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象 + JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储操作列表 // action_list - actionList.put(tasklist.getCreateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + actionList.put(tasklist.getCreateAction(getActionId())); // 将新增任务列表的操作添加到操作列表中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将操作列表添加到 JSONObject 对象中 - // client version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + // client_version + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中 // post - JSONObject jsResponse = postRequest(jsPost); + JSONObject jsResponse = postRequest(jsPost); // 向服务器发送 HTTP POST 请求,并获取响应内容 JSONObject jsResult = (JSONObject) jsResponse.getJSONArray( - GTaskStringUtils.GTASK_JSON_RESULTS).get(0); - tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); + GTaskStringUtils.GTASK_JSON_RESULTS).get(0); // 从响应内容中获取结果列表,并获取第一个结果 + tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); // 获取新任务列表的 ID,并将其设置为 TaskList 对象的 gid 属性 } catch (JSONException e) { Log.e(TAG, e.toString()); @@ -411,20 +452,25 @@ public class GTaskClient { throw new ActionFailureException("create tasklist: handing jsonobject failed"); } } - + /*createTaskList(TaskList tasklist)的作用是创建新任务列表。首先调用commitUpdate()方法提交所有未提交的更新操作。 + 然后创建一个新的 JSONObject 对象,并创建一个新的 JSONArray 对象,用于存储操作列表。将新增任务列表的操作添加到操作列表中,并将操作列表添加到 JSONObject 对象中。将客户端版本号也添加到 JSONObject 对象中。 + 向服务器发送 HTTP POST 请求,并获取响应内容。从响应内容中获取结果列表,并获取第一个结果。从结果中获取新任务列表的 ID,并将其设置为 TaskList 对象的 gid 属性。 + 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。 + */ public void commitUpdate() throws NetworkFailureException { - if (mUpdateArray != null) { + if (mUpdateArray != null) { // 判断更新操作列表是否为空 try { - JSONObject jsPost = new JSONObject(); + JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象 // action_list - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); // 将更新操作列表添加到 JSONObject 对象中 // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中 + + postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作 + mUpdateArray = null; // 更新操作提交成功后,清空更新操作列表 - postRequest(jsPost); - mUpdateArray = null; } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); @@ -432,52 +478,63 @@ public class GTaskClient { } } } - + /*commitUpdate()的作用是提交所有未提交的更新操作。如果更新操作列表不为空,则创建一个新的 JSONObject 对象,将更新操作列表添加到 JSONObject 对象中,并将客户端版本号也添加到 JSONObject 对象中。 + 向服务器发送 HTTP POST 请求,提交更新操作。提交成功后,清空更新操作列表。 + 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。 + */ public void addUpdateNode(Node node) throws NetworkFailureException { - if (node != null) { + if (node != null) { // 判断 Node 对象是否为空 // too many update items may result in an error // set max to 10 items - if (mUpdateArray != null && mUpdateArray.length() > 10) { - commitUpdate(); + if (mUpdateArray != null && mUpdateArray.length() > 10) { // 判断更新操作列表是否已满 + commitUpdate(); // 如果已满,则提交所有未提交的更新操作 } if (mUpdateArray == null) - mUpdateArray = new JSONArray(); - mUpdateArray.put(node.getUpdateAction(getActionId())); + mUpdateArray = new JSONArray(); // 如果更新操作列表还未创建,则创建一个新的 JSONArray 对象 + mUpdateArray.put(node.getUpdateAction(getActionId())); // 将 Node 对象的更新操作添加到更新操作列表中 } } - + /*addUpdateNode(Node node)的作用是向更新操作列表中添加一个新的更新操作。首先判断 Node 对象是否为空。 + 如果更新操作列表已满(长度大于 10),则调用commitUpdate()方法提交所有未提交的更新操作。 + 如果更新操作列表还未创建,则创建一个新的 JSONArray 对象。将 节点 + 如果 Node 对象为空,则不执行任何操作。 + */ public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 先提交所有未提交的更新操作 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); + JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象 + JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储更新操作 + JSONObject action = new JSONObject(); // 创建一个新的 JSONObject 对象,用于存储移动任务的操作 // action_list action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); - action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); // 设置操作类型为移动任务 + action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置操作 ID + action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); // 设置任务的 GID + if (preParent == curParent && task.getPriorSibling() != null) { // put prioring_sibing_id only if moving within the tasklist and // it is not the first one - action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); + action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); // 如果是在同一任务列表中移动任务,则设置前一个任务的 GID } - action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); - action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); + + action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); // 设置任务的原始任务列表的 GID + action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); // 设置任务的目标任务列表的 GID + if (preParent != curParent) { // put the dest_list only if moving between tasklists - action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); + action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); // 如果是在不同的任务列表之间移动任务,则设置任务的目标任务列表的 GID } - actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + + actionList.put(action); // 将移动任务的操作添加到更新操作列表中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将更新操作列表添加到 JSONObject 对象中 // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中 - postRequest(jsPost); + postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作 } catch (JSONException e) { Log.e(TAG, e.toString()); @@ -485,101 +542,127 @@ public class GTaskClient { throw new ActionFailureException("move task: handing jsonobject failed"); } } - + /*moveTask(Task task, TaskList preParent, TaskList curParent)的作用是移动一个任务到另一个任务列表中。 + 首先调用commitUpdate()方法提交所有未提交的更新操作。然后,创建一个新的 JSONObject 对象,用于存储移动任务的操作。 + 在移动任务的操作中,设置操作类型为移动任务。设置操作 ID 和任务的 GID。如果是在同一任务列表中移动任务,则设置前一个任务的 GID。设置任务的原始任务列表的 GID 和任务的目标任务列表的 GID。如果是在不同的任务列表之间移动任务,则设置任务的目标任务列表的 GID。 + 将移动任务的操作添加到更新操作列表中,然后将更新操作列表添加到 JSONObject 对象中。最后,添加客户端版本号到 JSONObject 对象中,向服务器发送 HTTP POST 请求,提交更新操作。 + 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常。 + */ public void deleteNode(Node node) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 先提交所有未提交的更新操作 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); + JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象 + JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储更新操作 // action_list - node.setDeleted(true); - actionList.put(node.getUpdateAction(getActionId())); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + node.setDeleted(true); // 将节点标记为已删除 + actionList.put(node.getUpdateAction(getActionId())); // 将节点的更新操作添加到更新操作列表中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将更新操作列表添加到 JSONObject 对象中 // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中 + + postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作 + mUpdateArray = null; // 将更新操作数组置为空 - postRequest(jsPost); - mUpdateArray = null; } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); - throw new ActionFailureException("delete node: handing jsonobject failed"); + throw new ActionFailureException("delete node: handing jsonobject failed"); // 处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常 } } + /*此方法的主要目的是删除一个节点,并将删除操作提交到服务器。 + 方法首先提交所有未提交的更新操作,然后创建一个新的 JSONObject 对象,将节点的删除操作添加到该对象中,同时添加客户端版本号。 + 最后,方法通过向服务器发送 HTTP POST 请求来提交更新操作,如果在处理 JSONObject 对象时出现异常,则会抛出 ActionFailureException 异常。 + */ public JSONArray getTaskLists() throws NetworkFailureException { - if (!mLoggedin) { + if (!mLoggedin) { // 如果用户没有登录,则抛出 ActionFailureException 异常 Log.e(TAG, "please login first"); throw new ActionFailureException("not logged in"); } try { - HttpGet httpGet = new HttpGet(mGetUrl); + HttpGet httpGet = new HttpGet(mGetUrl); // 创建一个新的 HttpGet 请求对象 HttpResponse response = null; - response = mHttpClient.execute(httpGet); + response = mHttpClient.execute(httpGet); // 执行 HttpGet 请求 // get the task list - String resString = getResponseContent(response.getEntity()); + String resString = getResponseContent(response.getEntity()); // 获取响应内容 String jsBegin = "_setup("; String jsEnd = ")}"; int begin = resString.indexOf(jsBegin); int end = resString.lastIndexOf(jsEnd); String jsString = null; - if (begin != -1 && end != -1 && begin < end) { + if (begin != -1 && end != -1 && begin < end) { // 如果响应内容中包含任务列表,那么提取出来 jsString = resString.substring(begin + jsBegin.length(), end); } - JSONObject js = new JSONObject(jsString); - return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); - } catch (ClientProtocolException e) { + JSONObject js = new JSONObject(jsString); // 将任务列表转换成 JSONObject 对象 + return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); // 返回任务列表数组 + + } catch (ClientProtocolException e) { // 如果发生协议错误,则抛出 NetworkFailureException 异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (IOException e) { + } catch (IOException e) { // 如果发生 I/O 错误,则抛出 NetworkFailureException 异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new NetworkFailureException("gettasklists: httpget failed"); - } catch (JSONException e) { + } catch (JSONException e) { // 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("get task lists: handing jasonobject failed"); } } + /*此方法的主要目的是从服务器获取用户的任务列表,并将其作为 JSONArray 对象返回。 + 方法首先检查用户是否已登录,然后创建一个新的 HttpGet 请求对象,并通过执行该请求来获取响应内容。 + 接下来,方法从响应内容中提取出任务列表,并将其转换为 JSONObject 对象,最后返回任务列表数组。 + 如果在执行 HttpGet 请求或处理 JSONObject 对象时发生错误,则会抛出 NetworkFailureException 或 ActionFailureException 异常。 + */ public JSONArray getTaskList(String listGid) throws NetworkFailureException { - commitUpdate(); + commitUpdate(); // 提交所有未提交的更改 try { - JSONObject jsPost = new JSONObject(); - JSONArray actionList = new JSONArray(); - JSONObject action = new JSONObject(); + JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象 + JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象 + JSONObject action = new JSONObject(); // 创建一个新的 JSONObject 对象 // action_list action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, - GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); - action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); - action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); - actionList.put(action); - jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); + GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); // 设置 action 的类型为 "getall" + action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置 action 的 ID + action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); // 设置 action 操作的任务列表 ID + action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); // 设置是否获取已删除的任务 + actionList.put(action); // 将 action 添加到 action_list 中 + jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将 action_list 添加到 jsPost 中 // client_version - jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); + jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 设置客户端版本号 - JSONObject jsResponse = postRequest(jsPost); - return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); - } catch (JSONException e) { + JSONObject jsResponse = postRequest(jsPost); // 发送请求并获取响应 + return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); // 从响应中获取任务列表并返回 + + } catch (JSONException e) { // 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常 Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("get task list: handing jsonobject failed"); } } + /*此方法的主要目的是从服务器获取特定任务列表的任务,并将其作为 JSONArray 对象返回。 + 方法首先提交所有未提交的更改,然后构造一个包含获取任务列表的请求并发送它。 + 接下来,方法从响应中提取出任务列表,并将其作为 JSONArray 对象返回。 + 如果在处理 JSONObject 对象时发生错误,则会抛出 ActionFailureException 异常。 + */ public Account getSyncAccount() { return mAccount; } + //这个方法返回GTaskClient的同步账户(即当前使用的 Google 帐户)。 public void resetUpdateArray() { mUpdateArray = null; } } + /*这个方法将GTaskClient的更新数组mUpdateArray设置为null,以清除未提交的更改。 + 在更新任务列表之前,需要调用commitUpdate()方法提交所有未提交的更改,如果您想丢弃这些更改,可以调用resetUpdateArray()方法以清除它们。 + */ \ No newline at end of file