目录

一、data包

1、MetaData.java

2、Node.java

3、SqlData.java

4、SqlNote.java

5、Task.java

6、TaskList.java

二、exception包

1、ActionFailureException.java

2、NetworkFailureException.java

三、remote包

1、GTaskASyncTask.java

2、GTaskClient.java

3、GTaskManager.java

4、GTaskSyncService.java


一、data包

1、MetaData.java

package net.micode.notes.gtask.data;public class MetaData extends Task {/** 功能描述:得到类的简写名称存入字符串TAG中* 实现过程:调用getSimpleName ()函数*/private final static String TAG = MetaData.class.getSimpleName();private String mRelatedGid = null;/** 功能描述:设置数据,即生成元数据库* 实现过程:调用JSONObject库函数put (),Task类中的setNotes ()和setName ()函数* 参数注解:*/public void setMeta(String gid, JSONObject metaInfo) {//对函数块进行注释try {metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);/** 将这对键值放入metaInfo这个jsonobject对象中*/} catch (JSONException e) {Log.e(TAG, "failed to put related gid");/** 输出错误信息*/}setNotes(metaInfo.toString());setName(GTaskStringUtils.META_NOTE_NAME);}/** 功能描述:获取相关联的Gid*/public String getRelatedGid() {return mRelatedGid;}/** 功能描述:判断当前数据是否为空,若为空则返回真即值得保存* Made By CuiCan*/@Overridepublic boolean isWorthSaving() {return getNotes() != null;}/** 功能描述:使用远程json数据对象设置元数据内容* 实现过程:调用父类Task中的setContentByRemoteJSON ()函数,并* 参数注解: */@Overridepublic void setContentByRemoteJSON(JSONObject js) {super.setContentByRemoteJSON(js);if (getNotes() != null) {try {JSONObject metaInfo = new JSONObject(getNotes().trim());mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);} catch (JSONException e) {Log.w(TAG, "failed to get related gid");/** 输出警告信息*/mRelatedGid = null;}}}/** 功能描述:使用本地json数据对象设置元数据内容,一般不会用到,若用到,则抛出异常* Made By CuiCan*/@Overridepublic void setContentByLocalJSON(JSONObject js) {// this function should not be calledthrow new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");/** 传递非法参数异常*/}/** 功能描述:从元数据内容中获取本地json对象,一般不会用到,若用到,则抛出异常* Made By CuiCan*/@Overridepublic JSONObject getLocalJSONFromContent() {throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");/** 传递非法参数异常* Made By Cui Can*/}/** 功能描述:获取同步动作状态,一般不会用到,若用到,则抛出异常* Made By CuiCan*/@Overridepublic int getSyncAction(Cursor c) {throw new IllegalAccessError("MetaData:getSyncAction should not be called");/** 传递非法参数异常* Made By Cui Can*/}}

2、Node.java

package net.micode.notes.gtask.data;import android.database.Cursor;import org.json.JSONObject;/*** 应该是同步操作的基础数据类型,定义了相关指示同步操作的常量* 关键字:abstract*/
public abstract class Node {//定义了各种用于表征同步状态的常量public static final int SYNC_ACTION_NONE = 0;// 本地和云端都无可更新内容(即本地和云端内容一致)public static final int SYNC_ACTION_ADD_REMOTE = 1;// 需要在远程云端增加内容public static final int SYNC_ACTION_ADD_LOCAL = 2;// 需要在本地增加内容public static final int SYNC_ACTION_DEL_REMOTE = 3;// 需要在远程云端删除内容public static final int SYNC_ACTION_DEL_LOCAL = 4;// 需要在本地删除内容public static final int SYNC_ACTION_UPDATE_REMOTE = 5;// 需要将本地内容更新到远程云端public static final int SYNC_ACTION_UPDATE_LOCAL = 6;// 需要将远程云端内容更新到本地public static final int SYNC_ACTION_UPDATE_CONFLICT = 7;// 同步出现冲突public static final int SYNC_ACTION_ERROR = 8;// 同步出现错误private String mGid;private String mName;private long mLastModified;//记录最后一次修改时间private boolean mDeleted;//表征是否被删除public Node() {mGid = null;mName = "";mLastModified = 0;mDeleted = false;}public abstract JSONObject getCreateAction(int actionId);public abstract JSONObject getUpdateAction(int actionId);public abstract void setContentByRemoteJSON(JSONObject js);public abstract void setContentByLocalJSON(JSONObject js);public abstract JSONObject getLocalJSONFromContent();public abstract int getSyncAction(Cursor c);public void setGid(String gid) {this.mGid = gid;}public void setName(String name) {this.mName = name;}public void setLastModified(long lastModified) {this.mLastModified = lastModified;}public void setDeleted(boolean deleted) {this.mDeleted = deleted;}public String getGid() {return this.mGid;}public String getName() {return this.mName;}public long getLastModified() {return this.mLastModified;}public boolean getDeleted() {return this.mDeleted;}}

3、SqlData.java

/** Description:用于支持小米便签最底层的数据库相关操作,和sqlnote的关系上是子集关系,即data是note的子集(节点)。* SqlData其实就是也就是所谓数据中的数据*/package net.micode.notes.gtask.data;
/** 功能描述:* 实现过程:* 参数注解: * Made By CuiCan*/public class SqlData {/** 功能描述:得到类的简写名称存入字符串TAG中* 实现过程:调用getSimpleName ()函数* Made By CuiCan*/private static final String TAG = SqlData.class.getSimpleName();private static final int INVALID_ID = -99999;//为mDataId置初始值-99999/*** 来自Notes类中定义的DataColumn中的一些常量*/// 集合了interface DataColumns中所有SF常量public static final String[] PROJECTION_DATA = new String[] {DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1,DataColumns.DATA3};/*** 以下五个变量作为sql表中5列的编号*/public static final int DATA_ID_COLUMN = 0;public static final int DATA_MIME_TYPE_COLUMN = 1;public static final int DATA_CONTENT_COLUMN = 2;public static final int DATA_CONTENT_DATA_1_COLUMN = 3;public static final int DATA_CONTENT_DATA_3_COLUMN = 4;private ContentResolver mContentResolver;//判断是否直接用Content生成,是为true,否则为falseprivate boolean mIsCreate;private long mDataId;private String mDataMimeType;private String mDataContent;private long mDataContentData1;private String mDataContentData3;private ContentValues mDiffDataValues;/** 功能描述:构造函数,用于初始化数据* 参数注解:mContentResolver用于获取ContentProvider提供的数据* 参数注解: mIsCreate表征当前数据是用哪种方式创建(两种构造函数的参数不同)* 参数注解: * Made By CuiCan*/public SqlData(Context context) {mContentResolver = context.getContentResolver();mIsCreate = true;mDataId = INVALID_ID;//mDataId置初始值-99999mDataMimeType = DataConstants.NOTE;mDataContent = "";mDataContentData1 = 0;mDataContentData3 = "";mDiffDataValues = new ContentValues();}/** 功能描述:构造函数,初始化数据* 参数注解:mContentResolver用于获取ContentProvider提供的数据* 参数注解: mIsCreate表征当前数据是用哪种方式创建(两种构造函数的参数不同)* 参数注解: * Made By CuiCan*/public SqlData(Context context, Cursor c) {mContentResolver = context.getContentResolver();mIsCreate = false;loadFromCursor(c);mDiffDataValues = new ContentValues();}/** 功能描述:从光标处加载数据* 从当前的光标处将五列的数据加载到该类的对象* Made By CuiCan*/private void loadFromCursor(Cursor c) {mDataId = c.getLong(DATA_ID_COLUMN);mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN);mDataContent = c.getString(DATA_CONTENT_COLUMN);mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN);mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN);}/** 功能描述:设置用于共享的数据,并提供异常抛出与处理机制* 参数注解: * Made By CuiCan*/public void setContent(JSONObject js) throws JSONException {//如果传入的JSONObject对象中有DataColumns.ID这一项,则设置,否则设为INVALID_IDlong dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID;if (mIsCreate || mDataId != dataId) {mDiffDataValues.put(DataColumns.ID, dataId);}mDataId = dataId;String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE): DataConstants.NOTE;if (mIsCreate || !mDataMimeType.equals(dataMimeType)) {mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType);}mDataMimeType = dataMimeType;String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : "";if (mIsCreate || !mDataContent.equals(dataContent)) {mDiffDataValues.put(DataColumns.CONTENT, dataContent);}mDataContent = dataContent;long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0;if (mIsCreate || mDataContentData1 != dataContentData1) {mDiffDataValues.put(DataColumns.DATA1, dataContentData1);}mDataContentData1 = dataContentData1;String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : "";if (mIsCreate || !mDataContentData3.equals(dataContentData3)) {mDiffDataValues.put(DataColumns.DATA3, dataContentData3);}mDataContentData3 = dataContentData3;}/** 功能描述:获取共享的数据内容,并提供异常抛出与处理机制* 参数注解: * Made By CuiCan*/public JSONObject getContent() throws JSONException {if (mIsCreate) {Log.e(TAG, "it seems that we haven't created this in database yet");return null;}//创建JSONObject对象。并将相关数据放入其中,并返回。JSONObject js = new JSONObject();js.put(DataColumns.ID, mDataId);js.put(DataColumns.MIME_TYPE, mDataMimeType);js.put(DataColumns.CONTENT, mDataContent);js.put(DataColumns.DATA1, mDataContentData1);js.put(DataColumns.DATA3, mDataContentData3);return js;}/** 功能描述:commit函数用于把当前造作所做的修改保存到数据库* 参数注解: * Made By CuiCan*/public void commit(long noteId, boolean validateVersion, long version) {if (mIsCreate) {if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) {mDiffDataValues.remove(DataColumns.ID);}mDiffDataValues.put(DataColumns.NOTE_ID, noteId);Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues);try {mDataId = Long.valueOf(uri.getPathSegments().get(1));} catch (NumberFormatException e) {Log.e(TAG, "Get note id error :" + e.toString());throw new ActionFailureException("create note failed");}} else {if (mDiffDataValues.size() > 0) {int result = 0;if (!validateVersion) {result = mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null);} else {result = mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues," ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE+ " WHERE " + NoteColumns.VERSION + "=?)", new String[] {String.valueOf(noteId), String.valueOf(version)});}if (result == 0) {Log.w(TAG, "there is no update. maybe user updates note when syncing");}}}mDiffDataValues.clear();mIsCreate = false;}/** 功能描述:获取当前id* 实现过程:* 参数注解: * Made By CuiCan*/public long getId() {return mDataId;}
}

4、SqlNote.java

/** Description:用于支持小米便签最底层的数据库相关操作,和sqldata的关系上是父集关系,即note是data的子父集。* 和SqlData相比,SqlNote算是真正意义上的数据了。*/package net.micode.notes.gtask.data;
/** 功能描述:* 实现过程:* 参数注解: * Made By CuiCan*/public class SqlNote {/** 功能描述:得到类的简写名称存入字符串TAG中* 实现过程:调用getSimpleName ()函数* Made By CuiCan*/private static final String TAG = SqlNote.class.getSimpleName();private static final int INVALID_ID = -99999;// 集合了interface NoteColumns中所有SF常量(17个)public static final String[] PROJECTION_NOTE = new String[] {NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID,NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE,NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE,NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID,NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID,NoteColumns.VERSION};//以下设置17个列的编号public static final int ID_COLUMN = 0;public static final int ALERTED_DATE_COLUMN = 1;public static final int BG_COLOR_ID_COLUMN = 2;public static final int CREATED_DATE_COLUMN = 3;public static final int HAS_ATTACHMENT_COLUMN = 4;public static final int MODIFIED_DATE_COLUMN = 5;public static final int NOTES_COUNT_COLUMN = 6;public static final int PARENT_ID_COLUMN = 7;public static final int SNIPPET_COLUMN = 8;public static final int TYPE_COLUMN = 9;public static final int WIDGET_ID_COLUMN = 10;public static final int WIDGET_TYPE_COLUMN = 11;public static final int SYNC_ID_COLUMN = 12;public static final int LOCAL_MODIFIED_COLUMN = 13;public static final int ORIGIN_PARENT_ID_COLUMN = 14;public static final int GTASK_ID_COLUMN = 15;public static final int VERSION_COLUMN = 16;//一下定义了17个内部的变量,其中12个可以由content中获得,5个需要初始化为0或者newprivate Context mContext;private ContentResolver mContentResolver;private boolean mIsCreate;private long mId;private long mAlertDate;private int mBgColorId;private long mCreatedDate;private int mHasAttachment;private long mModifiedDate;private long mParentId;private String mSnippet;private int mType;private int mWidgetId;private int mWidgetType;private long mOriginParent;private long mVersion;private ContentValues mDiffNoteValues;private ArrayList<SqlData> mDataList;/** 功能描述:构造函数* 参数注解: mIsCreate用于标示构造方式* 参数注解: * Made By CuiCan*///构造函数只有context,对所有的变量进行初始化public SqlNote(Context context) {mContext = context;mContentResolver = context.getContentResolver();mIsCreate = true;mId = INVALID_ID;mAlertDate = 0;mBgColorId = ResourceParser.getDefaultBgId(context);mCreatedDate = System.currentTimeMillis();//调用系统函数获得创建时间mHasAttachment = 0;mModifiedDate = System.currentTimeMillis();//最后一次修改时间初始化为创建时间mParentId = 0;mSnippet = "";mType = Notes.TYPE_NOTE;mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;mWidgetType = Notes.TYPE_WIDGET_INVALIDE;mOriginParent = 0;mVersion = 0;mDiffNoteValues = new ContentValues();mDataList = new ArrayList<SqlData>();}/** 功能描述:构造函数* 参数注解: mIsCreate用于标示构造方式* 参数注解: * Made By CuiCan*///构造函数有context和一个数据库的cursor,多数变量通过cursor指向的一条记录直接进行初始化public SqlNote(Context context, Cursor c) {mContext = context;mContentResolver = context.getContentResolver();mIsCreate = false;loadFromCursor(c);mDataList = new ArrayList<SqlData>();//if (mType == Notes.TYPE_NOTE)loadDataContent();mDiffNoteValues = new ContentValues();}/** 功能描述:构造函数* 参数注解: mIsCreate用于标示构造方式* 参数注解: * Made By CuiCan*/public SqlNote(Context context, long id) {mContext = context;mContentResolver = context.getContentResolver();mIsCreate = false;loadFromCursor(id);mDataList = new ArrayList<SqlData>();if (mType == Notes.TYPE_NOTE)loadDataContent();mDiffNoteValues = new ContentValues();}/** 功能描述:通过id从光标处加载数据* Made By CuiCan*/private void loadFromCursor(long id) {Cursor c = null;try {c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",new String[] {String.valueOf(id)}, null);//通过id获得对应的ContentResolver中的cursorif (c != null) {c.moveToNext();loadFromCursor(c);//然后加载数据进行初始化,这样函数//SqlNote(Context context, long id)与SqlNote(Context context, long id)的实现方式基本相同} else {Log.w(TAG, "loadFromCursor: cursor = null");}} finally {if (c != null)c.close();}}/** 功能描述:通过游标从光标处加载数据* Made By CuiCan*/private void loadFromCursor(Cursor c) {//直接从一条记录中的获得以下变量的初始值mId = c.getLong(ID_COLUMN);mAlertDate = c.getLong(ALERTED_DATE_COLUMN);mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);mCreatedDate = c.getLong(CREATED_DATE_COLUMN);mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);mParentId = c.getLong(PARENT_ID_COLUMN);mSnippet = c.getString(SNIPPET_COLUMN);mType = c.getInt(TYPE_COLUMN);mWidgetId = c.getInt(WIDGET_ID_COLUMN);mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);mVersion = c.getLong(VERSION_COLUMN);}/** 功能描述:通过content机制获取共享数据并加载到数据库当前游标处* 参数注解: * Made By CuiCan*/private void loadDataContent() {Cursor c = null;mDataList.clear();try {c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,"(note_id=?)", new String[] {String.valueOf(mId)}, null);if (c != null) {if (c.getCount() == 0) {Log.w(TAG, "it seems that the note has not data");return;}while (c.moveToNext()) {SqlData data = new SqlData(mContext, c);mDataList.add(data);}} else {Log.w(TAG, "loadDataContent: cursor = null");}} finally {if (c != null)c.close();}}/** 功能描述:设置通过content机制用于共享的数据信息* 参数注解: * Made By CuiCan*/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) {// for folder we can only update the snnipet and typeString snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : "";if (mIsCreate || !mSnippet.equals(snippet)) {mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);}mSnippet = snippet;int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE): Notes.TYPE_NOTE;if (mIsCreate || mType != type) {mDiffNoteValues.put(NoteColumns.TYPE, type);}mType = type;} 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;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;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;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;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;long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();if (mIsCreate || mModifiedDate != modifiedDate) {mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate);}mModifiedDate = modifiedDate;long parentId = note.has(NoteColumns.PARENT_ID) ? note.getLong(NoteColumns.PARENT_ID) : 0;if (mIsCreate || mParentId != parentId) {mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId);}mParentId = parentId;String snippet = note.has(NoteColumns.SNIPPET) ? note.getString(NoteColumns.SNIPPET) : "";if (mIsCreate || !mSnippet.equals(snippet)) {mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);}mSnippet = snippet;int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE): Notes.TYPE_NOTE;if (mIsCreate || mType != type) {mDiffNoteValues.put(NoteColumns.TYPE, type);}mType = type;int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID): AppWidgetManager.INVALID_APPWIDGET_ID;if (mIsCreate || mWidgetId != widgetId) {mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId);}mWidgetId = widgetId;int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;if (mIsCreate || mWidgetType != widgetType) {mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);}mWidgetType = widgetType;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;for (int i = 0; i < dataArray.length(); i++) {JSONObject data = dataArray.getJSONObject(i);SqlData sqlData = null;if (data.has(DataColumns.ID)) {long dataId = data.getLong(DataColumns.ID);for (SqlData temp : mDataList) {if (dataId == temp.getId()) {sqlData = temp;}}}if (sqlData == null) {sqlData = new SqlData(mContext);mDataList.add(sqlData);}sqlData.setContent(data);}}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();return false;}return true;}/** 功能描述:获取content机制提供的数据并加载到note中* 参数注解: * Made By CuiCan*/public JSONObject getContent() {try {JSONObject js = new JSONObject();if (mIsCreate) {Log.e(TAG, "it seems that we haven't created this in database yet");return null;}JSONObject note = new JSONObject();if (mType == Notes.TYPE_NOTE) {//类型为note时note.put(NoteColumns.ID, mId);note.put(NoteColumns.ALERTED_DATE, mAlertDate);note.put(NoteColumns.BG_COLOR_ID, mBgColorId);note.put(NoteColumns.CREATED_DATE, mCreatedDate);note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment);note.put(NoteColumns.MODIFIED_DATE, mModifiedDate);note.put(NoteColumns.PARENT_ID, mParentId);note.put(NoteColumns.SNIPPET, mSnippet);note.put(NoteColumns.TYPE, mType);note.put(NoteColumns.WIDGET_ID, mWidgetId);note.put(NoteColumns.WIDGET_TYPE, mWidgetType);note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent);js.put(GTaskStringUtils.META_HEAD_NOTE, note);JSONArray dataArray = new JSONArray();for (SqlData sqlData : mDataList) {JSONObject data = sqlData.getContent();if (data != null) {dataArray.put(data);}}js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);} 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);js.put(GTaskStringUtils.META_HEAD_NOTE, note);}return js;} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();}return null;}/** 功能描述:给当前id设置父id* 参数注解: * Made By CuiCan*/public void setParentId(long id) {mParentId = id;mDiffNoteValues.put(NoteColumns.PARENT_ID, id);}/** 功能描述:给当前id设置Gtaskid* 参数注解: * Made By CuiCan*/public void setGtaskId(String gid) {mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);}/** 功能描述:给当前id设置同步id* 参数注解: * Made By CuiCan*/public void setSyncId(long syncId) {mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);}/** 功能描述:初始化本地修改,即撤销所有当前修改* 参数注解: * Made By CuiCan*/public void resetLocalModified() {mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);}/** 功能描述:获得当前id* 参数注解: * Made By CuiCan*/public long getId() {return mId;}/** 功能描述:获得当前id的父id* 参数注解: * Made By CuiCan*/public long getParentId() {return mParentId;}/** 功能描述:获取小片段即用于显示的部分便签内容* 参数注解: * Made By CuiCan*/public String getSnippet() {return mSnippet;}/** 功能描述:判断是否为便签类型* 参数注解: * Made By CuiCan*/public boolean isNoteType() {return mType == Notes.TYPE_NOTE;}/** 功能描述:commit函数用于把当前造作所做的修改保存到数据库* 参数注解: * Made By CuiCan*/public void commit(boolean validateVersion) {if (mIsCreate) {if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {mDiffNoteValues.remove(NoteColumns.ID);}Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);try {mId = Long.valueOf(uri.getPathSegments().get(1));} catch (NumberFormatException e) {Log.e(TAG, "Get note id error :" + e.toString());throw new ActionFailureException("create note failed");}if (mId == 0) {throw new IllegalStateException("Create thread id failed");}if (mType == Notes.TYPE_NOTE) {for (SqlData sqlData : mDataList) {//直接使用sqldata中的实现sqlData.commit(mId, false, -1);}}} 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");}if (mDiffNoteValues.size() > 0) {mVersion ++;int result = 0;if (!validateVersion) {//构造字符串result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("+ NoteColumns.ID + "=?)", new String[] {String.valueOf(mId)});} else {result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",new String[] {String.valueOf(mId), String.valueOf(mVersion)});}if (result == 0) {Log.w(TAG, "there is no update. maybe user updates note when syncing");}}if (mType == Notes.TYPE_NOTE) {for (SqlData sqlData : mDataList) {sqlData.commit(mId, validateVersion, mVersion);}}}// refresh local infoloadFromCursor(mId);if (mType == Notes.TYPE_NOTE)loadDataContent();mDiffNoteValues.clear();mIsCreate = false;}
}

5、Task.java

package net.micode.notes.gtask.data;public class Task extends Node {private static final String TAG = Task.class.getSimpleName();private boolean mCompleted;//是否完成private String mNotes;private JSONObject mMetaInfo;//将在实例中存储数据的类型private Task mPriorSibling;//对应的优先兄弟Task的指针(待完善)private TaskList mParent;//所在的任务列表的指针public Task() {super();mCompleted = false;mNotes = null;mPriorSibling = null;//TaskList中当前Task前面的Task的指针mParent = null;//当前Task所在的TaskListmMetaInfo = null;}public JSONObject getCreateAction(int actionId) {JSONObject js = new JSONObject();try {// action_typejs.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);// action_idjs.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);// indexjs.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));// entity_deltaJSONObject entity = new JSONObject();entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,GTaskStringUtils.GTASK_JSON_TYPE_TASK);if (getNotes() != null) {entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());}js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);// parent_idif (mParent!= null) {js.put(GTaskStringUtils.GTASK_JSON_PARENT_ID, mParent.getGid());}// dest_parent_typejs.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,GTaskStringUtils.GTASK_JSON_TYPE_GROUP);// list_idif (mParent!= null) {js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());}// prior_sibling_idif (mPriorSibling != null) {js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("fail to generate task-create jsonobject");}return js;}public JSONObject getUpdateAction(int actionId) {JSONObject js = new JSONObject();try {// action_typejs.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);// action_idjs.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);// idjs.put(GTaskStringUtils.GTASK_JSON_ID, getGid());// entity_deltaJSONObject entity = new JSONObject();entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());if (getNotes() != null) {entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());}entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("fail to generate task-update jsonobject");}return js;}public void setContentByRemoteJSON(JSONObject js) {if (js != null) {try {// idif (js.has(GTaskStringUtils.GTASK_JSON_ID)) {setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));}// last_modifiedif (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));}// nameif (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));}// notesif (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));}// deletedif (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));}// completedif (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("fail to get task content from jsonobject");}}}public void setContentByLocalJSON(JSONObject js) {    //��metadata����ʵʩif (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");}try {JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {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)) {setName(data.getString(DataColumns.CONTENT));break;}}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();}}public JSONObject getLocalJSONFromContent() {String name = getName();try {if (mMetaInfo == null) {// new task created from webif (name == null) {Log.w(TAG, "the note seems to be an empty one");return null;}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;} else {// synced taskJSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);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;}}note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);return mMetaInfo;}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();return null;}}public void setMetaInfo(MetaData metaData) {if (metaData != null && metaData.getNotes() != null) {try {mMetaInfo = new JSONObject(metaData.getNotes());} catch (JSONException e) {Log.w(TAG, e.toString());mMetaInfo = null;}}}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);}if (noteInfo == null) {Log.w(TAG, "it seems that note meta has been deleted");return SYNC_ACTION_UPDATE_REMOTE;}if (!noteInfo.has(NoteColumns.ID)) {Log.w(TAG, "remote note id seems to be deleted");return SYNC_ACTION_UPDATE_LOCAL;}// validate the note id nowif (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 updateif (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {// no update both sidereturn SYNC_ACTION_NONE;} else {// apply remote to localreturn SYNC_ACTION_UPDATE_LOCAL;}} else {// validate gtask idif (!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 onlyreturn SYNC_ACTION_UPDATE_REMOTE;} else {return SYNC_ACTION_UPDATE_CONFLICT;}}} catch (Exception e) {Log.e(TAG, e.toString());e.printStackTrace();}return SYNC_ACTION_ERROR;}public boolean isWorthSaving() {return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)|| (getNotes() != null && getNotes().trim().length() > 0);}public void setCompleted(boolean completed) {this.mCompleted = completed;}public void setNotes(String notes) {this.mNotes = notes;}public void setPriorSibling(Task priorSibling) {this.mPriorSibling = priorSibling;}public void setParent(TaskList parent) {this.mParent = parent;}public boolean getCompleted() {return this.mCompleted;}public String getNotes() {return this.mNotes;}public Task getPriorSibling() {return this.mPriorSibling;}public TaskList getParent() {return this.mParent;}}

6、TaskList.java

package net.micode.notes.gtask.data;public class TaskList extends Node {private static final String TAG = TaskList.class.getSimpleName();//tag标记private int mIndex;//当前TaskList的指针private ArrayList<Task> mChildren;//类中主要的保存数据的单元,用来实现一个以Task为元素的ArrayListpublic TaskList() {super();mChildren = new ArrayList<Task>();mIndex = 1;}/* (non-Javadoc)* @see net.micode.notes.gtask.data.Node#getCreateAction(int)* 生成并返回一个包含了一定数据的JSONObject实体*/public JSONObject getCreateAction(int actionId) {JSONObject js = new JSONObject();try {// action_typejs.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);// action_idjs.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);// indexjs.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex);// entity_deltaJSONObject entity = new JSONObject();//entity实体entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,GTaskStringUtils.GTASK_JSON_TYPE_GROUP);js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("fail to generate tasklist-create jsonobject");}return js;}/* (non-Javadoc)* @see net.micode.notes.gtask.data.Node#getUpdateAction(int)* 生成并返回一个包含了一定数据的JSONObject实体*/public JSONObject getUpdateAction(int actionId) {JSONObject js = new JSONObject();try {// action_typejs.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);// action_idjs.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);// idjs.put(GTaskStringUtils.GTASK_JSON_ID, getGid());// entity_deltaJSONObject 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);} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("fail to generate tasklist-update jsonobject");}return js;}public void setContentByRemoteJSON(JSONObject js) {if (js != null) {try {// idif (js.has(GTaskStringUtils.GTASK_JSON_ID)) {setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));}// last_modifiedif (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));}// nameif (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("fail to get tasklist content from jsonobject");}}}public void setContentByLocalJSON(JSONObject js) {if (js == null || !js.has(GTaskStringUtils.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);elseLog.e(TAG, "invalid system folder");} else {Log.e(TAG, "error type");}} catch (JSONException e) {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);elsefolder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);js.put(GTaskStringUtils.META_HEAD_NOTE, folder);return js;} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();return null;}}public int getSyncAction(Cursor c) {try {if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {// there is no local updateif (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {// no update both sidereturn SYNC_ACTION_NONE;} else {// apply remote to localreturn SYNC_ACTION_UPDATE_LOCAL;}} else {// validate gtask idif (!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 onlyreturn SYNC_ACTION_UPDATE_REMOTE;} else {// for folder conflicts, just apply local modificationreturn SYNC_ACTION_UPDATE_REMOTE;}}} catch (Exception e) {Log.e(TAG, e.toString());e.printStackTrace();}return SYNC_ACTION_ERROR;}/*** @return* 功能:获得TaskList的大小,即mChildren的大小*/public int getChildTaskCount() {return mChildren.size();}/*** @param task* @return 返回值为是否成功添加任务。* 功能:在当前任务表末尾添加新的任务。*/public boolean addChildTask(Task task) {boolean ret = false;if (task != null && !mChildren.contains(task)) {ret = mChildren.add(task);if (ret) {// need to set prior sibling and parenttask.setPriorSibling(mChildren.isEmpty() ? null : mChildren.get(mChildren.size() - 1));task.setParent(this);//注意:每一次ArrayList的变化都要紧跟相关Task中PriorSibling的更改//,接下来几个函数都有相关操作}}return ret;}/*** @param task* @param index* @return* 功能:在当前任务表的指定位置添加新的任务。*/public boolean addChildTask(Task task, int index) {if (index < 0 || index > mChildren.size()) {Log.e(TAG, "add child task: invalid index");return false;}int pos = mChildren.indexOf(task);if (task != null && pos == -1) {mChildren.add(index, task);// update the task listTask preTask = null;Task afterTask = null;if (index != 0)preTask = mChildren.get(index - 1);if (index != mChildren.size() - 1)afterTask = mChildren.get(index + 1);task.setPriorSibling(preTask);if (afterTask != null)afterTask.setPriorSibling(task);}return true;}/*** @param task* @return 返回删除是否成功* 功能:删除TaskList中的一个Task*/public boolean removeChildTask(Task task) {boolean ret = false;int index = mChildren.indexOf(task);if (index != -1) {ret = mChildren.remove(task);if (ret) {// reset prior sibling and parenttask.setPriorSibling(null);task.setParent(null);// update the task listif (index != mChildren.size()) {mChildren.get(index).setPriorSibling(index == 0 ? null : mChildren.get(index - 1));}}}return ret;}/*** @param task* @param index* @return* 功能:将当前TaskList中含有的某个Task移到index位置*/public boolean moveChildTask(Task task, int index) {if (index < 0 || index >= mChildren.size()) {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");return false;}if (pos == index)return true;return (removeChildTask(task) && addChildTask(task, index));//利用已实现好的功能完成当下功能;}/*** @param gid* @return返回寻找结果* 功能:按gid寻找Task*/public Task findChildTaskByGid(String gid) {for (int i = 0; i < mChildren.size(); i++) {Task t = mChildren.get(i);if (t.getGid().equals(gid)) {return t;}}return null;}/*** @param task* @return* 功能:返回指定Task的index*/public int getChildTaskIndex(Task task) {return mChildren.indexOf(task);}/*** @param index* @return* 功能:返回指定index的Task*/public Task getChildTaskByIndex(int index) {if (index < 0 || index >= mChildren.size()) {Log.e(TAG, "getTaskByIndex: invalid index");return null;}return mChildren.get(index);}/*** @param gid* @return* 功能:返回指定gid的Task*/public Task getChilTaskByGid(String gid) {for (Task task : mChildren) {//一种常见的ArrayList的遍历方法(四种,见精读笔记)if (task.getGid().equals(gid))return task;}return null;}public ArrayList<Task> getChildTaskList() {return this.mChildren;}public void setIndex(int index) {this.mIndex = index;}public int getIndex() {return this.mIndex;}
}

二、exception包

1、ActionFailureException.java

/** Description:支持小米便签运行过程中的运行异常处理。*/package net.micode.notes.gtask.exception;public class ActionFailureException extends RuntimeException {private static final long serialVersionUID = 4425249765923293627L;/** serialVersionUID相当于java类的身份证。主要用于版本控制。* serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。* Made By Cuican*/public ActionFailureException() {super();}/** 在JAVA类中使用super来引用父类的成分,用this来引用当前对象.* 如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。* 怎么去引用里面的父类对象呢?使用super来引用* 也就是说,此处super()以及super (paramString)可认为是Exception ()和Exception (paramString)* Made By Cuican*/public ActionFailureException(String paramString) {super(paramString);}public ActionFailureException(String paramString, Throwable paramThrowable) {super(paramString, paramThrowable);}
}

2、NetworkFailureException.java

/** Description:支持小米便签运行过程中的网络异常处理。*/package net.micode.notes.gtask.exception;public class NetworkFailureException extends Exception {private static final long serialVersionUID = 2107610287180234136L;/** serialVersionUID相当于java类的身份证。主要用于版本控制。* serialVersionUID作用是序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。* Made By Cuican*/public NetworkFailureException() {super();}/** 在JAVA类中使用super来引用父类的成分,用this来引用当前对象.* 如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象。* 怎么去引用里面的父类对象呢?使用super来引用* 也就是说,此处super()以及super (paramString)可认为是Exception ()和Exception (paramString)* Made By Cuican*/public NetworkFailureException(String paramString) {super(paramString);}public NetworkFailureException(String paramString, Throwable paramThrowable) {super(paramString, paramThrowable);}
}

三、remote包

1、GTaskASyncTask.java

package net.micode.notes.gtask.remote;/*异步操作类,实现GTask的异步操作过程* 主要方法:* private void showNotification(int tickerId, String content) 向用户提示当前同步的状态,是一个用于交互的方法* protected Integer doInBackground(Void... unused) 此方法在后台线程执行,完成任务的主要工作,通常需要较长的时间* protected void onProgressUpdate(String... progress)  可以使用进度条增加用户体验度。 此方法在主线程执行,用于显示任务执行的进度。* protected void onPostExecute(Integer result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI*/
public class GTaskASyncTask extends AsyncTask<Void, String, Integer> {private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;public interface OnCompleteListener {void onComplete();}private Context mContext;private NotificationManager mNotifiManager;private GTaskManager mTaskManager;private OnCompleteListener mOnCompleteListener;public GTaskASyncTask(Context context, OnCompleteListener listener) {mContext = context;mOnCompleteListener = listener;mNotifiManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);mTaskManager = GTaskManager.getInstance();}public void cancelSync() {mTaskManager.cancelSync();}public void publishProgess(String message) { // 发布进度单位,系统将会调用onProgressUpdate()方法更新这些值publishProgress(new String[] {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;  // 点击清除按钮或点击通知后会自动消失PendingIntent pendingIntent;  //一个描述了想要启动一个Activity、Broadcast或是Service的意图if (tickerId != R.string.ticker_success) {pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,NotesPreferenceActivity.class), 0);  //如果同步不成功,那么从系统取得一个用于启动一个NotesPreferenceActivity的PendingIntent对象} else {pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,NotesListActivity.class), 0); //如果同步成功,那么从系统取得一个用于启动一个NotesListActivity的PendingIntent对象}notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,pendingIntent);mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);//通过NotificationManager对象的notify()方法来执行一个notification的消息}@Overrideprotected Integer doInBackground(Void... unused) {publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity.getSyncAccountName(mContext)));  //利用getString,将把 NotesPreferenceActivity.getSyncAccountName(mContext))的字符串内容传进sync_progress_login中return mTaskManager.sync(mContext, this);    //进行后台同步具体操作}@Overrideprotected void onProgressUpdate(String... progress) {showNotification(R.string.ticker_syncing, progress[0]);if (mContext instanceof GTaskSyncService) {  //instanceof 判断mContext是否是GTaskSyncService的实例((GTaskSyncService) mContext).sendBroadcast(progress[0]);}}@Overrideprotected void onPostExecute(Integer result) {  //用于在执行完后台任务后更新UI,显示结果 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) {showNotification(R.string.ticker_cancel, mContext.getString(R.string.error_sync_cancelled));} //几种不同情况下的结果显示if (mOnCompleteListener != null) {new Thread(new Runnable() {  //这里好像是方法内的一个线程,但是并不太懂什么意思public void run() {   //完成后的操作,使用onComplete()将所有值都重新初始化,相当于完成一次操作mOnCompleteListener.onComplete();    }}).start();}}
}

2、GTaskClient.java

package net.micode.notes.gtask.remote;/** 主要功能:实现GTASK的登录操作,进行GTASK任务的创建,创建任务列表,从网络上获取任务和任务列表的内容* 主要使用类或技术:accountManager JSONObject HttpParams authToken Gid*/
public class GTaskClient {private static final String TAG = GTaskClient.class.getSimpleName();private static final String GTASK_URL = "https://mail.google.com/tasks/"; //这个是指定的URLprivate static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";private static GTaskClient mInstance = null;private DefaultHttpClient mHttpClient;private String mGetUrl;private String mPostUrl;private long mClientVersion;private boolean mLoggedin;private long mLastLoginTime;private int mActionId;private Account mAccount;private JSONArray mUpdateArray;private GTaskClient() {mHttpClient = null;mGetUrl = GTASK_GET_URL;mPostUrl = GTASK_POST_URL;mClientVersion = -1;mLoggedin = false;mLastLoginTime = 0;mActionId = 1;mAccount = null;mUpdateArray = null;}/*用来获取的实例化对象* 使用 getInstance()* 返回mInstance这个实例化对象*/public static synchronized GTaskClient getInstance() {if (mInstance == null) {mInstance = new GTaskClient();}return mInstance;}/*用来实现登录操作的函数,传入的参数是一个Activity* 设置登录操作限制时间,如果超时则需要重新登录* 有两种登录方式,使用用户自己的URL登录或者使用谷歌官方的URL登录* 返回true或者false,即最后是否登陆成功*/public boolean login(Activity activity) {// we suppose that the cookie would expire after 5 minutes// then we need to re-login//判断距离最后一次登录操作是否超过5分钟final long interval = 1000 * 60 * 5;if (mLastLoginTime + interval < System.currentTimeMillis()) {mLoggedin = false;}// need to re-login after account switch  重新登录操作if (mLoggedin&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity.getSyncAccountName(activity))) {mLoggedin = false;}//如果没超过时间,则不需要重新登录if (mLoggedin) {Log.d(TAG, "already logged in");return true;}mLastLoginTime = System.currentTimeMillis();//更新最后登录时间,改为系统当前的时间String authToken = loginGoogleAccount(activity, false);//判断是否登录到谷歌账户if (authToken == null) {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/");int index = mAccount.name.indexOf('@') + 1;String suffix = mAccount.name.substring(index);url.append(suffix + "/");mGetUrl = url.toString() + "ig";  //设置用户对应的getUrlmPostUrl = url.toString() + "r/ig";  //设置用户对应的postUrlif (tryToLoginGtask(activity, authToken)) {mLoggedin = true;}}// try to login with google official url//如果用户账户无法登录,则使用谷歌官方的URI进行登录if (!mLoggedin) {mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL;if (!tryToLoginGtask(activity, authToken)) {return false;}}mLoggedin = true;return true;}/*具体实现登录谷歌账户的方法* 使用令牌机制* 使用AccountManager来管理注册账号* 返回值是账号的令牌*/private String loginGoogleAccount(Activity activity, boolean invalidateToken) {String authToken;  //令牌,是登录操作保证安全性的一个方法AccountManager accountManager = AccountManager.get(activity);//AccountManager这个类给用户提供了集中注册账号的接口Account[] accounts = accountManager.getAccountsByType("com.google");//获取全部以com.google结尾的accountif (accounts.length == 0) {Log.e(TAG, "there is no available google account");return null;}String accountName = NotesPreferenceActivity.getSyncAccountName(activity);Account account = null;//遍历获得的accounts信息,寻找已经记录过的账户信息for (Account a : accounts) {if (a.name.equals(accountName)) {account = a;break;}}if (account != null) {mAccount = account;} else {Log.e(TAG, "unable to get an account with the same name in the settings");return null;}// get the token now//获取选中账号的令牌AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account,"goanna_mobile", null, activity, null, null);try {Bundle authTokenBundle = accountManagerFuture.getResult();authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);//如果是invalidateToken,那么需要调用invalidateAuthToken(String, String)方法废除这个无效tokenif (invalidateToken) {accountManager.invalidateAuthToken("com.google", authToken);loginGoogleAccount(activity, false);}} catch (Exception e) {Log.e(TAG, "get auth token failed");authToken = null;}return authToken;}//尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法private boolean tryToLoginGtask(Activity activity, String authToken) {if (!loginGtask(authToken)) {  // maybe the auth token is out of authTokedate, now let's invalidate the// token and try again//删除过一个无效的authToken,申请一个新的后再次尝试登陆authToken = loginGoogleAccount(activity, true);if (authToken == null) {Log.e(TAG, "login google account failed");return false;}if (!loginGtask(authToken)) {Log.e(TAG, "login gtask failed");return false;}}return true;}//实现登录GTask的具体操作private boolean loginGtask(String authToken) {int timeoutConnection = 10000;int timeoutSocket = 15000;  //socket是一种通信连接实现数据的交换的端口HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间mHttpClient = new DefaultHttpClient(httpParameters);BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookiemHttpClient.setCookieStore(localBasicCookieStore);HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);// login gtasktry {String loginUrl = mGetUrl + "?auth=" + authToken;  //设置登录的urlHttpGet httpGet = new HttpGet(loginUrl);  //通过登录的uri实例化网页上资源的查找HttpResponse response = null;response = mHttpClient.execute(httpGet);// get the cookie now//获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”,则说明有验证成功的有效的cookieList<Cookie> cookies = mHttpClient.getCookieStore().getCookies();boolean hasAuthCookie = false;for (Cookie cookie : cookies) {if (cookie.getName().contains("GTL")) {hasAuthCookie = true;}}if (!hasAuthCookie) {Log.w(TAG, "it seems that there is no auth cookie");}// get the client version//获取client的内容,具体操作是在返回的Content中截取从_setup(开始到)}</script>中间的字符串内容,也就是gtask_url的内容String resString = getResponseContent(response.getEntity());String jsBegin = "_setup(";String jsEnd = ")}</script>";int begin = resString.indexOf(jsBegin);int end = resString.lastIndexOf(jsEnd);String jsString = null;if (begin != -1 && end != -1 && begin < end) {jsString = resString.substring(begin + jsBegin.length(), end);}JSONObject js = new JSONObject(jsString);mClientVersion = js.getLong("v");} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();return false;} catch (Exception e) {// simply catch all exceptionsLog.e(TAG, "httpget gtask_url failed");return false;}return true;}private int getActionId() {return mActionId++;}/*实例化创建一个用于向网络传输数据的对象* 使用HttpPost类* 返回一个httpPost实例化对象,但里面还没有内容*/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;}/*通过URL获取响应后返回的数据,也就是网络上的数据和资源* 使用getContentEncoding()获取网络上的资源和数据* 返回值就是获取到的资源*/private String getResponseContent(HttpEntity entity) throws IOException {String contentEncoding = null;if (entity.getContentEncoding() != null) {//通过URL得到HttpEntity对象,如果不为空则使用getContent()方法创建一个流将数据从网络都过来contentEncoding = entity.getContentEncoding().getValue();Log.d(TAG, "encoding: " + contentEncoding);}InputStream input = entity.getContent();if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//GZIP是使用DEFLATE进行压缩数据的另一个压缩库input = new GZIPInputStream(entity.getContent());} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//DEFLATE是一个无专利的压缩算法,它可以实现无损数据压缩Inflater inflater = new Inflater(true);input = new InflaterInputStream(entity.getContent(), inflater);}try {InputStreamReader isr = new InputStreamReader(input);BufferedReader br = new BufferedReader(isr);//是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了时候,再读入内存,是为了提供读的效率而设计的StringBuilder sb = new StringBuilder();while (true) {String buff = br.readLine();if (buff == null) {return sb.toString();}sb = sb.append(buff);}} finally {input.close();}}/*通过JSON发送请求* 请求的具体内容在json的实例化对象js中然后传入* 利用UrlEncodedFormEntity entity和httpPost.setEntity(entity)方法把js中的内容放置到httpPost中* 执行请求后使用getResponseContent方法得到返回的数据和资源* 将资源再次放入json后返回*/private JSONObject postRequest(JSONObject js) throws NetworkFailureException {if (!mLoggedin) {//未登录Log.e(TAG, "please login first");throw new ActionFailureException("not logged in");}//实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里HttpPost httpPost = createHttpPost();try {LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();list.add(new BasicNameValuePair("r", js.toString()));UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); //UrlEncodedFormEntity()的形式比较单一,是普通的键值对httpPost.setEntity(entity);// execute the post//执行这个请求HttpResponse response = mHttpClient.execute(httpPost);String jsString = getResponseContent(response.getEntity());return new JSONObject(jsString);} catch (ClientProtocolException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new NetworkFailureException("postRequest failed");} catch (IOException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new NetworkFailureException("postRequest failed");} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("unable to convert response content to jsonobject");} catch (Exception e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("error occurs when posting request");}}/*创建单个任务* 传入参数是一个.gtask.data.Task包里Task类的对象* 利用json获取Task里的内容,并且创建相应的jsPost* 利用postRequest得到任务的返回信息* 使用task.setGid设置task的new_ID*/public void createTask(Task task) throws NetworkFailureException {commitUpdate();try {JSONObject jsPost = new JSONObject();JSONArray actionList = new JSONArray();// action_listactionList.put(task.getCreateAction(getActionId()));jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);// client_versionjsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);// postJSONObject jsResponse = postRequest(jsPost);JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_RESULTS).get(0);task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("create task: handing jsonobject failed");}}/** 创建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid*/public void createTaskList(TaskList tasklist) throws NetworkFailureException {commitUpdate();try {JSONObject jsPost = new JSONObject();JSONArray actionList = new JSONArray();// action_listactionList.put(tasklist.getCreateAction(getActionId()));jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);// client versionjsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);// postJSONObject jsResponse = postRequest(jsPost);JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_RESULTS).get(0);tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("create tasklist: handing jsonobject failed");}}/** 同步更新操作* 使用JSONObject进行数据存储,使用jsPost.put,Put的信息包括UpdateArray和ClientVersion* 使用postRequest发送这个jspost,进行处理*/public void commitUpdate() throws NetworkFailureException {if (mUpdateArray != null) {try {JSONObject jsPost = new JSONObject();// action_listjsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);// client_versionjsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);postRequest(jsPost);mUpdateArray = null;} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("commit update: handing jsonobject failed");}}}/** 添加更新的事项* 调用commitUpdate()实现*/public void addUpdateNode(Node node) throws NetworkFailureException {if (node != null) {// too many update items may result in an error// set max to 10 itemsif (mUpdateArray != null && mUpdateArray.length() > 10) {commitUpdate();}if (mUpdateArray == null)mUpdateArray = new JSONArray();mUpdateArray.put(node.getUpdateAction(getActionId()));}}/** 移动task,比如讲task移动到不同的task列表中去* 通过getGid获取task所属列表的gid* 通过JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的* 最后还是通过postRequest进行更新后的发送*/public void moveTask(Task task, TaskList preParent, TaskList curParent)throws NetworkFailureException {commitUpdate();try {JSONObject jsPost = new JSONObject();JSONArray actionList = new JSONArray();JSONObject action = new JSONObject();// action_listaction.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());if (preParent == curParent && task.getPriorSibling() != null) {// put prioring_sibing_id only if moving within the tasklist and// it is not the first one//设置优先级ID,只有当移动是发生在文件中action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());}action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());  //设置移动前所属列表action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());  //设置当前所属列表if (preParent != curParent) {// put the dest_list only if moving between tasklistsaction.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());}actionList.put(action);//最后将ACTION_LIST加入到jsPost中jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);// client_versionjsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);postRequest(jsPost);} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("move task: handing jsonobject failed");}}/** 删除操作节点* 还是利用JSON* 删除过后使用postRequest发送删除后的结果*/public void deleteNode(Node node) throws NetworkFailureException {commitUpdate();try {JSONObject jsPost = new JSONObject();JSONArray actionList = new JSONArray();// action_listnode.setDeleted(true);actionList.put(node.getUpdateAction(getActionId()));  //这里会获取到删除操作的ID,加入到actionLiast中jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);// client_versionjsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);postRequest(jsPost);mUpdateArray = null;} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("delete node: handing jsonobject failed");}}/** 获取任务列表* 首先通过GetURI使用getResponseContent从网上获取数据* 然后筛选出"_setup("到)}</script>的部分,并且从中获取GTASK_JSON_LISTS的内容返回*/public JSONArray getTaskLists() throws NetworkFailureException {if (!mLoggedin) {Log.e(TAG, "please login first");throw new ActionFailureException("not logged in");}try {HttpGet httpGet = new HttpGet(mGetUrl);HttpResponse response = null;response = mHttpClient.execute(httpGet);// get the task list//筛选工作,把筛选出的字符串放入jsStringString resString = getResponseContent(response.getEntity());String jsBegin = "_setup(";String jsEnd = ")}</script>";int begin = resString.indexOf(jsBegin);int end = resString.lastIndexOf(jsEnd);String jsString = null;if (begin != -1 && end != -1 && begin < end) {jsString = resString.substring(begin + jsBegin.length(), end);}JSONObject js = new JSONObject(jsString);//获取GTASK_JSON_LISTSreturn js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);} catch (ClientProtocolException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new NetworkFailureException("gettasklists: httpget failed");} catch (IOException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new NetworkFailureException("gettasklists: httpget failed");} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("get task lists: handing jasonobject failed");}}/** 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务*/public JSONArray getTaskList(String listGid) throws NetworkFailureException {commitUpdate();try {JSONObject jsPost = new JSONObject();JSONArray actionList = new JSONArray();JSONObject action = new JSONObject();// action_listaction.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);    //这里设置为传入的listGidaction.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);actionList.put(action);jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);// client_versionjsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);JSONObject jsResponse = postRequest(jsPost);return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("get task list: handing jsonobject failed");}}public Account getSyncAccount() {return mAccount;}//重置更新的内容public void resetUpdateArray() {mUpdateArray = null;}
}

3、GTaskManager.java

package net.micode.notes.gtask.remote;public class GTaskManager {private static final String TAG = GTaskManager.class.getSimpleName();public static final int STATE_SUCCESS = 0;public static final int STATE_NETWORK_ERROR = 1;public static final int STATE_INTERNAL_ERROR = 2;public static final int STATE_SYNC_IN_PROGRESS = 3;public static final int STATE_SYNC_CANCELLED = 4; private static GTaskManager mInstance = null;private Activity mActivity;private Context mContext;private ContentResolver mContentResolver;private boolean mSyncing;private boolean mCancelled;private HashMap<String, TaskList> mGTaskListHashMap;private HashMap<String, Node> mGTaskHashMap;private HashMap<String, MetaData> mMetaHashMap;private TaskList mMetaList;private HashSet<Long> mLocalDeleteIdMap;   private HashMap<String, Long> mGidToNid;private HashMap<Long, String> mNidToGid;private GTaskManager() {                                   //对象初始化函数mSyncing = false;                                      //正在同步,flase代表未执行mCancelled = false;                                    //全局标识,flase代表可以执行mGTaskListHashMap = new HashMap<String, TaskList>();   //<>代表Java的泛型,就是创建一个用类型作为参数的类。mGTaskHashMap = new HashMap<String, Node>();mMetaHashMap = new HashMap<String, MetaData>();mMetaList = null;mLocalDeleteIdMap = new HashSet<Long>();mGidToNid = new HashMap<String, Long>();    //GoogleID to NodeID??mNidToGid = new HashMap<Long, String>();    //NodeID to GoogleID???通过hashmap散列表建立映射}/*** 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。* 功能:类初始化函数* @author TTS* @return GtaskManger*/public static synchronized GTaskManager getInstance() {    //可能运行在多线程环境下,使用语言级同步--synchronizedif (mInstance == null) {mInstance = new GTaskManager();}return mInstance;}/*** 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。* @author TTS* @param activity*/public synchronized void setActivityContext(Activity activity) {// used for getting auth tokenmActivity = activity;}/*** 核心函数* 功能:实现了本地同步操作和远端同步操作* @author TTS* @param context-----获取上下文* @param asyncTask-------用于同步的异步操作类* @return int*/public int sync(Context context, GTaskASyncTask asyncTask) {           //核心函数if (mSyncing) {Log.d(TAG, "Sync is in progress");                       //创建日志文件(调试信息),debugreturn STATE_SYNC_IN_PROGRESS;}mContext = context;mContentResolver = mContext.getContentResolver();mSyncing = true;mCancelled = false;mGTaskListHashMap.clear();mGTaskHashMap.clear();mMetaHashMap.clear();mLocalDeleteIdMap.clear();mGidToNid.clear();mNidToGid.clear();try {GTaskClient client = GTaskClient.getInstance();    //getInstance即为创建一个实例,client--客户机client.resetUpdateArray();     //JSONArray类型,reset即置为NULL// login google taskif (!mCancelled) {if (!client.login(mActivity)) {throw new NetworkFailureException("login google task failed");}}// get the task list from googleasyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list));initGTaskList();                                 //获取Google上的JSONtasklist转为本地TaskList// do content sync workasyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing));syncContent();} catch (NetworkFailureException e) {                       //分为两种异常,此类异常为网络异常Log.e(TAG, e.toString());                             //创建日志文件(调试信息),errorreturn STATE_NETWORK_ERROR;} catch (ActionFailureException e) {                        //此类异常为操作异常Log.e(TAG, e.toString());return STATE_INTERNAL_ERROR;} catch (Exception e) {Log.e(TAG, e.toString());e.printStackTrace();return STATE_INTERNAL_ERROR;} finally {mGTaskListHashMap.clear();mGTaskHashMap.clear();mMetaHashMap.clear();mLocalDeleteIdMap.clear();mGidToNid.clear();mNidToGid.clear();mSyncing = false;}return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;}/***功能:初始化GtaskList,获取Google上的JSONtasklist转为本地TaskList。*获得的数据存储在mMetaList,mGTaskListHashMap,mGTaskHashMap*@author TTS*@exception NetworkFailureException*@return void*/private void initGTaskList() throws NetworkFailureException {if (mCancelled)return;GTaskClient client = GTaskClient.getInstance();    //getInstance即为创建一个实例,client应指远端客户机try {//Json对象是Name Value对(即子元素)的无序集合,相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象,提供操纵Json对象的各种方法。//其格式为{"key1":value1,"key2",value2....};key 必须是字符串。//因为ajax请求不刷新页面,但配合js可以实现局部刷新,因此json常常被用来作为异步请求的返回对象使用。JSONArray jsTaskLists = client.getTaskLists();     //原注释为get task list------lists???// init meta list firstmMetaList = null;                                       //TaskList类型for (int i = 0; i < jsTaskLists.length(); i++) {JSONObject object = jsTaskLists.getJSONObject(i);  //JSONObject与JSONArray一个为对象,一个为数组。此处取出单个JASONObjectString gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {mMetaList = new TaskList();                    //MetaList意为元表,Tasklist类型,此处为初始化mMetaList.setContentByRemoteJSON(object);      //将JSON中部分数据复制到自己定义的对象中相对应的数据:name->mname...// load meta dataJSONArray jsMetas = client.getTaskList(gid);   //原注释为get action_list------list???for (int j = 0; j < jsMetas.length(); j++) {object = (JSONObject) jsMetas.getJSONObject(j);MetaData metaData = new MetaData();            //继承自NodemetaData.setContentByRemoteJSON(object);if (metaData.isWorthSaving()) {                             //if not worth to save,metadata将不加入mMetaListmMetaList.addChildTask(metaData);if (metaData.getGid() != null) {mMetaHashMap.put(metaData.getRelatedGid(), metaData);}}}}}// create meta list if not existedif (mMetaList == null) {mMetaList = new TaskList();mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX+ GTaskStringUtils.FOLDER_META);GTaskClient.getInstance().createTaskList(mMetaList);}// init task listfor (int i = 0; i < jsTaskLists.length(); i++) {JSONObject object = jsTaskLists.getJSONObject(i);String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);  //通过getString函数传入本地某个标志数据的名称,获取其在远端的名称。String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)&& !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX+ GTaskStringUtils.FOLDER_META)) {TaskList tasklist = new TaskList();     //继承自Nodetasklist.setContentByRemoteJSON(object);mGTaskListHashMap.put(gid, tasklist);       mGTaskHashMap.put(gid, tasklist);          //为什么加两遍???// load tasksJSONArray jsTasks = client.getTaskList(gid);for (int j = 0; j < jsTasks.length(); j++) {object = (JSONObject) jsTasks.getJSONObject(j);gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);Task task = new Task();task.setContentByRemoteJSON(object);if (task.isWorthSaving()) {task.setMetaInfo(mMetaHashMap.get(gid));tasklist.addChildTask(task);mGTaskHashMap.put(gid, task);}}}}} catch (JSONException e) {Log.e(TAG, e.toString());e.printStackTrace();throw new ActionFailureException("initGTaskList: handing JSONObject failed");}}/*** 功能:本地内容同步操作* @throws NetworkFailureException* @return 无返回值*/private void syncContent() throws NetworkFailureException {    //本地内容同步操作int syncType;Cursor c = null;                                           //数据库指针String gid;                                                //GoogleID??Node node;                                                 //Node包含Sync_Action的不同类型mLocalDeleteIdMap.clear();                                 //HashSet<Long>类型if (mCancelled) {return;}// for local deleted notetry {c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,"(type<>? AND parent_id=?)", new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}, null);if (c != null) {while (c.moveToNext()) {gid = c.getString(SqlNote.GTASK_ID_COLUMN);node = mGTaskHashMap.get(gid);if (node != null) {mGTaskHashMap.remove(gid);doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c);}mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));}} else {Log.w(TAG, "failed to query trash folder");}} finally {if (c != null) {c.close();c = null;}}// sync folder firstsyncFolder();// for note existing in databasetry {c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,"(type=? AND parent_id<>?)", new String[] {String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER)}, NoteColumns.TYPE + " DESC");if (c != null) {while (c.moveToNext()) {gid = c.getString(SqlNote.GTASK_ID_COLUMN);node = mGTaskHashMap.get(gid);if (node != null) {mGTaskHashMap.remove(gid);mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));   //通过hashmap建立联系mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);   //通过hashmap建立联系syncType = node.getSyncAction(c);} else {if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {// local addsyncType = Node.SYNC_ACTION_ADD_REMOTE;} else {// remote deletesyncType = Node.SYNC_ACTION_DEL_LOCAL;}}doContentSync(syncType, node, c);}} else {Log.w(TAG, "failed to query existing note in database");}} finally {if (c != null) {c.close();c = null;}}// go through remaining itemsIterator<Map.Entry<String, Node>> iter = mGTaskHashMap.entrySet().iterator();   //Iterator迭代器while (iter.hasNext()) {Map.Entry<String, Node> entry = iter.next();node = entry.getValue();doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);}// mCancelled can be set by another thread, so we neet to check one by    //thread----线程// one// clear local delete tableif (!mCancelled) {if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) {throw new ActionFailureException("failed to batch-delete local deleted notes");}}// refresh local sync idif (!mCancelled) {GTaskClient.getInstance().commitUpdate();refreshLocalSyncId();}}/*** 功能:* @author TTS* @throws NetworkFailureException*/private void syncFolder() throws NetworkFailureException {Cursor c = null;String gid;Node node;int syncType;if (mCancelled) {return;}// for root foldertry {c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null);if (c != null) {c.moveToNext();gid = c.getString(SqlNote.GTASK_ID_COLUMN);node = mGTaskHashMap.get(gid);if (node != null) {mGTaskHashMap.remove(gid);mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER);mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid);// for system folder, only update remote name if necessaryif (!node.getName().equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT))doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);} else {doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);}} else {Log.w(TAG, "failed to query root folder");}} finally {if (c != null) {c.close();c = null;}}// for call-note foldertry {c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)",new String[] {String.valueOf(Notes.ID_CALL_RECORD_FOLDER)}, null);if (c != null) {if (c.moveToNext()) {gid = c.getString(SqlNote.GTASK_ID_COLUMN);node = mGTaskHashMap.get(gid);if (node != null) {mGTaskHashMap.remove(gid);mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER);mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid);// for system folder, only update remote name if// necessaryif (!node.getName().equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX+ GTaskStringUtils.FOLDER_CALL_NOTE))doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);} else {doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);}}} else {Log.w(TAG, "failed to query call note folder");}} finally {if (c != null) {c.close();c = null;}}// for local existing folderstry {c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,"(type=? AND parent_id<>?)", new String[] {String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, NoteColumns.TYPE + " DESC");if (c != null) {while (c.moveToNext()) {gid = c.getString(SqlNote.GTASK_ID_COLUMN);node = mGTaskHashMap.get(gid);if (node != null) {mGTaskHashMap.remove(gid);mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);syncType = node.getSyncAction(c);} else {if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {// local addsyncType = Node.SYNC_ACTION_ADD_REMOTE;} else {// remote deletesyncType = Node.SYNC_ACTION_DEL_LOCAL;}}doContentSync(syncType, node, c);}} else {Log.w(TAG, "failed to query existing folder");}} finally {if (c != null) {c.close();c = null;}}// for remote add foldersIterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();while (iter.hasNext()) {Map.Entry<String, TaskList> entry = iter.next();gid = entry.getKey();node = entry.getValue();if (mGTaskHashMap.containsKey(gid)) {mGTaskHashMap.remove(gid);doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);}}if (!mCancelled)GTaskClient.getInstance().commitUpdate();}/*** 功能:syncType分类,addLocalNode,addRemoteNode,deleteNode,updateLocalNode,updateRemoteNode* @author TTS* @param syncType* @param node* @param c* @throws NetworkFailureException*/private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException {if (mCancelled) {return;}MetaData meta;switch (syncType) {case Node.SYNC_ACTION_ADD_LOCAL:addLocalNode(node);break;case Node.SYNC_ACTION_ADD_REMOTE:addRemoteNode(node, c);break;case Node.SYNC_ACTION_DEL_LOCAL:meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN));if (meta != null) {GTaskClient.getInstance().deleteNode(meta);}mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));break;case Node.SYNC_ACTION_DEL_REMOTE:meta = mMetaHashMap.get(node.getGid());if (meta != null) {GTaskClient.getInstance().deleteNode(meta);}GTaskClient.getInstance().deleteNode(node);break;case Node.SYNC_ACTION_UPDATE_LOCAL:updateLocalNode(node, c);break;case Node.SYNC_ACTION_UPDATE_REMOTE:updateRemoteNode(node, c);break;case Node.SYNC_ACTION_UPDATE_CONFLICT:// merging both modifications maybe a good idea// right now just use local update simplyupdateRemoteNode(node, c);break;case Node.SYNC_ACTION_NONE:break;case Node.SYNC_ACTION_ERROR:default:throw new ActionFailureException("unkown sync action type");}}/*** 功能:本地增加Node* @author TTS* @param node* @throws NetworkFailureException*/private void addLocalNode(Node node) throws NetworkFailureException {if (mCancelled) {return;}SqlNote sqlNote;if (node instanceof TaskList) {if (node.getName().equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) {sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER);} else if (node.getName().equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) {sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER);} else {sqlNote = new SqlNote(mContext);sqlNote.setContent(node.getLocalJSONFromContent());sqlNote.setParentId(Notes.ID_ROOT_FOLDER);}} else {sqlNote = new SqlNote(mContext);JSONObject js = node.getLocalJSONFromContent();try {if (js.has(GTaskStringUtils.META_HEAD_NOTE)) {JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);if (note.has(NoteColumns.ID)) {long id = note.getLong(NoteColumns.ID);if (DataUtils.existInNoteDatabase(mContentResolver, id)) {// the id is not available, have to create a new onenote.remove(NoteColumns.ID);}}}if (js.has(GTaskStringUtils.META_HEAD_DATA)) {JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);for (int i = 0; i < dataArray.length(); i++) {JSONObject data = dataArray.getJSONObject(i);if (data.has(DataColumns.ID)) {long dataId = data.getLong(DataColumns.ID);if (DataUtils.existInDataDatabase(mContentResolver, dataId)) {// the data id is not available, have to create// a new onedata.remove(DataColumns.ID);}}}}} catch (JSONException e) {Log.w(TAG, e.toString());e.printStackTrace();}sqlNote.setContent(js);Long parentId = mGidToNid.get(((Task) node).getParent().getGid());if (parentId == null) {Log.e(TAG, "cannot find task's parent id locally");throw new ActionFailureException("cannot add local node");}sqlNote.setParentId(parentId.longValue());}// create the local nodesqlNote.setGtaskId(node.getGid());sqlNote.commit(false);// update gid-nid mappingmGidToNid.put(node.getGid(), sqlNote.getId());mNidToGid.put(sqlNote.getId(), node.getGid());// update metaupdateRemoteMeta(node.getGid(), sqlNote);}/*** 功能:update本地node* @author TTS* @param node* ----同步操作的基础数据类型* @param c* ----Cursor* @throws NetworkFailureException*/private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException {if (mCancelled) {return;}SqlNote sqlNote;// update the note locallysqlNote = new SqlNote(mContext, c);sqlNote.setContent(node.getLocalJSONFromContent());Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()): new Long(Notes.ID_ROOT_FOLDER);if (parentId == null) {Log.e(TAG, "cannot find task's parent id locally");throw new ActionFailureException("cannot update local node");}sqlNote.setParentId(parentId.longValue());sqlNote.commit(true);// update meta infoupdateRemoteMeta(node.getGid(), sqlNote);}/*** 功能:远程增加Node* 需要updateRemoteMeta* @author TTS* @param node* ----同步操作的基础数据类型* @param c* --Cursor* @throws NetworkFailureException*/private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException {if (mCancelled) {return;}SqlNote sqlNote = new SqlNote(mContext, c);     //从本地mContext中获取内容Node n;// update remotelyif (sqlNote.isNoteType()) {Task task = new Task();task.setContentByLocalJSON(sqlNote.getContent());String parentGid = mNidToGid.get(sqlNote.getParentId());if (parentGid == null) {Log.e(TAG, "cannot find task's parent tasklist");           //调试信息throw new ActionFailureException("cannot add remote task");}mGTaskListHashMap.get(parentGid).addChildTask(task);            //在本地生成的GTaskList中增加子结点//登录远程服务器,创建TaskGTaskClient.getInstance().createTask(task); n = (Node) task;// add metaupdateRemoteMeta(task.getGid(), sqlNote);} else {TaskList tasklist = null;// we need to skip folder if it has already existedString folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX;if (sqlNote.getId() == Notes.ID_ROOT_FOLDER)folderName += GTaskStringUtils.FOLDER_DEFAULT;else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER)folderName += GTaskStringUtils.FOLDER_CALL_NOTE;elsefolderName += sqlNote.getSnippet();//iterator迭代器,通过统一的接口迭代所有的map元素Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) {Map.Entry<String, TaskList> entry = iter.next();String gid = entry.getKey();TaskList list = entry.getValue();if (list.getName().equals(folderName)) {tasklist = list;if (mGTaskHashMap.containsKey(gid)) {mGTaskHashMap.remove(gid);}break;}}// no match we can add nowif (tasklist == null) {tasklist = new TaskList();tasklist.setContentByLocalJSON(sqlNote.getContent());GTaskClient.getInstance().createTaskList(tasklist);mGTaskListHashMap.put(tasklist.getGid(), tasklist);}n = (Node) tasklist;}// update local notesqlNote.setGtaskId(n.getGid());sqlNote.commit(false);sqlNote.resetLocalModified();sqlNote.commit(true);// gid-id mapping                                             //创建id间的映射mGidToNid.put(n.getGid(), sqlNote.getId());mNidToGid.put(sqlNote.getId(), n.getGid());}/*** 功能:更新远端的Node,包含meta更新(updateRemoteMeta)* @author TTS* @param node* ----同步操作的基础数据类型* @param c*  --Cursor* @throws NetworkFailureException*/private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException {if (mCancelled) {return;}SqlNote sqlNote = new SqlNote(mContext, c);// update remotelynode.setContentByLocalJSON(sqlNote.getContent());GTaskClient.getInstance().addUpdateNode(node);                                //GTaskClient用途为从本地登陆远端服务器 // update metaupdateRemoteMeta(node.getGid(), sqlNote);// move task if necessaryif (sqlNote.isNoteType()) {Task task = (Task) node;TaskList preParentList = task.getParent(); //preParentList为通过node获取的父节点列表String curParentGid = mNidToGid.get(sqlNote.getParentId());//curParentGid为通过光标在数据库中找到sqlNote的mParentId,再通过mNidToGid由long类型转为String类型的Gidif (curParentGid == null) {Log.e(TAG, "cannot find task's parent tasklist");throw new ActionFailureException("cannot update remote task");}TaskList curParentList = mGTaskListHashMap.get(curParentGid);//通过HashMap找到对应Gid的TaskListif (preParentList != curParentList) {                                          //?????????????preParentList.removeChildTask(task);curParentList.addChildTask(task);GTaskClient.getInstance().moveTask(task, preParentList, curParentList);}}// clear local modified flagsqlNote.resetLocalModified();//commit到本地数据库sqlNote.commit(true); }/*** 功能:升级远程meta。  meta---元数据----计算机文件系统管理数据---管理数据的数据。* @author TTS* @param gid* ---GoogleID为String类型* @param sqlNote* ---同步前的数据库操作,故使用类SqlNote* @throws NetworkFailureException*/private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException {if (sqlNote != null && sqlNote.isNoteType()) {MetaData metaData = mMetaHashMap.get(gid);if (metaData != null) {metaData.setMeta(gid, sqlNote.getContent());GTaskClient.getInstance().addUpdateNode(metaData);} else {metaData = new MetaData();metaData.setMeta(gid, sqlNote.getContent());mMetaList.addChildTask(metaData);mMetaHashMap.put(gid, metaData);GTaskClient.getInstance().createTask(metaData);}}}/*** 功能:刷新本地,给sync的ID对应上最后更改过的对象* @author TTS* @return void* @throws NetworkFailureException*/private void refreshLocalSyncId() throws NetworkFailureException {if (mCancelled) {return;}// get the latest gtask list                                               //获取最近的(最晚的)gtask listmGTaskHashMap.clear();mGTaskListHashMap.clear();mMetaHashMap.clear();initGTaskList();Cursor c = null;try {c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,"(type<>? AND parent_id<>?)", new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}, NoteColumns.TYPE + " DESC");                                                 //query语句:五个参数,NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uriif (c != null) {while (c.moveToNext()) {String gid = c.getString(SqlNote.GTASK_ID_COLUMN);Node node = mGTaskHashMap.get(gid);if (node != null) {mGTaskHashMap.remove(gid);ContentValues values = new ContentValues();                     //在ContentValues中创建键值对。准备通过contentResolver写入数据values.put(NoteColumns.SYNC_ID, node.getLastModified());mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,   //进行批量更改,选择参数为NULL,应该可以用insert替换,参数分别为表名和需要更新的value对象。c.getLong(SqlNote.ID_COLUMN)), values, null, null);} else {Log.e(TAG, "something is missed");throw new ActionFailureException("some local items don't have gid after sync");}}} else {Log.w(TAG, "failed to query local note to refresh sync id");}} finally {if (c != null) {c.close();c = null;}}}/*** 功能:获取同步账号,mAccount.name* @author TTS* @return String*/public String getSyncAccount() {return GTaskClient.getInstance().getSyncAccount().name;}/*** 功能:取消同步,置mCancelled为true* @author TTS*/public void cancelSync() {mCancelled = true;}
}

4、GTaskSyncService.java

package net.micode.notes.gtask.remote;/** Service是在一段不定的时间运行在后台,不和用户交互的应用组件* 主要方法:* private void startSync()  启动一个同步工作* private void cancelSync() 取消同步* public void onCreate()* public int onStartCommand(Intent intent, int flags, int startId)  service生命周期的组成部分,相当于重启service(比如在被暂停之后),而不是创建一个新的service* public void onLowMemory()  在没有内存的情况下如果存在service则结束掉这的service* public IBinder onBind()* public void sendBroadcast(String msg)   发送同步的相关通知* public static void startSync(Activity activity)* public static void cancelSync(Context context) * public static boolean isSyncing()  判读是否在进行同步* public static String getProgressString()  获取当前进度的信息*/public class GTaskSyncService extends Service {public final static String ACTION_STRING_NAME = "sync_action_type";public final static int ACTION_START_SYNC = 0;public final static int ACTION_CANCEL_SYNC = 1;public final static int ACTION_INVALID = 2;public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service";public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing";public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg";private static GTaskASyncTask mSyncTask = null;private static String mSyncProgress = "";//开始一个同步的工作private void startSync() {if (mSyncTask == null) {mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {public void onComplete() {mSyncTask = null;sendBroadcast("");stopSelf();  }});sendBroadcast("");mSyncTask.execute(); //这个函数让任务是以单线程队列方式或线程池队列方式运行}}private void cancelSync() {if (mSyncTask != null) {mSyncTask.cancelSync();}}@Overridepublic void onCreate() {  //初始化一个servicemSyncTask = null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Bundle bundle = intent.getExtras();if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {//两种情况,开始同步或者取消同步case ACTION_START_SYNC:startSync();break;case ACTION_CANCEL_SYNC:cancelSync();break;default:break;}return START_STICKY; //等待新的intent来是这个service继续运行}return super.onStartCommand(intent, flags, startId);}@Overridepublic void onLowMemory() {if (mSyncTask != null) {mSyncTask.cancelSync();}}public IBinder onBind(Intent intent) {  //不知道干吗用的return null;}public void sendBroadcast(String msg) {mSyncProgress = msg;Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);  //创建一个新的Intentintent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); //附加INTENT中的相应参数的值intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg);sendBroadcast(intent);   //发送这个通知}public static void startSync(Activity activity) {//执行一个service,service的内容里的同步动作就是开始同步GTaskManager.getInstance().setActivityContext(activity);Intent intent = new Intent(activity, GTaskSyncService.class);intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC);activity.startService(intent);}public static void cancelSync(Context context) {//执行一个service,service的内容里的同步动作就是取消同步Intent intent = new Intent(context, GTaskSyncService.class);intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);context.startService(intent);}public static boolean isSyncing() {return mSyncTask != null;}public static String getProgressString() {return mSyncProgress;}
}

小米便签源码分析——gtask包相关推荐

  1. 2022 iapp 云便签源码

    二次开发云便签加强版iapp源码,WPS云便签一款可以对接iapp源码的软件,实现"添加便签,查询便签,删除便签,修改便签"四个功能,不管软件内,软件外.内部直接自己改,外部可以依 ...

  2. php日常工作便签源码,php便签

    取回选项 访问方式 类型 说明 ObsClient::RestoreTierExpedited string 快速取回,取回耗时1~5分钟. ObsClient::RestoreTierStandar ...

  3. tcpdump源码分析——抓包原理

    本篇我们从总体看下tcpdump工具的抓包原理,通过学习了解并掌握其实现的机制,为后续进一步底层操作做准备. 1.1.1.1  如何实现 先来看看包传递过来的流程,如下图.包从网卡到内存,到内核态,最 ...

  4. 小米便签从0到1维护教程

    小米便签开源社区版从0到1维护教程 1.前置条件-------软件的安装: 开发工具:Android studio 下载Android studio 汉化教程 安装请自行解决 SDK版本以及相关文件 ...

  5. 微信支付生成签名和验签SDK源码分析

    目录 一.签名分析 1.1 流程分析 1.构造签名串 2.计算签名值 3.设置请求头 二.源码级别分析 二.获取平台证书分析 三.验签分析 3.1 验签使用场景: 3.2 验证流程: 1.获取微信平台 ...

  6. client-go之listers包源码分析

    listers包源码分析 listers包 admissionregistration包 listers包 从cache.Indexer中获取原生k8s的对象/列表 admissionregistra ...

  7. 65、Spark Streaming:数据接收原理剖析与源码分析

    一.数据接收原理 二.源码分析 入口包org.apache.spark.streaming.receiver下ReceiverSupervisorImpl类的onStart()方法 ###overri ...

  8. heritrix源码分析(未完成。太长了!!)

    Heritrix源码分析(一) 包介绍  序号  包名                   说明 1 org.apache.commons.httpclient      封装了apache的http ...

  9. SpringBoot Jar包构建源码分析

    我们知道,SpringBoot仅凭一个Jar包就能将我们构建的整个工程跑起来,如果你也想知道这个能跑起来的jar内部结构是如何构建出来的,请耐心读完本篇,本篇内容可能有点多,但包你有收获.如果读完没有 ...

  10. 【Android】条形码/二维码扫描——ZXing源码分析及相关jar包导入

    转载自:http://blog.csdn.net/u010574567/article/details/51916604 *********************1.源码分析************ ...

最新文章

  1. linux-glibc内存管理小结2(内存相关系统调用的实现)
  2. Ubuntu14.04 64bit 编译安装nginx1.7+php5.4+mysql5.6
  3. 为什么要使用 Service Mesh?
  4. Flex布局及其应用
  5. 使用android frame动画定义自己的ProgressBar
  6. Linux中变量#,@,0,1,2,*,$$,$?的含义
  7. linux 强制结束p进程的命令,Linux常用命令之性能命令
  8. android 阻塞式函数,Android之PC浏览器上传表单格式大文件到手机客户端read函数阻塞问题...
  9. 我的地盘我做主—玩转Python函数和变量
  10. 配置 Ubuntu 字符界面启动
  11. 跟对人,走对路,做对事!
  12. java检查文件的编码格式
  13. Oracle ~ 索引种类、创建及管理
  14. android 音频子系统框架(一)
  15. 32位x86处理器编程架构
  16. 云南省首家喜来登和德尔塔品牌酒店落地春城昆明
  17. Android基础之RemoteViews
  18. MTK5G平台 MT6885/MT6853/MT6873如何配置长按关机
  19. python江红余青松_python上机实践重点代码江红余青松版
  20. [PM2] Spawning PM2 daemon with pm2_home=/root/.pm2 错误

热门文章

  1. 【rmzt:suika动漫美女可爱主题】
  2. Linux:CentOS 7 解压 7zip 压缩的文件
  3. 西门子触摸屏函数翻译_触摸屏的中英文切换怎么做?
  4. 漂白android软件,原本图片漂白软件
  5. CodeBlock的安装、配置和运行
  6. 最新大数据案例分享:2019微信数据报告(图集)
  7. 车牌号识别依托OCR文字识别核心
  8. 安卓手机有坏点测试软件,手机屏幕坏点怎么检测
  9. 给定一个净值序列,计算年化收益、最大回撤、夏普比率
  10. 群接龙,JK上报一键化手机脚本autojs