/* * 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; //包含了一些用于处理GTask(Google Task)相关数据的类。具体来说,这些类实现了将本地笔记同步到Google Task中,以及从Google Task中同步笔记到本地的功能。 import android.database.Cursor;//引入Android类cursor(为Android提供接口用于访问数据源中的数据,并支持对数据进行查询、排序、更新等操作。) import android.text.TextUtils;// 引入Android类TextUtilsAndroid提供的一个工具类,包含了一些字符串处理相关的方法,如检查字符串是否为空、去除字符串两端的空格等 import android.util.Log;//引入Android类Log是Android提供的一个工具类,用于在开发和调试过程中输出日志信息 import net.micode.notes.data.Notes;//是该应用程序中的一个关键类,定义了笔记和数据表的结构 import net.micode.notes.data.Notes.DataColumns;//笔记表子类,定义了笔记表中的各个字段 import net.micode.notes.data.Notes.DataConstants;//是一个接口,定义了一些常量,如便签类型、便签状态等 import net.micode.notes.data.Notes.NoteColumns;//笔记表子类,定义了笔记表中的各个字段 import net.micode.notes.gtask.exception.ActionFailureException;//是自定义异常类,表示某个操作失败了 import net.micode.notes.tool.GTaskStringUtils;//是一个字符串处理工具类,定义了一些与Google Task有关的字符串处理方法 import org.json.JSONArray;//是一个表示JSON数组的类,可以方便地读取和操作JSON数组中的元素。 import org.json.JSONException;//是一个异常类,表示在解析JSON数据时发生了错误。 import org.json.JSONObject;//是一个表示JSON对象的类,可以方便地读取和操作JSON对象中的属性和值。 public class Task extends Node//定义了一个Task类,继承自Node类 { private static final String TAG = Task.class.getSimpleName(); private boolean mCompleted;//表示任务是否已完成 private String mNotes;//表示任务的注释信息 private JSONObject mMetaInfo;//表示任务的元信息,是一个JSONObject对象 private Task mPriorSibling;//表示该任务在同级任务中的前一个任务对象 private TaskList mParent;//表示该任务所属的任务列表对象 public Task() { super(); mCompleted = false; mNotes = null; mPriorSibling = null; mParent = null; mMetaInfo = null; }//无参构造函数,初始化所有属性值均为null或false public JSONObject getCreateAction(int actionId) //getCreateAction方法接收一个整型参数actionId,将该参数作为返回JSONObject对象的action_id属性值。 { JSONObject js = new JSONObject(); try { // action_type,创建操作 js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); // action_id js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // index,父任务列表中的索引 js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this)); // entity_delta一个JSONObject对象 JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());//得到任务名 entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");//对任务创建者id进行判空操作 entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,//实体类数据task GTaskStringUtils.GTASK_JSON_TYPE_TASK); if (getNotes() != null) //如果任务有注释,则设置notes属性表示任务注释信息。 { entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); } js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // parent_id js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid()); // dest_parent_type js.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE, GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // list_id js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid()); // prior_sibling_id if (mPriorSibling != null) { js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid()); } //如果该任务在兄弟任务中不是第一个,则设置prior_sibling_id属性值为前一个兄弟任务的gid。 } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to generate task-create jsonobject"); } //如果在生成JSONObject对象时发生异常,则会抛出一个自定义异常ActionFailureException。 return js; } public JSONObject getUpdateAction(int actionId) //getUpdateAction方法接收一个整型参数actionId,将该参数作为返回JSONObject对象的action_id属性值 { JSONObject js = new JSONObject(); try { // action_type js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); //action_type属性值为update,表示更新操作 // action_id js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); //id属性值为该任务的gid。 // id js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); // entity_delta JSONObject entity = new JSONObject(); entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());//任务名称 if (getNotes() != null) { entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes()); }//如果该任务有注释,则设置notes属性表示任务注释信息 entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); }//deleted属性表示任务是否被删除,如果该值为true,则该任务会被移除 catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to generate task-update jsonobject"); }//如果在生成JSONObject对象时发生异常,则会抛出一个自定义异常ActionFailureException。 return js; } public void setContentByRemoteJSON(JSONObject js) //定义了一个setContentByRemoteJSON方法,该方法从远程JSON对象中获取任务的属性值,并将这些属性值设置到本地任务对象中 //表示从远程服务器获取的任务信息 { if (js != null) //首先检查传入的JSON对象是否为空,如果不是空对象,则依次从JSON对象中获取以下属性值 { try { // id if (js.has(GTaskStringUtils.GTASK_JSON_ID)) //id属性值,并调用setGid方法将其赋值给本地任务对象的gid属性 { setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); } // last_modified if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); }//last_modified属性值,并调用setLastModified方法将其赋值给本地任务对象的lastModified属性 // name if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); }//name属性值,并调用setName方法将其赋值给本地任务对象的name属性 // notes if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) { setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES)); }//notes属性值,并调用setNotes方法将其赋值给本地任务对象的notes属性 // deleted if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) { setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED)); }//deleted属性值,并调用setDeleted方法将其赋值给本地任务对象的deleted属性 // completed if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) { setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED)); }//completed属性值,并调用setCompleted方法将其赋值给本地任务对象的completed属性 } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); throw new ActionFailureException("fail to get task content from jsonobject"); }//如果在解析JSON对象时发生异常,则会抛出一个自定义异常ActionFailureException } } public void setContentByLocalJSON(JSONObject js) //定义了一个setContentByLocalJSON方法,该方法从本地JSON对象中获取任务的属性值,并将这些属性值设置到本地任务对象中 //setContentByLocalJSON方法接收一个JSONObject参数js,用来表示本地存储的任务信息 { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); }//该方法首先检查传入的JSON对象是否为空,以及是否包含必要属性。如果不满足这些条件,则打印一条警告日志并退出方法 try { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); //从JSON对象中获取META_HEAD_NOTE和META_HEAD_DATA属性的值,并分别赋给变量note和dataArray if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) { Log.e(TAG, "invalid type"); return; } //该方法检查获取到的note对象的type属性是否为Notes.TYPE_NOTE,如果不是则打印一条错误日志并退出方法 for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { setName(data.getString(DataColumns.CONTENT)); break; } }//该方法遍历dataArray数组中的每个元素,找到mime_type属性为DataConstants.NOTE的元素,并将其content属性值赋给本地任务对象的name属性 } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); }//如果在解析JSON对象时发生异常,则会打印一条错误日志 } public JSONObject getLocalJSONFromContent() //定义了一个getLocalJSONFromContent方法,该方法从本地任务对象中获取任务的属性值,并将这些属性值构造成JSON对象返回 { String name = getName(); try { if (mMetaInfo == null)//获取任务的名称 { // new task created from web if (name == null) { Log.w(TAG, "the note seems to be an empty one"); return null; } //根据任务的元信息(即mMetaInfo属性),判断任务是从Web端创建还是同步而来。如果任务的元信息为空,则认为该任务是从Web端创建的。 JSONObject js = new JSONObject(); JSONObject note = new JSONObject(); JSONArray dataArray = new JSONArray(); JSONObject data = new JSONObject(); data.put(DataColumns.CONTENT, name); dataArray.put(data); js.put(GTaskStringUtils.META_HEAD_DATA, dataArray); note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); js.put(GTaskStringUtils.META_HEAD_NOTE, note); return js;//对于从Web端创建的任务,如果任务名称为空,则会打印一条警告日志并返回null。 // 否则,该方法构造一个JSONObject对象,其中包含META_HEAD_DATA和META_HEAD_NOTE两个属性 // 并将任务的名称设置为META_HEAD_DATA属性所表示的JSONArray对象中的data属性值 } else { // synced task JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA); //对于同步而来的任务,该方法首先获取任务的META_HEAD_DATA和META_HEAD_NOTE属性的值, for (int i = 0; i < dataArray.length(); i++) { JSONObject data = dataArray.getJSONObject(i); if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) { data.put(DataColumns.CONTENT, getName()); break; } }//遍历META_HEAD_DATA属性值所表示的JSONArray对象中的所有元素,找到mime_type属性为DataConstants.NOTE的元素,并将其content属性值设置为本地任务对象的名称 note.put(NoteColumns.TYPE, Notes.TYPE_NOTE); return mMetaInfo; }//最后,该方法将note对象的type属性设置为Notes.TYPE_NOTE,并返回元信息对应的JSONObject对象 } catch (JSONException e) { Log.e(TAG, e.toString()); e.printStackTrace(); return null; }//如果在构造JSON对象时发生异常,则会打印一条错误日志,并返回null } public void setMetaInfo(MetaData metaData) //用于设置mMetaInfo属性 //接收一个MetaData对象参数metaData { if (metaData != null && metaData.getNotes() != null) { try { mMetaInfo = new JSONObject(metaData.getNotes()); } //metaData不为空并且其notes属性不为空字符串,则将notes属性值解析为JSON对象,并将其赋给mMetaInfo属性 catch (JSONException e) { Log.w(TAG, e.toString()); mMetaInfo = null; }//如果在解析JSON对象时发生异常,则会打印一条警告日志并将mMetaInfo属性赋为null }//如果metaData对象或者其notes属性为空,则不会对mMetaInfo属性做任何更改 } public int getSyncAction(Cursor c) //用于返回同步任务的操作类型 { try { JSONObject noteInfo = null; if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) { noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); }//mMetaInfo属性,中获取与任务相关联的笔记信息 if (noteInfo == null) { Log.w(TAG, "it seems that note meta has been deleted"); return SYNC_ACTION_UPDATE_REMOTE; }//// 如果不存在,则会打印一条警告日志并返回SYNC_ACTION_UPDATE_REMOTE操作类型 if (!noteInfo.has(NoteColumns.ID)) { Log.w(TAG, "remote note id seems to be deleted"); return SYNC_ACTION_UPDATE_LOCAL; }//检查笔记信息中是否存在NoteColumns.ID属性, // 如果不存在,则会打印一条警告日志并返回SYNC_ACTION_UPDATE_LOCAL操作类型 // validate the note id now if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) { Log.w(TAG, "note id doesn't match"); return SYNC_ACTION_UPDATE_LOCAL; }//获取查询结果集c中的本地笔记的id属性值,并将其与笔记信息中的NoteColumns.ID属性值进行比较。 // 如果两者不相等,则会打印一条警告日志并返回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; }//根据本地笔记对象的LOCAL_MODIFIED_COLUMN属性值是否为0来确定是否存在本地更新。如果该属性值为0,则表示没有本地更新。 // 如果本地笔记对象的SYNC_ID_COLUMN属性值等于当前任务对象的最后修改时间,则表示两者都没有更新 // 返回SYNC_ACTION_NONE操作类型;否则,返回SYNC_ACTION_UPDATE_LOCAL操作类型。 } else { // validate 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; }//如果本地笔记对象的LOCAL_MODIFIED_COLUMN属性值不为0,则表示存在本地更新。 // 此时,检查SqlNote.GTASK_ID_COLUMN属性值是否与当前任务对象的Google Task ID相等。 // 如果不相等,打印一条错误日志并返回SYNC_ACTION_ERROR操作类型。 // 接着,比较本地笔记对象的SYNC_ID_COLUMN属性值与getLastModified()方法返回值是否相等。 // 如果相等,则表示只存在本地更新,返回SYNC_ACTION_UPDATE_REMOTE操作类型; // 否则,返回SYNC_ACTION_UPDATE_CONFLICT操作类型 } } catch (Exception e) { Log.e(TAG, e.toString()); e.printStackTrace(); } return SYNC_ACTION_ERROR; }//如果在执行过程中发生异常,则会打印一条错误日志并返回SYNC_ACTION_ERROR操作类型。 public boolean isWorthSaving() { return mMetaInfo != null || (getName() != null && getName().trim().length() > 0) || (getNotes() != null && getNotes().trim().length() > 0); }//isWorthSaving()方法用于判断当前任务对象是否值得保存,返回一个布尔值。 //该方法会判断以下三种情况,只要其中任意一种情况成立,则返回true,表示该任务对象值得保存: //mMetaInfo属性不为null,即当前任务对象存在元信息。 //getName()方法返回值不为null且去除空格后长度大于0,表示当前任务对象的名称不为空。 //getNotes()方法返回值不为null且去除空格后长度大于0,表示当前任务对象的笔记内容不为空。 //如果上述所有条件都不成立,则返回false,表示当前任务对象不值得保存 public void setCompleted(boolean completed) { this.mCompleted = completed; } public void setNotes(String notes) { this.mNotes = notes; } public void setPriorSibling(Task priorSibling) { this.mPriorSibling = priorSibling; } public void setParent(TaskList parent) { this.mParent = parent; } public boolean getCompleted() { return this.mCompleted; } public String getNotes() { return this.mNotes; } public Task getPriorSibling() { return this.mPriorSibling; } public TaskList getParent() { return this.mParent; } }