You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
note/TaskList.java

505 lines
38 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.micode.notes.gtask.data;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
// TaskList类继承自Node类可理解为用于表示任务列表相关的对象包含了任务列表自身的一些属性以及操作方法。
public class TaskList extends Node {
// 定义一个用于日志记录的标签,其值为类的简单名称(不含包名部分),便于在日志中清晰识别与该类相关的输出信息。
private static final String TAG = TaskList.class.getSimpleName();
// 用于记录任务列表的索引位置可能在某个更大的分组或者排序体系中的序号等初始值为1后续可根据实际情况改变。
private int mIndex;
// 用于存储该任务列表包含的多个任务对象以ArrayList形式进行管理方便进行任务的添加、删除、遍历等操作初始化为一个空的ArrayList。
private ArrayList<Task> mChildren;
// 无参构造函数用于创建TaskList对象时进行默认的初始化操作先调用父类Node类的无参构造函数然后初始化mChildren为一个新的空ArrayList并将mIndex设为1。
public TaskList() {
super();
mChildren = new ArrayList<Task>();
mIndex = 1;
}
// getCreateAction方法用于生成一个表示创建任务列表操作的JSONObject对象该JSON对象包含了创建任务列表所需的关键信息
// 例如操作类型、任务列表的基本属性等内容若在构建JSON过程中出现异常则抛出ActionFailureException异常。
public JSONObject getCreateAction(int actionId) {
// 创建一个新的JSONObject对象用于组装并最终返回包含创建任务列表操作相关信息的JSON数据结构。
JSONObject js = new JSONObject();
try {
// 设置JSON对象中的"action_type"字段表示操作类型将其值设为GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE
// 明确该JSON数据代表的是创建任务列表的操作方便后续解析此JSON的模块知晓操作意图。
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
// 设置JSON对象中的"action_id"字段把传入的actionId参数值赋给该字段actionId可能用于唯一标识这个创建任务列表操作的序号等便于区分不同操作实例。
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置JSON对象中的"index"字段将当前任务列表对象的索引位置mIndex赋给该字段用于表示任务列表在所属体系中的顺序等相关情况。
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex);
// 创建一个新的JSONObject对象用于组装任务列表实体相关的详细信息后续会将其整体放入外层的js对象中代表要创建的任务列表主体内容。
JSONObject entity = new JSONObject();
// 设置entity JSON对象中的"name"字段通过调用getName方法应是在父类Node或者本类中定义的获取名称的方法获取任务列表名称并赋给该字段使创建操作的JSON数据包含名称信息便于识别。
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
// 设置entity JSON对象中的"creator_id"字段,暂时将其值设为"null",可能后续需根据实际创建者标识准确赋值,这里先占位表示创建者信息暂未明确。
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
// 设置entity JSON对象中的"entity_type"字段将其值设为GTaskStringUtils.GTASK_JSON_TYPE_GROUP
// 表明这个实体是任务列表类型(分组类型),方便系统区分不同类型的实体。
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
// 将包含任务列表实体详细信息的entity对象以GTaskStringUtils.GTASK_JSON_ENTITY_DELTA为键添加到外层的js对象中
// 这样整个JSON数据结构就完整包含了创建任务列表操作以及要创建的任务列表具体内容等信息。
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
// 如果在构建JSON对象如往JSONObject添加元素等操作过程中出现JSONException异常记录错误日志打印异常堆栈信息方便排查问题
// 同时抛出ActionFailureException异常表示生成创建任务列表的JSON对象失败以便上层调用者捕获并处理该异常情况。
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate tasklist-create jsonobject");
}
// 如果成功构建了包含创建任务列表操作相关信息的JSON对象无异常情况则返回该js对象供后续操作如发送给服务器等场景使用。
return js;
}
}
// getUpdateAction方法用于生成一个表示更新任务列表操作的JSONObject对象该JSON对象包含了更新任务列表所需的关键信息
// 例如操作类型、任务列表的唯一标识符以及要更新的任务列表具体属性等内容若在构建JSON过程中出现异常则抛出ActionFailureException异常。
public JSONObject getUpdateAction(int actionId) {
// 创建一个新的JSONObject对象用于组装并最终返回包含更新任务列表操作相关信息的JSON数据结构。
JSONObject js = new JSONObject();
try {
// 设置JSON对象中的"action_type"字段表示操作类型将其值设为GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE
// 意味着这个JSON数据代表的是更新任务列表的操作方便后续解析该JSON数据的模块能识别操作意图。
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
// 设置JSON对象中的"action_id"字段将传入的actionId参数值赋给该字段actionId可能是用于唯一标识这个更新任务列表操作的序号等
// 在整个任务管理系统中便于区分不同的操作实例。
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
// 设置JSON对象中的"id"字段通过调用getGid方法该方法应该是在当前类或者父类中定义的用于获取任务列表唯一标识符的方法获取任务列表的唯一标识符Gid
// 并将其赋给该字段,用于明确要更新的是哪个具体任务列表,建立与具体任务列表实体的关联。
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
// 创建一个新的JSONObject对象用于组装任务列表实体相关的详细信息这些信息就是此次更新操作中涉及要改变的任务列表属性内容
// 后续会将其作为整体放入外层的js对象中代表更新任务列表时具体的变更内容。
JSONObject entity = new JSONObject();
// 设置entity JSON对象中的"name"字段通过调用getName方法用于获取任务列表名称的方法获取任务列表名称
// 并将其赋给该字段这样在更新任务列表的JSON数据中包含了可能要更新的任务列表名称信息方便根据实际需求修改任务列表的显示名称等情况。
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
// 设置entity JSON对象中的"deleted"字段通过调用getDeleted方法用于获取任务列表是否已删除状态的方法获取任务列表的删除状态
// 并将其赋给该字段,表明更新任务列表操作也可以涉及任务列表删除状态的变更,比如将未删除的任务列表标记为已删除等情况。
entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
// 将包含任务列表实体详细信息要更新的具体属性内容的entity对象以GTaskStringUtils.GTASK_JSON_ENTITY_DELTA为键添加到外层的js对象中
// 这样整个JSON数据结构就完整地包含了更新任务列表操作以及具体要更新的任务列表内容等信息。
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
// 如果在构建JSON对象如往JSONObject中添加元素等操作过程中出现了JSONException异常记录错误日志打印异常堆栈信息
// 方便排查问题同时抛出ActionFailureException异常表示生成更新任务列表的JSON对象失败以便上层调用者能捕获并处理该异常情况。
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate tasklist-update jsonobject");
}
// 如果成功构建了包含更新任务列表操作相关信息的JSON对象没有出现异常情况则返回该js对象供后续操作比如发送给服务器等场景使用。
return js;
}
// setContentByRemoteJSON方法用于根据传入的JSONObject对象通常是从远程获取的包含任务列表相关信息的JSON数据来设置当前TaskList对象的各项属性值
// 若传入的JSON对象为null或者在解析JSON过程中出现异常则抛出ActionFailureException异常。
public void setContentByRemoteJSON(JSONObject js) {
if (js!= null) {
try {
// 判断传入的JSON对象js中是否包含"id"字段如果包含则调用setGid方法用于设置任务列表唯一标识符的方法
// 并将该字段对应的字符串值通过getString方法获取传递进去实现根据远程JSON数据更新当前任务列表对象的唯一标识符属性。
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
// 判断传入的JSON对象js中是否包含"last_modified"字段如果包含则调用setLastModified方法用于设置任务列表最后修改时间的方法
// 并将该字段对应的长整型值通过getLong方法获取传递进去实现根据远程JSON数据更新当前任务列表对象的最后修改时间属性用于记录任务列表最新的修改情况。
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
// 判断传入的JSON对象js中是否包含"name"字段如果包含则调用setName方法用于设置任务列表名称的方法
// 并将该字段对应的字符串值通过getString方法获取传递进去实现根据远程JSON数据更新当前任务列表对象的任务列表名称属性以便任务列表显示正确的名称。
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
} catch (JSONException e) {
// 如果在解析JSON对象如获取对应字段的值等操作过程中出现了JSONException异常记录错误日志打印异常堆栈信息
// 方便排查问题同时抛出ActionFailureException异常表示从JSON对象中获取任务列表内容并设置到当前对象失败以便上层调用者能捕获并处理该异常情况。
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to get tasklist content from jsonobject");
}
}
}
// setContentByLocalJSON方法用于根据本地的JSONObject对象来设置当前TaskList对象的相关内容
// 如果传入的JSON对象不符合要求为null或者缺少关键的节点信息则记录警告日志若解析JSON出现异常也会记录错误日志。
public void setContentByLocalJSON(JSONObject js) {
// 判断传入的JSON对象是否为null或者是否不包含名为GTaskStringUtils.META_HEAD_NOTE的节点
// 如果满足这些情况之一则表示该JSON对象不符合处理要求记录警告日志提示没有可用信息。
if (js == null ||!js.has(GTaskStringUtils.META_HEAD_NOTE)) {
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
try {
// 从传入的JSON对象中获取名为GTaskStringUtils.META_HEAD_NOTE的子JSON对象该对象预期包含了与文件夹或系统相关的属性信息比如类型、名称等关键内容。
JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
// 判断获取到的folder对象中表示类型的字段NoteColumns.TYPE的值是否等于文件夹类型Notes.TYPE_FOLDER
// 如果是文件夹类型则从folder对象中获取表示摘要在这里可理解为文件夹名称的字段NoteColumns.SNIPPET对应的字符串值
// 然后调用setName方法用于设置任务列表名称的方法将其设置为特定格式加上前缀GTaskStringUtils.MIUI_FOLDER_PREFFIX的名称完成根据本地JSON数据对任务列表名称的更新。
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) {
// 如果类型是系统类型Notes.TYPE_SYSTEM则进一步根据系统文件夹的ID来设置不同的默认名称。
// 判断folder对象中表示ID的字段NoteColumns.ID的值是否等于根文件夹的IDNotes.ID_ROOT_FOLDER
// 如果是则调用setName方法将任务列表名称设置为特定格式加上前缀GTaskStringUtils.MIUI_FOLDER_PREFFIX和默认文件夹名称GTaskStringUtils.FOLDER_DEFAULT的名称。
if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER)
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);
// 判断folder对象中表示ID的字段NoteColumns.ID的值是否等于通话记录文件夹的IDNotes.ID_CALL_RECORD_FOLDER
// 如果是则调用setName方法将任务列表名称设置为特定格式加上前缀GTaskStringUtils.MIUI_FOLDER_PREFFIX和通话记录文件夹对应的名称GTaskStringUtils.FOLDER_CALL_NOTE的名称。
else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)
setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_CALL_NOTE);
else
// 如果不是上述已知的系统文件夹ID则记录错误日志表示是无效的系统文件夹因为无法确定如何正确设置名称了。
Log.e(TAG, "invalid system folder");
} else {
// 如果类型既不是文件夹类型也不是系统类型,则记录错误日志,表示出现了错误的类型,不符合预期的处理逻辑。
Log.e(TAG, "error type");
}
} catch (JSONException e) {
// 如果在解析JSON对象如获取子对象、获取字段值等操作过程中出现了JSONException异常记录错误日志打印异常堆栈信息方便排查问题。
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
// getLocalJSONFromContent方法用于根据当前TaskList对象的内容生成对应的本地JSONObject表示形式
// 如果在构建JSON过程中出现异常则记录错误日志并返回null主要是按照特定格式组装包含任务列表相关信息的JSON数据。
public JSONObject getLocalJSONFromContent() {
try {
// 创建一个新的JSONObject对象用于组装并最终返回包含任务列表相关信息的本地JSON数据结构。
JSONObject js = new JSONObject();
// 创建一个新的JSONObject对象用于存放与任务列表相关的属性信息这里主要是类型和名称相关内容后续会将其作为整体放入外层的js对象中。
JSONObject folder = new JSONObject();
// 获取当前任务列表对象的名称后续会根据名称来判断和设置相应的属性信息到folder对象中。
String folderName = getName();
// 判断任务列表名称是否以特定前缀GTaskStringUtils.MIUI_FOLDER_PREFFIX开头如果是则截取去掉前缀后的部分作为实际的文件夹名称
// 这样处理可能是为了在生成JSON数据时只保留关键的名称内容去除特定格式相关的前缀部分。
if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX))
folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(),
folderName.length());
// 将处理后的文件夹名称folderName添加到folder对象的NoteColumns.SNIPPET字段中相当于在JSON数据中记录了任务列表对应的名称信息。
folder.put(NoteColumns.SNIPPET, folderName);
// 判断处理后的文件夹名称是否等于默认文件夹名称GTaskStringUtils.FOLDER_DEFAULT或者通话记录文件夹对应的名称GTaskStringUtils.FOLDER_CALL_NOTE
// 如果是则将folder对象中表示类型的字段NoteColumns.TYPE的值设为系统类型Notes.TYPE_SYSTEM表明这是系统相关的文件夹
// 否则将类型字段设为文件夹类型Notes.TYPE_FOLDER以此来明确任务列表对应的类型属性并添加到folder对象中。
if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT)
|| folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE))
folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
else
folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
// 将包含任务列表相关属性信息的folder对象以GTaskStringUtils.META_HEAD_NOTE为键添加到外层的js对象中形成完整的符合要求的本地JSON数据结构。
js.put(GTaskStringUtils.META_HEAD_NOTE, folder);
// 返回组装好的js对象即包含了当前任务列表相关信息的本地JSON表示形式可供在本地存储、传输或者与其他本地模块交互时使用。
return js;
} catch (JSONException e) {
// 如果在构建JSON对象如往JSONObject中添加元素等操作过程中出现了JSONException异常记录错误日志打印异常堆栈信息方便排查问题。
Log.e(TAG, e.toString());
e.printStackTrace();
// 如果出现异常情况最终返回null表示无法成功获取任务列表对应的本地JSON内容表示形式。
return null;
}
}
// getSyncAction方法用于根据传入的Cursor对象通常用于从数据库查询结果中获取数据以及当前TaskList对象的相关状态
// 来确定在数据同步操作中应该执行的具体动作返回对应的同步动作标识SYNC_ACTION_* 系列常量之一若出现异常则返回SYNC_ACTION_ERROR。
public int getSyncAction(Cursor c) {
try {
// 判断本地是否没有更新通过检查Cursor对象中代表本地修改状态的列SqlNote.LOCAL_MODIFIED_COLUMN指定的列的值是否为0来确定
// 如果为0表示本地没有进行过更新操作。
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// 进一步判断远程和本地是否都没有更新通过比较Cursor对象中代表同步ID的列SqlNote.SYNC_ID_COLUMN指定的列的值
// 和当前TaskList对象的最后修改时间通过getLastModified方法获取是否相等来确定如果相等说明两边数据都没有更新
// 则返回SYNC_ACTION_NONE表示不需要进行任何同步操作两边数据是一致的。
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
return SYNC_ACTION_NONE;
} else {
// 如果同步ID不相等说明远程有更新需要将远程数据应用到本地返回SYNC_ACTION_UPDATE_LOCAL表示以远程数据更新本地数据。
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
// 如果本地有更新即本地修改状态列的值不为0则需要进一步验证任务列表的Gtask ID是否匹配
// 通过比较Cursor对象中代表Gtask ID的列SqlNote.GTASK_ID_COLUMN指定的列获取的字符串值
// 和当前TaskList对象通过getGid方法获取的Gtask ID是否相等来确定如果不相等记录错误日志因为这可能是比较严重的不一致情况
// 并返回SYNC_ACTION_ERROR表示出现了同步错误两边的关键标识不一致了。
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
return SYNC_ACTION_ERROR;
}
// 再次判断远程和本地的更新情况通过比较Cursor对象中代表同步ID的列SqlNote.SYNC_ID_COLUMN指定的列的值
// 和当前TaskList对象的最后修改时间通过getLastModified方法获取是否相等来确定如果相等说明只有本地进行了修改
// 则返回SYNC_ACTION_UPDATE_REMOTE表示需要将本地的修改同步到远程让远程数据也更新为本地修改后的状态。
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
return SYNC_ACTION_UPDATE_REMOTE;
} else {
// 对于文件夹类型的冲突情况(根据注释这里针对文件夹做了特殊处理),直接采用本地修改进行同步,
// 也就是返回SYNC_ACTION_UPDATE_REMOTE表示将本地的修改应用到远程数据上以本地为准进行同步可能是基于特定业务逻辑考虑文件夹的同步策略。
return SYNC_ACTION_UPDATE_REMOTE;
}
}
} catch (Exception e) {
// 如果在整个方法执行过程中出现了任何异常捕获了Exception类型涵盖了各种可能的运行时异常等情况记录错误日志打印异常堆栈信息方便排查问题
// 并返回SYNC_ACTION_ERROR表示出现了同步相关的错误情况无法准确判断同步动作。
Log.e(TAG, "gtask id doesn't match");
e.printStackTrace();
}
// 如果前面执行过程中出现了未处理的情况或者最终正常流程执行完毕但没有返回合适的同步动作标识默认返回SYNC_ACTION_ERROR表示出现错误。
return SYNC_ACTION_ERROR;
}
// getChildTaskCount方法用于获取当前TaskList对象中包含的子任务Task类型的数量
// 它直接返回存储子任务的ArrayListmChildren的大小即其中包含的元素个数也就是子任务的数量。
public int getChildTaskCount() {
return mChildren.size();
}
// addChildTask方法单个参数版本用于向当前TaskList对象的子任务列表mChildren中添加一个Task类型的子任务
// 如果添加成功还会设置该子任务的前序兄弟任务priorSibling和父任务parent属性返回添加操作是否成功的布尔值。
public boolean addChildTask(Task task) {
// 初始化一个布尔变量ret用于记录最终添加子任务操作是否成功初始值设为false。
boolean ret = false;
// 首先判断传入的任务对象task不为null并且当前子任务列表mChildren中不包含该任务对象避免重复添加才进行后续添加操作。
if (task!= null &&!mChildren.contains(task)) {
// 调用ArrayList的add方法尝试将任务对象添加到子任务列表mChildrenadd方法会返回添加操作是否成功的布尔值将其赋值给ret变量。
ret = mChildren.add(task);
// 如果添加操作成功ret为true则需要设置该子任务的前序兄弟任务priorSibling和父任务parent属性。
if (ret) {
// 判断子任务列表是否为空如果为空则将该子任务的前序兄弟任务设为null因为没有其他任务在它之前
// 如果不为空,则将该子任务的前序兄弟任务设为子任务列表中的最后一个任务(即当前刚添加任务之前的那个任务),通过获取子任务列表最后一个元素的方式来设置。
task.setPriorSibling(mChildren.isEmpty()? null : mChildren
.get(mChildren.size() - 1));
// 设置该子任务的父任务为当前TaskList对象表明该任务属于这个任务列表建立正确的层级关系。
task.setParent(this);
}
}
// 返回添加操作是否成功的结果ret的值供外部调用者知晓添加子任务的情况。
return ret;
}
// addChildTask方法两个参数版本用于向当前TaskList对象的子任务列表mChildren中指定索引位置添加一个Task类型的子任务
// 如果索引位置不合法会记录错误日志并返回false添加成功会更新相关任务的前序兄弟任务关系返回添加操作是否成功的布尔值按逻辑这里始终返回true但可以根据实际情况调整返回值来更准确反馈操作结果
public boolean addChildTask(Task task, int index) {
// 判断传入的索引值index是否小于0或者大于子任务列表的当前大小mChildren.size()如果是则表示索引位置不合法记录错误日志并返回false表示添加操作失败。
if (index < 0 || index > mChildren.size()) {
Log.e(TAG, "add child task: invalid index");
return false;
}
// 查找传入的任务对象task在子任务列表mChildren中的位置索引如果不存在则返回 -1这里获取其位置索引用于后续判断是否重复添加等情况。
int pos = mChildren.indexOf(task);
// 再次判断任务对象task不为null并且在子任务列表中的位置索引为 -1即不存在于列表中避免重复添加才进行后续添加操作。
if (task!= null && pos == -1) {
// 使用ArrayList的add方法在指定的索引位置index添加任务对象将任务插入到子任务列表中相应位置。
mChildren.add(index, task);
// 更新任务列表中相关任务的前序兄弟任务关系,以下操作是为了维护任务之间正确的顺序关系。
// 初始化前序任务preTask和后续任务afterTask变量分别用于存储插入位置之前和之后的任务对象初始值设为null后续根据实际情况赋值。
Task preTask = null;
Task afterTask = null;
// 如果插入的索引位置不是0即不是在列表开头插入则获取插入位置前一个位置的任务对象赋值给preTask作为新插入任务的前序兄弟任务。
if (index!= 0)
preTask = mChildren.get(index - 1);
// 如果插入的索引位置不是子任务列表的最后一个位置即不是在列表末尾插入则获取插入位置后一个位置的任务对象赋值给afterTask后续用于更新其前序兄弟任务关系。
if (index!= mChildren.size() - 1)
afterTask = mChildren.get(index + 1);
// 设置新插入任务task的前序兄弟任务为preTask建立正确的顺序关系。
task.setPriorSibling(preTask);
// 如果afterTask不为null即存在后续任务则设置该后续任务afterTask的前序兄弟任务为新插入的任务task更新顺序关系确保任务之间的先后顺序正确。
if (afterTask!= null)
afterTask.setPriorSibling(task);
}
// 按当前逻辑只要执行到这里就认为添加操作是进行了的即使可能有一些逻辑上的异常情况未完全考虑周全所以返回true表示添加子任务操作成功
// 也可以根据更严格的业务逻辑需求,进一步完善这里的返回值判断,使其更准确地反馈添加操作的实际结果。
return true;
}
// removeChildTask方法用于从当前TaskList对象的子任务列表mChildren中移除指定的Task类型子任务
// 如果移除成功,会重置该子任务的前序兄弟任务和父任务属性,同时更新子任务列表中相关任务的前序兄弟任务关系,返回移除操作是否成功的布尔值。
public boolean removeChildTask(Task task) {
// 初始化一个布尔变量ret用于记录最终移除子任务操作是否成功初始值设为false。
boolean ret = false;
// 获取要移除的任务对象task在子任务列表mChildren中的索引位置如果不存在则返回 -1后续根据该索引进行相关操作判断。
int index = mChildren.indexOf(task);
// 如果任务对象在子任务列表中的索引位置不为 -1即存在于列表中则进行移除操作。
if (index!= -1) {
// 调用ArrayList的remove方法尝试移除任务对象remove方法会返回移除操作是否成功的布尔值将其赋值给ret变量。
ret = mChildren.remove(task);
// 如果移除操作成功ret为true则需要重置该子任务的前序兄弟任务和父任务属性以及更新子任务列表中相关任务的前序兄弟任务关系。
if (ret) {
// 将该子任务的前序兄弟任务设为null因为它已经从任务列表中移除了不再有前序兄弟任务的关联。
task.setPriorSibling(null);
// 将该子任务的父任务设为null表明它不再属于当前的任务列表解除层级关系。
task.setParent(null);
// 更新子任务列表中相关任务的前序兄弟任务关系,以下操作是为了维护剩余任务之间正确的顺序关系。
// 判断移除的任务所在索引位置index是否不等于子任务列表的当前大小即不是移除的最后一个任务如果是则需要更新后续任务的前序兄弟任务关系。
if (index!= mChildren.size()) {
// 获取移除任务所在索引位置对应的任务对象即后续任务并设置其前序兄弟任务为移除任务之前的那个任务如果移除的是第一个任务则设为null
// 通过获取相应索引位置的任务对象来更新其前序兄弟任务属性,确保任务之间的先后顺序正确。
mChildren.get(index).setPriorSibling(
index == 0? null : mChildren.get(index - 1));
}
}
}
// 返回移除操作是否成功的结果ret的值供外部调用者知晓移除子任务的情况。
return ret;
}
// moveChildTask方法用于在当前TaskList对象的子任务列表mChildren中移动指定的Task类型子任务到新的索引位置
// 如果索引位置不合法或者任务不在列表中会记录错误日志并返回false移动成功则返回true内部通过先移除再添加的方式实现移动操作。
public boolean moveChildTask(Task task, int index) {
// 判断传入的新索引位置index是否小于0或者大于等于子任务列表的当前大小mChildren.size()如果是则表示索引位置不合法记录错误日志并返回false表示移动操作失败。
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "move child task: invalid index");
return false;
}
// 获取要移动的任务对象task在子任务列表mChildren中的当前索引位置如果不存在则返回 -1后续根据该索引进行相关操作判断。
int pos = mChildren.indexOf(task);
// 如果任务对象在子任务列表中的索引位置为 -1即任务不在列表中记录错误日志并返回false表示移动操作失败因为无法移动一个不存在于列表中的任务。
if (pos == -1) {
Log.e(TAG, "move child task: the task should in the list");
return false;
}
// 判断任务对象当前的索引位置pos是否与传入的新索引位置index相等如果相等说明任务已经在目标位置了不需要进行移动操作直接返回true表示移动操作成功其实就是无需操作的情况
if (pos == index)
return true;
// 通过先调用removeChildTask方法移除任务对象再调用addChildTask方法两个参数版本将任务对象添加到新的索引位置的方式来实现移动任务的操作
// 如果移除和添加操作都成功则整体移动操作成功返回true如果有任何一个操作失败则返回false表示移动操作失败。
return (removeChildTask(task) && addChildTask(task, index));
}
// findChildTaskByGid方法用于在当前TaskList对象的子任务列表mChildren中根据任务的唯一标识符Gid查找对应的Task类型子任务
// 如果找到则返回该任务对象没找到则返回null通过遍历子任务列表进行查找匹配。
public Task findChildTaskByGid(String gid) {
// 遍历子任务列表mChildren从索引0开始到列表大小结束不包含列表大小对应的索引即遍历所有元素
for (int i = 0; i < mChildren.size(); i++) {
// 获取当前遍历到的任务对象。
Task t = mChildren.get(i);
// 判断当前任务对象的唯一标识符通过getGid方法获取是否与传入的Gid参数相等如果相等则找到了对应的任务对象返回该任务对象。
if (t.getGid().equals(gid)) {
return t;
}
}
// 如果遍历完整个子任务列表都没有找到匹配的任务对象则返回null表示未找到。
return null;
}
// getChildTaskIndex方法用于获取指定Task类型子任务在当前TaskList对象的子任务列表mChildren中的索引位置
// 通过调用ArrayList的indexOf方法来查找并返回对应的索引值如果任务不在列表中则返回 -1。
public int getChildTaskIndex(Task task) {
return mChildren.indexOf(task);
}
// getChildTaskByIndex方法用于根据索引位置从当前TaskList对象的子任务列表mChildren中获取对应的Task类型子任务
// 如果索引位置不合法会记录错误日志并返回null合法则返回对应索引位置的任务对象通过直接从列表中获取元素的方式来获取任务对象。
public Task getChildTaskByIndex(int index) {
// 判断传入的索引值index是否小于0或者大于等于子任务列表的当前大小mChildren.size()如果是则表示索引位置不合法记录错误日志并返回null表示无法获取任务对象。
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "getTaskByIndex: invalid index");
return null;
}
// 如果索引位置合法,则直接从子任务列表中获取对应索引位置的任务对象,并返回该任务对象。
return mChildren.get(index);
}
// getChilTaskByGid方法同样用于在当前TaskList对象的子任务列表mChildren中根据任务的唯一标识符Gid查找对应的Task类型子任务
// 不过这里是通过增强for循环来遍历列表进行查找匹配找到则返回任务对象没找到则返回null功能和findChildTaskByGid方法类似但遍历方式不同。
public Task getChilTaskByGid(String gid) {
// 使用增强for循环遍历子任务列表mChildren依次获取每个任务对象进行判断。
for (Task task : mChildren) {
// 判断当前遍历到的任务对象的唯一标识符通过getGid方法获取是否与传入的Gid参数相等如果相等则找到了对应的任务对象返回该任务对象。
if (task.getGid().equals(gid))
return task;
}
// 如果遍历完整个子任务列表都没有找到匹配的任务对象则返回null表示未找到。
return null;
}
// getChildTaskList方法用于获取当前TaskList对象的子任务列表mChildren直接返回存储子任务的ArrayList对象
// 外部调用者可以通过获取到的列表进行进一步的操作,比如遍历、修改等(但需遵循相应的规则和逻辑)。
public ArrayList<Task> getChildTaskList() {
return this.mChildren;
}
// setIndex方法用于设置当前TaskList对象的索引属性mIndex将传入的索引值赋给该属性方便更新任务列表在所属体系中的顺序等相关情况。
public void setIndex(int index) {
this.mIndex = index;
}
// getIndex方法用于获取当前TaskList对象的索引属性mIndex的值直接返回该属性的值外部调用者可以获取该索引值来了解任务列表的相关顺序信息等。
public int getIndex() {
return this.mIndex;
}