From fc061033345ced31ca3f551cd72bd85a564d463c Mon Sep 17 00:00:00 2001 From: KasumizawaMiyu Date: Fri, 31 Mar 2023 17:04:16 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A6=88=E5=A6=88=E7=94=9F=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: KasumizawaMiyu --- src/data/Contact.java | 36 +++-- src/data/NotesDatabaseHelper.java | 108 ++++++------- src/data/NotesProvider.java | 147 +++++++++--------- src/gtask/data/MetaData.java | 20 +-- src/gtask/data/Node.java | 23 +-- src/gtask/data/SqlData.java | 27 ++-- src/gtask/data/SqlNote.java | 37 +++-- src/gtask/data/Task.java | 24 +-- src/gtask/data/TaskList.java | 26 ++-- .../exception/ActionFailureException.java | 4 +- .../exception/NetworkFailureException.java | 3 + src/gtask/remote/GTaskASyncTask.java | 38 ++++- src/gtask/remote/GTaskClient.java | 93 ++++++++--- src/gtask/remote/GTaskManager.java | 81 +++++++--- src/gtask/remote/GTaskSyncService.java | 32 +++- 15 files changed, 425 insertions(+), 274 deletions(-) diff --git a/src/data/Contact.java b/src/data/Contact.java index 00b51e9..94b6b45 100644 --- a/src/data/Contact.java +++ b/src/data/Contact.java @@ -25,6 +25,7 @@ import android.util.Log; import java.util.HashMap; +<<<<<<< HEAD <<<<<<< HEAD:app/src/main/java/net/micode/notes/data/Contact.java public class Contact { private static HashMap sContactCache;//建立哈希表 @@ -34,46 +35,51 @@ public class Contact {//连接类 private static HashMap sContactCache;//建立哈希表 private static final String TAG = "Contact";//设置TAG的值为'连接' >>>>>>> 0444a65d4e44c509f57ad301a5a2b59200d62177:src/data/Contact.java +======= +public class Contact { //连接类 + private static HashMap sContactCache; //定义连接哈希表 + private static final String TAG = "Contact"; //设置TAG的值为'连接' +>>>>>>> b12b9a8449498593360310c554053628b31cc8c9 private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + " AND " + Data.RAW_CONTACT_ID + " IN " + "(SELECT raw_contact_id " + " FROM phone_lookup" - + " WHERE min_match = '+')"; + + " WHERE min_match = '+')"; //SQL语句 - public static String getContact(Context context, String phoneNumber) { + public static String getContact(Context context, String phoneNumber) { //获取连接 if(sContactCache == null) { - sContactCache = new HashMap(); + sContactCache = new HashMap(); //连接哈希表为空时创建连接哈希表 } if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); + return sContactCache.get(phoneNumber); //连接哈希表存在电话号码时获取值 } String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); //将电话号码进行函数处理并代替'+'符号 + Cursor cursor = context.getContentResolver().query( //用于查询的结果集 + Data.CONTENT_URI, //通话记录uri new String [] { Phone.DISPLAY_NAME }, selection, new String[] { phoneNumber }, - null); + null); //查询指定号码相关联系人名字 if (cursor != null && cursor.moveToFirst()) { - try { - String name = cursor.getString(0); - sContactCache.put(phoneNumber, name); + try { //有结果时 + String name = cursor.getString(0); //获取联系人名字 + sContactCache.put(phoneNumber, name); //缓存电话号码与联系人名字 return name; } catch (IndexOutOfBoundsException e) { - Log.e(TAG, " Cursor get string error " + e.toString()); + Log.e(TAG, " Cursor get string error " + e.toString()); //日志记录信息 return null; } finally { - cursor.close(); + cursor.close(); //关闭结果集 } } else { - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; + Log.d(TAG, "No contact matched with number:" + phoneNumber); //日志记录信息 + return null; //没找到,返回NULL } } } diff --git a/src/data/NotesDatabaseHelper.java b/src/data/NotesDatabaseHelper.java index ffe5d57..57805ab 100644 --- a/src/data/NotesDatabaseHelper.java +++ b/src/data/NotesDatabaseHelper.java @@ -26,23 +26,23 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; + //引入Notes中接口 +public class NotesDatabaseHelper extends SQLiteOpenHelper { //该类为便签SQL表的定义以及操作,便于进行文件夹与便签的各种操作,例如添加或删除的行为 + private static final String DB_NAME = "note.db"; //数据库名称 -public class NotesDatabaseHelper extends SQLiteOpenHelper { - private static final String DB_NAME = "note.db"; + private static final int DB_VERSION = 4; //数据库版本 - private static final int DB_VERSION = 4; + public interface TABLE { //定义一个数据库表接口 + public static final String NOTE = "note"; //便签名 - public interface TABLE { - public static final String NOTE = "note"; - - public static final String DATA = "data"; + public static final String DATA = "data"; //便签数据 } - private static final String TAG = "NotesDatabaseHelper"; + private static final String TAG = "NotesDatabaseHelper"; //日志类型 - private static NotesDatabaseHelper mInstance; + private static NotesDatabaseHelper mInstance; //创建NotesDatabaseHelper类对象 - private static final String CREATE_NOTE_TABLE_SQL = + private static final String CREATE_NOTE_TABLE_SQL = //SQL语句,创建便签表,包含ID、最后修改日期、背景颜色、便签数等在Notes类中的内容 "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + @@ -63,7 +63,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")"; - private static final String CREATE_DATA_TABLE_SQL = + private static final String CREATE_DATA_TABLE_SQL = //创建数据表的SQL语句 "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + DataColumns.MIME_TYPE + " TEXT NOT NULL," + @@ -80,7 +80,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + - TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; //创建查询操作表索引,用于查找 /** * Increase folder's note count when move note to the folder @@ -92,7 +92,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; + " END"; //创建触发器,方便进行操作,当移动便签时统计新的父文件夹内便签数量 /** * Decrease folder's note count when move note from folder @@ -105,7 +105,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + - " END"; + " END"; //与上一个方法作用相反,统计旧的父文件夹便签数量 /** * Increase folder's note count when insert new note to the folder @@ -117,7 +117,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; + " END"; //创建便签时增加统计数量 /** * Decrease folder's note count when delete note from the folder @@ -130,7 +130,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0;" + - " END"; + " END"; //删除时减少数量 /** * Update note's content when insert data with type {@link DataConstants#NOTE} @@ -143,7 +143,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; + " END"; //更新便签数据时更改table表内容 /** * Update note's content when data with {@link DataConstants#NOTE} type has changed @@ -156,7 +156,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; + " END"; //改变便签数据时更改table表内容 /** * Update note's content when data with {@link DataConstants#NOTE} type has deleted @@ -169,7 +169,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=''" + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + - " END"; + " END"; //删除便签数据时改变table表内容 /** * Delete datas belong to note which has been deleted @@ -180,7 +180,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " BEGIN" + " DELETE FROM " + TABLE.DATA + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + - " END"; + " END"; //删除便签时删除便签内容 /** * Delete notes belong to folder which has been deleted @@ -191,7 +191,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " BEGIN" + " DELETE FROM " + TABLE.NOTE + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; + " END"; //删除文件夹时删除内部的便签 /** * Move notes belong to folder which has been moved to trash folder @@ -204,20 +204,20 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; + " END"; //移动便签的父文件夹时便签也一起更改 public NotesDatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); - } + } //创建一个数据库 public void createNoteTable(SQLiteDatabase db) { db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); - Log.d(TAG, "note table has been created"); + reCreateNoteTableTriggers(db); //重新创建触发器 + createSystemFolder(db); //创建系统文件夹 + Log.d(TAG, "note table has been created"); //创建一个新的便签表,返回日志 } - private void reCreateNoteTableTriggers(SQLiteDatabase db) { + private void reCreateNoteTableTriggers(SQLiteDatabase db) { //数据库对象DB db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); @@ -233,17 +233,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); - } + } //用于执行SQL语句,运行重新创建便签表触发器函数 - private void createSystemFolder(SQLiteDatabase db) { - ContentValues values = new ContentValues(); + private void createSystemFolder(SQLiteDatabase db) { //创建系统级文件夹 + ContentValues values = new ContentValues(); //为字典类创建对象 /** * call record foler for call notes */ values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //为通讯便签创建记录文件夹,并添加键值对 /** * root folder which is default folder @@ -251,7 +251,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.clear(); values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //创建根文件夹,是默认的、最终的父文件夹 /** * temporary folder which is used for moving note @@ -259,7 +259,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.clear(); values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //为移动中的便签创建的临时文件夹 /** * create trash folder @@ -267,24 +267,24 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.clear(); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //创建垃圾桶 } - public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); + public void createDataTable(SQLiteDatabase db) { //创建数据表 + db.execSQL(CREATE_DATA_TABLE_SQL); //SQL输入保存的语句 reCreateDataTableTriggers(db); db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); - Log.d(TAG, "data table has been created"); + Log.d(TAG, "data table has been created"); //日志记录 } - private void reCreateDataTableTriggers(SQLiteDatabase db) { + private void reCreateDataTableTriggers(SQLiteDatabase db) { //为数据表重新创建触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); //删除触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); //重新创建被删除的触发器 } static synchronized NotesDatabaseHelper getInstance(Context context) { @@ -292,16 +292,16 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { mInstance = new NotesDatabaseHelper(context); } return mInstance; - } + } //静态同步方法,用于返回NotesDatabaseHelper的对象实例mInstance @Override public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); - } + createNoteTable(db); //创建便签表 + createDataTable(db); //创建数据表 + } //用于初始化表 @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //用于检查并升级数据库版本 boolean reCreateTriggers = false; boolean skipV2 = false; @@ -309,31 +309,31 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { upgradeToV2(db); skipV2 = true; // this upgrade including the upgrade from v2 to v3 oldVersion++; - } + } //检测到版本为1,升级版本 if (oldVersion == 2 && !skipV2) { upgradeToV3(db); - reCreateTriggers = true; - oldVersion++; + reCreateTriggers = true; //重建触发器标志 + oldVersion++; //检测到版本为2,升级版本 } if (oldVersion == 3) { upgradeToV4(db); oldVersion++; - } + } //检测到版本为3,升级版本 if (reCreateTriggers) { reCreateNoteTableTriggers(db); reCreateDataTableTriggers(db); - } + } //进行触发器的重建 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion - + "fails"); + + "fails"); //版本不匹配则抛出异常 } } - private void upgradeToV2(SQLiteDatabase db) { + private void upgradeToV2(SQLiteDatabase db) { //升级版本并重建表 db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); createNoteTable(db); @@ -353,10 +353,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); - } + } //删除不用的触发器,并添加不为空的新列,添加键值对 private void upgradeToV4(SQLiteDatabase db) { db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0"); - } + } //添加新的不为空的列 } diff --git a/src/data/NotesProvider.java b/src/data/NotesProvider.java index edb0a60..9ae1528 100644 --- a/src/data/NotesProvider.java +++ b/src/data/NotesProvider.java @@ -36,22 +36,22 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE; public class NotesProvider extends ContentProvider { - private static final UriMatcher mMatcher; + private static final UriMatcher mMatcher; //UriMatcher类用于分辨数据表 - private NotesDatabaseHelper mHelper; + private NotesDatabaseHelper mHelper; //建立NotesDatabaseHelper类对象 - private static final String TAG = "NotesProvider"; + private static final String TAG = "NotesProvider"; //设置类名值 - private static final int URI_NOTE = 1; + private static final int URI_NOTE = 1; //设置便签uri private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; + private static final int URI_DATA = 3; //设置数据uri private static final int URI_DATA_ITEM = 4; - private static final int URI_SEARCH = 5; + private static final int URI_SEARCH = 5; //设置搜索uri private static final int URI_SEARCH_SUGGEST = 6; static { - mMatcher = new UriMatcher(UriMatcher.NO_MATCH); + mMatcher = new UriMatcher(UriMatcher.NO_MATCH); //进行初始化 mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); @@ -59,48 +59,48 @@ public class NotesProvider extends ContentProvider { mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); - } + } //将不同的uri与数值相匹配 /** * x'0A' represents the '\n' character in sqlite. For title and content in the search result, * we will trim '\n' and white space in order to show more information. - */ + */ //用0A代表\n,为搜索结果换行 private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," - + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; //... private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER - + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; //检索便签的sql语句,在列表中搜寻。使用Notes类中的接口与变量 @Override public boolean onCreate() { mHelper = NotesDatabaseHelper.getInstance(getContext()); - return true; + return true; //创建NotesDatabaseHelper类并返回成果标识 } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); + String sortOrder) { //负责查询数据,接受uri、返回烈、选择、排列方式 + Cursor c = null; //创建空游标,表示数据库操作结果集合 + SQLiteDatabase db = mHelper.getReadableDatabase(); //获取数据库对象 String id = null; - switch (mMatcher.match(uri)) { + switch (mMatcher.match(uri)) { //确定uri类型 case URI_NOTE: c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, - sortOrder); + sortOrder); //传参,进行标准查询 break; case URI_NOTE_ITEM: id = uri.getPathSegments().get(1); c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); - break; + break; //传参,对id进行查询 case URI_DATA: c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder); @@ -112,13 +112,13 @@ public class NotesProvider extends ContentProvider { break; case URI_SEARCH: case URI_SEARCH_SUGGEST: - if (sortOrder != null || projection != null) { + if (sortOrder != null || projection != null) { //检查是否指定排序方式 throw new IllegalArgumentException( "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); } String searchString = null; - if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { + if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { //提取uri中搜索模式 if (uri.getPathSegments().size() > 1) { searchString = uri.getPathSegments().get(1); } @@ -133,43 +133,43 @@ public class NotesProvider extends ContentProvider { try { searchString = String.format("%%%s%%", searchString); c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, - new String[] { searchString }); + new String[] { searchString }); //在Notes表进行搜索 } catch (IllegalStateException ex) { - Log.e(TAG, "got exception: " + ex.toString()); + Log.e(TAG, "got exception: " + ex.toString()); //日志 } break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); //抛出异常 } if (c != null) { - c.setNotificationUri(getContext().getContentResolver(), uri); - } + c.setNotificationUri(getContext().getContentResolver(), uri); //在游标查询的数据变化时进行通知 + } //通知uri是标识查询结果的uri,setNotificationUri方法可注册通知uri,与对象c相关联 return c; } @Override - public Uri insert(Uri uri, ContentValues values) { - SQLiteDatabase db = mHelper.getWritableDatabase(); + public Uri insert(Uri uri, ContentValues values) { //uri表示要插入的uri,values表示要插入的数据 + SQLiteDatabase db = mHelper.getWritableDatabase(); //打开或创建一个数据库 long dataId = 0, noteId = 0, insertedId = 0; - switch (mMatcher.match(uri)) { + switch (mMatcher.match(uri)) { //匹配uri case URI_NOTE: - insertedId = noteId = db.insert(TABLE.NOTE, null, values); + insertedId = noteId = db.insert(TABLE.NOTE, null, values); //将数据插入到Notes表中 break; case URI_DATA: - if (values.containsKey(DataColumns.NOTE_ID)) { - noteId = values.getAsLong(DataColumns.NOTE_ID); + if (values.containsKey(DataColumns.NOTE_ID)) { //检查values是否含有NOTE_ID内容,返回bool值 + noteId = values.getAsLong(DataColumns.NOTE_ID); //关联noteId } else { - Log.d(TAG, "Wrong data format without note id:" + values.toString()); + Log.d(TAG, "Wrong data format without note id:" + values.toString()); //日志记录 } - insertedId = dataId = db.insert(TABLE.DATA, null, values); + insertedId = dataId = db.insert(TABLE.DATA, null, values); //数据库插入新行的id返回到两个变量中 break; default: throw new IllegalArgumentException("Unknown URI " + uri); } // Notify the note uri - if (noteId > 0) { + if (noteId > 0) { //不为零表示插入成功, getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); //通知uri发生变化 } // Notify the data uri @@ -178,22 +178,22 @@ public class NotesProvider extends ContentProvider { ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); } - return ContentUris.withAppendedId(uri, insertedId); + return ContentUris.withAppendedId(uri, insertedId); //返回新的uri,表示插入位置 } @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - int count = 0; + public int delete(Uri uri, String selection, String[] selectionArgs) { //表示要删除的uri、SQL中的WHERE与参数 + int count = 0; //表示删除记录数 String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); + SQLiteDatabase db = mHelper.getWritableDatabase(); //打开数据库 boolean deleteData = false; - switch (mMatcher.match(uri)) { + switch (mMatcher.match(uri)) { //uri匹配 case URI_NOTE: - selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; - count = db.delete(TABLE.NOTE, selection, selectionArgs); + selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; //设置WHERE + count = db.delete(TABLE.NOTE, selection, selectionArgs); //删除,并计数 break; case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); + id = uri.getPathSegments().get(1); //获取id /** * ID that smaller than 0 is system folder which is not allowed to * trash @@ -204,45 +204,45 @@ public class NotesProvider extends ContentProvider { } count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - break; + break; //删除指定id,并计数 case URI_DATA: - count = db.delete(TABLE.DATA, selection, selectionArgs); + count = db.delete(TABLE.DATA, selection, selectionArgs); //删除,并计数 deleteData = true; break; case URI_DATA_ITEM: - id = uri.getPathSegments().get(1); + id = uri.getPathSegments().get(1); //获取id count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - deleteData = true; + deleteData = true; //删除指定id,并计数 break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); //报错 } - if (count > 0) { + if (count > 0) { //表示有删除操作,通知uri发生变化 if (deleteData) { getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } getContext().getContentResolver().notifyChange(uri, null); } - return count; + return count; //返回删除的记录数 } @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - int count = 0; + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { //表示更新的uri、values为新的列值、where以及参数 + int count = 0; //更新条数 String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean updateData = false; - switch (mMatcher.match(uri)) { + SQLiteDatabase db = mHelper.getWritableDatabase(); //打开数据库 + boolean updateData = false; //设置数据表更新表示 + switch (mMatcher.match(uri)) { //匹配uri case URI_NOTE: - increaseNoteVersion(-1, selection, selectionArgs); - count = db.update(TABLE.NOTE, values, selection, selectionArgs); + increaseNoteVersion(-1, selection, selectionArgs); //跟新便签 + count = db.update(TABLE.NOTE, values, selection, selectionArgs); //更新指定表的行,并计数 break; case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); + id = uri.getPathSegments().get(1); //提取id increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); + + parseSelection(selection), selectionArgs); //增加指定的id条件 break; case URI_DATA: count = db.update(TABLE.DATA, values, selection, selectionArgs); @@ -255,51 +255,50 @@ public class NotesProvider extends ContentProvider { updateData = true; break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); //抛出异常 } if (count > 0) { if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);//通知指定uri数据更改 } - getContext().getContentResolver().notifyChange(uri, null); + getContext().getContentResolver().notifyChange(uri, null); //通知uri数据更改 } return count; } - private String parseSelection(String selection) { - return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); + private String parseSelection(String selection) { //检查selection是否为空 + return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); //为空则返回“” } - private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { + private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { //使用数据库更新便签版本 StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); sql.append(TABLE.NOTE); sql.append(" SET "); sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); + sql.append("=" + NoteColumns.VERSION + "+1 "); //升级便签版本号 - if (id > 0 || !TextUtils.isEmpty(selection)) { + if (id > 0 || !TextUtils.isEmpty(selection)) { //selection不为空或存在id则增加where条件 sql.append(" WHERE "); } if (id > 0) { sql.append(NoteColumns.ID + "=" + String.valueOf(id)); } if (!TextUtils.isEmpty(selection)) { - String selectString = id > 0 ? parseSelection(selection) : selection; - for (String args : selectionArgs) { - selectString = selectString.replaceFirst("\\?", args); + String selectString = id > 0 ? parseSelection(selection) : selection; //parseSelection将传入的参数中的占位符替换为实际的值 + for (String args : selectionArgs) { // + selectString = selectString.replaceFirst("\\?", args); //replaceFirst选择参数数组中的值替换语句中的占位符 } sql.append(selectString); } - mHelper.getWritableDatabase().execSQL(sql.toString()); + mHelper.getWritableDatabase().execSQL(sql.toString()); //执行SQL语句 } @Override - public String getType(Uri uri) { - // TODO Auto-generated method stub + public String getType(Uri uri) { //获取指定uri的MIME类型 + // TODO Auto-generated method stub //表示该方法没有实现 return null; } - } diff --git a/src/gtask/data/MetaData.java b/src/gtask/data/MetaData.java index 3a2050b..c4683e4 100644 --- a/src/gtask/data/MetaData.java +++ b/src/gtask/data/MetaData.java @@ -24,31 +24,33 @@ import net.micode.notes.tool.GTaskStringUtils; import org.json.JSONException; import org.json.JSONObject; - public class MetaData extends Task { - private final static String TAG = MetaData.class.getSimpleName(); + // 通过getSimpleName()获得类的gid并存入字符串中 + private final static String TAG = MetaData.class.getSimpleName(); private String mRelatedGid = null; - + // 设置元数据,生成元数据库 public void setMeta(String gid, JSONObject metaInfo) { try { + // 注释方法块 metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { + // 生成无法创建关联gid的日志 Log.e(TAG, "failed to put related gid"); } setNotes(metaInfo.toString()); setName(GTaskStringUtils.META_NOTE_NAME); } - + // 获取关联的gid public String getRelatedGid() { return mRelatedGid; } - + // 判断数据是否为空是否值得保存 @Override public boolean isWorthSaving() { return getNotes() != null; } - + // 使用远程json设置元数据内容 @Override public void setContentByRemoteJSON(JSONObject js) { super.setContentByRemoteJSON(js); @@ -62,18 +64,18 @@ public class MetaData extends Task { } } } - + // 使用本地json对象设置数据内容,该方法不应该被调用,若调用则抛出异常 @Override public void setContentByLocalJSON(JSONObject js) { // this function should not be called throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); } - + // 从元数据中获取本地json对象,该方法不应该被调用,若调用则抛出异常 @Override public JSONObject getLocalJSONFromContent() { throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); } - + // 获取同步动作状态,该方法不应该被调用,若调用则抛出异常 @Override public int getSyncAction(Cursor c) { throw new IllegalAccessError("MetaData:getSyncAction should not be called"); diff --git a/src/gtask/data/Node.java b/src/gtask/data/Node.java index 63950e0..1484c14 100644 --- a/src/gtask/data/Node.java +++ b/src/gtask/data/Node.java @@ -19,32 +19,33 @@ package net.micode.notes.gtask.data; import android.database.Cursor; import org.json.JSONObject; - +// 对同步操作的基本节点进行一个定义 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() { diff --git a/src/gtask/data/SqlData.java b/src/gtask/data/SqlData.java index d3ec3be..72ba013 100644 --- a/src/gtask/data/SqlData.java +++ b/src/gtask/data/SqlData.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +// Description:用于支持小米便签最底层的数据库相关操作,和sqlnote的关系上是子集关系,即data是note的子集(节点)。 +// SqlData其实就是也就是所谓数据中的数据 package net.micode.notes.gtask.data; import android.content.ContentResolver; @@ -34,17 +35,17 @@ import net.micode.notes.gtask.exception.ActionFailureException; import org.json.JSONException; import org.json.JSONObject; - public class SqlData { + // 将得到的内容写入字符串tag中 private static final String TAG = SqlData.class.getSimpleName(); - + // 设置无效id为-99999 private static final int INVALID_ID = -99999; - + // 集合interface DataColumns中所有sf常量 public static final String[] PROJECTION_DATA = new String[] { DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, DataColumns.DATA3 }; - + // 为sql表编号 public static final int DATA_ID_COLUMN = 0; public static final int DATA_MIME_TYPE_COLUMN = 1; @@ -56,7 +57,7 @@ public class SqlData { public static final int DATA_CONTENT_DATA_3_COLUMN = 4; private ContentResolver mContentResolver; - + // 判断是否用content生成,真为true,假为false private boolean mIsCreate; private long mDataId; @@ -70,7 +71,7 @@ public class SqlData { private String mDataContentData3; private ContentValues mDiffDataValues; - + // 初始化数据库的构造函数 public SqlData(Context context) { mContentResolver = context.getContentResolver(); mIsCreate = true; @@ -81,14 +82,14 @@ public class SqlData { mDataContentData3 = ""; mDiffDataValues = new ContentValues(); } - + // 初始化数据库的构造函数 public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); mIsCreate = false; loadFromCursor(c); mDiffDataValues = new ContentValues(); } - + // 从游标处加载数据 private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -96,7 +97,7 @@ public class SqlData { mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } - + // 设置用于共享的数据 public void setContent(JSONObject js) throws JSONException { long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; if (mIsCreate || mDataId != dataId) { @@ -129,7 +130,7 @@ public class SqlData { } mDataContentData3 = dataContentData3; } - + // 获取共享数据的内容 public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); @@ -143,7 +144,7 @@ public class SqlData { js.put(DataColumns.DATA3, mDataContentData3); return js; } - + // 提交更改至数据库 public void commit(long noteId, boolean validateVersion, long version) { if (mIsCreate) { @@ -182,7 +183,7 @@ public class SqlData { mDiffDataValues.clear(); mIsCreate = false; } - + // 获取当前id public long getId() { return mDataId; } diff --git a/src/gtask/data/SqlNote.java b/src/gtask/data/SqlNote.java index 79a4095..be42a61 100644 --- a/src/gtask/data/SqlNote.java +++ b/src/gtask/data/SqlNote.java @@ -37,12 +37,15 @@ import org.json.JSONObject; import java.util.ArrayList; +// 用于支持小米便签最底层的数据库相关操作,和sqldata的关系上是父集关系,即note是data的子父集 +// 和SqlData相比SqlNote算是真正意义上的数据 public class SqlNote { + // 得到的类名写入tag中 private static final String TAG = SqlNote.class.getSimpleName(); private static final int INVALID_ID = -99999; - + // 集合了interface NoteColumns中所有SF常量 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, @@ -121,7 +124,7 @@ public class SqlNote { private ContentValues mDiffNoteValues; private ArrayList mDataList; - + // 构造函数,初始化context参数 public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -142,7 +145,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } - + // 通过游标初始化context public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -165,7 +168,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); } - + // 从游标加载数据 private void loadFromCursor(long id) { Cursor c = null; try { @@ -184,7 +187,7 @@ public class SqlNote { c.close(); } } - + // 从游标加载数据 private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); @@ -199,7 +202,7 @@ public class SqlNote { mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); mVersion = c.getLong(VERSION_COLUMN); } - + // 获取共享数据并加载到数据库当前游标处 private void loadDataContent() { Cursor c = null; mDataList.clear(); @@ -225,7 +228,7 @@ public class SqlNote { c.close(); } } - + // 设置通过content机制用于共享的数据信息 public boolean setContent(JSONObject js) { try { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); @@ -358,7 +361,7 @@ public class SqlNote { } return true; } - + // 获取content机制提供的数据并加载到note中 public JSONObject getContent() { try { JSONObject js = new JSONObject(); @@ -406,40 +409,40 @@ public class SqlNote { } return null; } - + //给当前id设置父id public void setParentId(long id) { mParentId = id; mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } - + // 给当前id设置Gtaskid public void setGtaskId(String gid) { mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } - + // 给当前id设置同步id public void setSyncId(long syncId) { mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); } - + // 初始化本地修改,即撤销 public void resetLocalModified() { mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); } - + // 获得当前id public long getId() { return mId; } - + // 获得id的父id public long getParentId() { return mParentId; } - + // 获取小部分内容以显示部分便签内容 public String getSnippet() { return mSnippet; } - + // 判断是否为便签类型 public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } - + // 提交更改到数据库 public void commit(boolean validateVersion) { if (mIsCreate) { if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { diff --git a/src/gtask/data/Task.java b/src/gtask/data/Task.java index 6a19454..58097db 100644 --- a/src/gtask/data/Task.java +++ b/src/gtask/data/Task.java @@ -34,17 +34,17 @@ import org.json.JSONObject; 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; - + // 父类指针 private TaskList mParent; - + // 初始化构造方法 public Task() { super(); mCompleted = false; @@ -53,7 +53,7 @@ public class Task extends Node { mParent = null; mMetaInfo = null; } - + // 用于创建jsonobject对象,获取创建新行为的操作 public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -102,7 +102,7 @@ public class Task extends Node { return js; } - + // 用于创建jsonobject对象,实现创建更新行为的操作 public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -134,7 +134,7 @@ public class Task extends Node { return js; } - + // 用于从远端目录创建 public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -174,7 +174,7 @@ public class Task extends Node { } } } - + // 本地创建 public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { @@ -203,7 +203,7 @@ public class Task extends Node { e.printStackTrace(); } } - + // 从目录获取本地json public JSONObject getLocalJSONFromContent() { String name = getName(); try { @@ -246,7 +246,7 @@ public class Task extends Node { return null; } } - + // 设置meta信息 public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { @@ -257,7 +257,7 @@ public class Task extends Node { } } } - + // 获取同步行为 public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; diff --git a/src/gtask/data/TaskList.java b/src/gtask/data/TaskList.java index 4ea21c5..5f48d1d 100644 --- a/src/gtask/data/TaskList.java +++ b/src/gtask/data/TaskList.java @@ -32,9 +32,9 @@ import java.util.ArrayList; public class TaskList extends Node { private static final String TAG = TaskList.class.getSimpleName(); - + // 当前TaskList的指针 private int mIndex; - + // 类中主要的保存数据的单元,用来实现一个以Task为元素的ArrayList private ArrayList mChildren; public TaskList() { @@ -42,7 +42,7 @@ public class TaskList extends Node { mChildren = new ArrayList(); mIndex = 1; } - + // 生成并返回一个包含了一定数据的JSONObject实体 public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -73,7 +73,7 @@ public class TaskList extends Node { return js; } - + // 更新一个包含了一定数据的JSONObject实体 public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -215,11 +215,11 @@ public class TaskList extends Node { return SYNC_ACTION_ERROR; } - + // 获得TaskList的大小 public int getChildTaskCount() { return mChildren.size(); } - + // 在当前任务表末尾添加新的任务 public boolean addChildTask(Task task) { boolean ret = false; if (task != null && !mChildren.contains(task)) { @@ -233,7 +233,7 @@ public class TaskList extends Node { } return ret; } - + // 在当前任务表的指定位置添加新的任务 public boolean addChildTask(Task task, int index) { if (index < 0 || index > mChildren.size()) { Log.e(TAG, "add child task: invalid index"); @@ -259,7 +259,7 @@ public class TaskList extends Node { return true; } - + // 删除TaskList中的一个Task public boolean removeChildTask(Task task) { boolean ret = false; int index = mChildren.indexOf(task); @@ -280,7 +280,7 @@ public class TaskList extends Node { } return ret; } - + // 移动TaskList中的一个Task public boolean moveChildTask(Task task, int index) { if (index < 0 || index >= mChildren.size()) { @@ -298,7 +298,7 @@ public class TaskList extends Node { return true; return (removeChildTask(task) && addChildTask(task, index)); } - + // 按gid寻找Task public Task findChildTaskByGid(String gid) { for (int i = 0; i < mChildren.size(); i++) { Task t = mChildren.get(i); @@ -308,11 +308,11 @@ public class TaskList extends Node { } return null; } - + // 返回指定Task的index public int getChildTaskIndex(Task task) { return mChildren.indexOf(task); } - + // 返回指定index的Task public Task getChildTaskByIndex(int index) { if (index < 0 || index >= mChildren.size()) { Log.e(TAG, "getTaskByIndex: invalid index"); @@ -320,7 +320,7 @@ public class TaskList extends Node { } return mChildren.get(index); } - + // 返回指定gid的task public Task getChilTaskByGid(String gid) { for (Task task : mChildren) { if (task.getGid().equals(gid)) diff --git a/src/gtask/exception/ActionFailureException.java b/src/gtask/exception/ActionFailureException.java index 15504be..7787d25 100644 --- a/src/gtask/exception/ActionFailureException.java +++ b/src/gtask/exception/ActionFailureException.java @@ -14,15 +14,17 @@ * limitations under the License. */ +// 小米便签运行过程中的运行异常处理 package net.micode.notes.gtask.exception; public class ActionFailureException extends RuntimeException { + // 版本控制用,反序列化版本升级时仍保持对象唯一性 private static final long serialVersionUID = 4425249765923293627L; + // 通过super()来引用父类成分 public ActionFailureException() { super(); } - public ActionFailureException(String paramString) { super(paramString); } diff --git a/src/gtask/exception/NetworkFailureException.java b/src/gtask/exception/NetworkFailureException.java index b08cfb1..6f67afe 100644 --- a/src/gtask/exception/NetworkFailureException.java +++ b/src/gtask/exception/NetworkFailureException.java @@ -14,11 +14,14 @@ * limitations under the License. */ +// 运行过程中的网络异常处理 package net.micode.notes.gtask.exception; public class NetworkFailureException extends Exception { + // 版本控制用,反序列化版本升级时仍保持对象唯一性 private static final long serialVersionUID = 2107610287180234136L; + // 通过super()来引用父类成分 public NetworkFailureException() { super(); } diff --git a/src/gtask/remote/GTaskASyncTask.java b/src/gtask/remote/GTaskASyncTask.java index b3b61e7..7981605 100644 --- a/src/gtask/remote/GTaskASyncTask.java +++ b/src/gtask/remote/GTaskASyncTask.java @@ -15,6 +15,14 @@ * limitations under the License. */ +/* + *异步操作类,实现Gtask异步操作过程 + *主要方法: + *private void showNotification(int tickerId, String content) 用于为用户同步当前事件状态 + *protected Integer doInBackground(Void... unused) 后台线程执行,完成任务主要工作 + *protected void onProgressUpdate(String... progress) 主线程运行,以进度条显示用户工作完成状态 + *protected void onPostExecute(Integer result) 更新UI + */ package net.micode.notes.gtask.remote; import android.app.Notification; @@ -44,7 +52,7 @@ public class GTaskASyncTask extends AsyncTask { private GTaskManager mTaskManager; private OnCompleteListener mOnCompleteListener; - + // GTask的一个同步进程类,包含上下文信息,事件完成进度监听方法,通知管理方法,和进程管理方法 public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; @@ -52,56 +60,70 @@ public class GTaskASyncTask extends AsyncTask { .getSystemService(Context.NOTIFICATION_SERVICE); mTaskManager = GTaskManager.getInstance(); } - + //取消同步 public void cancelSync() { mTaskManager.cancelSync(); } - + // 发布并更新事件处理进程 public void publishProgess(String message) { 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; + // 同步失败挂起活动信息 if (tickerId != R.string.ticker_success) { pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); - + // 同步成功显示活动信息列表 } else { + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), 0); } - notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent); + // 该方法疑似为设置显示最新事件信息,但运行时编译器报错,暂时注释以规避报错选项 + /*notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, + pendingIntent);*/ + // mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } @Override protected Integer doInBackground(Void... unused) { + //利用getString将NotesPreferenceActivity.getSyncAccountName(mContext)的字符串内容 + //传进sync_progress_login中 publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity .getSyncAccountName(mContext))); + //返回后台同步的具体操作 return mTaskManager.sync(mContext, this); } @Override protected void onProgressUpdate(String... progress) { showNotification(R.string.ticker_syncing, progress[0]); + //判断mContext是否为GTaskSyncService的实例 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } @Override + //后台运行完后更新ui,显示更新后结果 protected void onPostExecute(Integer result) { 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)); @@ -111,9 +133,11 @@ public class GTaskASyncTask extends AsyncTask { showNotification(R.string.ticker_cancel, mContext .getString(R.string.error_sync_cancelled)); } + //不同状态下的结果显示 if (mOnCompleteListener != null) { + //新增可运行线程 new Thread(new Runnable() { - + //线程运行,初始化操作 public void run() { mOnCompleteListener.onComplete(); } diff --git a/src/gtask/remote/GTaskClient.java b/src/gtask/remote/GTaskClient.java index c67dfdf..fee4803 100644 --- a/src/gtask/remote/GTaskClient.java +++ b/src/gtask/remote/GTaskClient.java @@ -60,10 +60,13 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; - +/* + *实现GTask登录操作,创建GTask任务,与谷歌服务联网获取任务和任务列表 + *主要用类:accountManager JSONObject HttpParams authToken Gid + */ public class GTaskClient { private static final String TAG = GTaskClient.class.getSimpleName(); - + //指定登录URL地址 private static final String GTASK_URL = "https://mail.google.com/tasks/"; private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; @@ -89,7 +92,7 @@ public class GTaskClient { private Account mAccount; private JSONArray mUpdateArray; - + // 创建GTask构造方法 private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -101,35 +104,38 @@ public class GTaskClient { mAccount = null; mUpdateArray = null; } - + // 实例化并锁定GTaskClient,使用getInstance()返回mInstance public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); } return mInstance; } - + // 用于实现登录操作的布尔方法,提供了账号URL密码登录和谷歌官方邮箱URL登录两种登陆方法 public boolean login(Activity activity) { // we suppose that the cookie would expire after 5 minutes // then we need to re-login + // 五分钟后需要重新登录 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(); + // 返回的Token为空则登陆失败 String authToken = loginGoogleAccount(activity, false); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -137,6 +143,7 @@ public class GTaskClient { } // 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/"); @@ -152,6 +159,7 @@ public class GTaskClient { } // try to login with google official url + // 调取谷歌邮箱官方URL登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -163,25 +171,30 @@ public class GTaskClient { mLoggedin = true; return true; } - + // 实现谷歌登录的方法,以AccountManager管理账号,Token登录 private String loginGoogleAccount(Activity activity, boolean invalidateToken) { + // 登录Token String authToken; + // 账号管理,提供账号注册接口 AccountManager accountManager = AccountManager.get(activity); + // 获取以com.google结尾的账号列表 Account[] accounts = accountManager.getAccountsByType("com.google"); - + // 如果账号长度为空则返回无可用账号 if (accounts.length == 0) { Log.e(TAG, "there is no available google account"); return null; } - + // 获取账户名称 String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; + // 遍历返回的账户信息,寻找记录的账户信息 for (Account a : accounts) { if (a.name.equals(accountName)) { account = a; break; } } + if (account != null) { mAccount = account; } else { @@ -190,11 +203,13 @@ public class GTaskClient { } // get the token now + // 取得登录Token AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { Bundle authTokenBundle = accountManagerFuture.getResult(); authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); + // 若Token无效,则通过invalidateAuthToken方法废除该Token if (invalidateToken) { accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); @@ -206,11 +221,12 @@ public class GTaskClient { return authToken; } - + // 尝试登录的布尔方法需要预先判断Token是否有效 private boolean tryToLoginGtask(Activity activity, String authToken) { if (!loginGtask(authToken)) { // maybe the auth token is out of date, now let's invalidate the // token and try again + // 若Token则废弃Token且重试 authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -224,26 +240,35 @@ public class GTaskClient { } return true; } - + // 登录GTask具体操作 private boolean loginGtask(String authToken) { int timeoutConnection = 10000; + // socket为一种通信数据交换的端口 int timeoutSocket = 15000; + // 实现一个新的HTTP参数类 HttpParams httpParameters = new BasicHttpParams(); + // 设置链接超时时间 HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); + // 设置设置端口超时时间 HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); mHttpClient = new DefaultHttpClient(httpParameters); + // 存储新的本地cookie BasicCookieStore localBasicCookieStore = new BasicCookieStore(); mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); // login gtask + // 登录GTask具体操作 try { + // 设置登录URL String loginUrl = mGetUrl + "?auth=" + authToken; + // 通过已实例化URL网页中的资源查找 HttpGet httpGet = new HttpGet(loginUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); // get the cookie now + // 遍历已存储的cookie以验证是否与登录cookie相符,若相符则匹配 List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -256,6 +281,7 @@ public class GTaskClient { } // get the client version + // 以脚本获取返回的Content中GTask_Url的内容 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -273,40 +299,47 @@ public class GTaskClient { return false; } catch (Exception e) { // simply catch all exceptions + // 仅捕获到异常则返回捕获失败 Log.e(TAG, "httpget gtask_url failed"); return false; } return true; } - + // 获取行为ID private int getActionId() { return mActionId++; } + // 实例化创建用于网络传输的对向,使用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; } - + // 获取响应的资源目录 private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; + // 荣国URL获得HttpEntity对象,若返回值不为空,则创建数据流获取返回对象 if (entity.getContentEncoding() != null) { contentEncoding = entity.getContentEncoding().getValue(); Log.d(TAG, "encoding: " + contentEncoding); } InputStream input = entity.getContent(); + // Gzip为使用DEFLATE压缩数据的另一个压缩库 if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { input = new GZIPInputStream(entity.getContent()); - } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { + } + // Deflate为一个无专利的无损数据压缩算法 + else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("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(); @@ -322,7 +355,10 @@ public class GTaskClient { input.close(); } } - + /* + * 以json发送请求,请求的内容在json中的实例化对象传入,利用json获取task中内容 + * 并创捷对应jspost,利用postrequest得到返回的任务信息并用task_setGid设置task的新id + */ private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -360,6 +396,8 @@ public class GTaskClient { } } + // 创建单个任务,传入task类的对象、使用json获取task中的内容,并创建相应的jspost,利用postRequest获得任务返回信 + // 息并且使用task.setGid设置task的new_id public void createTask(Task task) throws NetworkFailureException { commitUpdate(); try { @@ -385,7 +423,7 @@ public class GTaskClient { throw new ActionFailureException("create task: handing jsonobject failed"); } } - + // 创建任务列表,设置tasklist_Gid public void createTaskList(TaskList tasklist) throws NetworkFailureException { commitUpdate(); try { @@ -411,7 +449,8 @@ public class GTaskClient { 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 { @@ -432,7 +471,7 @@ public class GTaskClient { } } } - + // 添加更新事项,通过调用 commitUpdate()实现 public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { // too many update items may result in an error @@ -446,7 +485,9 @@ public class GTaskClient { mUpdateArray.put(node.getUpdateAction(getActionId())); } } - + // 移动task至不同的任务列表中去,通过getgid获取所属不同任务列表的gid,通过 + // JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的 + // 最后通过postRequest进行更新后的任务列表的发送 public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { commitUpdate(); @@ -463,6 +504,7 @@ public class GTaskClient { 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()); @@ -472,6 +514,7 @@ public class GTaskClient { action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } actionList.put(action); + //最后将ACTION_LIST加入到jsPost中 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // client_version @@ -486,6 +529,7 @@ public class GTaskClient { } } + //删除操作节点,利用JSON,删除后使用postRequest发送删除后的结果 public void deleteNode(Node node) throws NetworkFailureException { commitUpdate(); try { @@ -494,6 +538,7 @@ public class GTaskClient { // action_list node.setDeleted(true); + // 这里会获取到删除操作的ID,加入到actionLiast中 actionList.put(node.getUpdateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); @@ -508,7 +553,8 @@ public class GTaskClient { throw new ActionFailureException("delete node: handing jsonobject failed"); } } - + //获取任务列表,首先通过GetURL使用getResponseContent联网获取数据,然后筛选出"_setup("到)}的部分, + // 并且从中获取GTASK_JSON_LISTS的内容返回 public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -521,6 +567,7 @@ public class GTaskClient { response = mHttpClient.execute(httpGet); // get the task list + // 获取任务列表并存储进jsString中 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -547,6 +594,7 @@ public class GTaskClient { } } + // 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -558,6 +606,7 @@ public class GTaskClient { action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); + // 设置为传入的listGid action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); actionList.put(action); @@ -578,7 +627,7 @@ public class GTaskClient { public Account getSyncAccount() { return mAccount; } - + // 重装更新后的内容 public void resetUpdateArray() { mUpdateArray = null; } diff --git a/src/gtask/remote/GTaskManager.java b/src/gtask/remote/GTaskManager.java index d2b4082..d514ada 100644 --- a/src/gtask/remote/GTaskManager.java +++ b/src/gtask/remote/GTaskManager.java @@ -86,33 +86,44 @@ public class GTaskManager { private HashMap mGidToNid; private HashMap mNidToGid; - + // 初始化Google任务管理器的函数 private GTaskManager() { + // 初始化同步状态为未执行 mSyncing = false; + // 全局状态标识为可执行 mCancelled = false; + // java泛型类,用于创建一个用类作为参数的类 mGTaskListHashMap = new HashMap(); mGTaskHashMap = new HashMap(); mMetaHashMap = new HashMap(); mMetaList = null; mLocalDeleteIdMap = new HashSet(); + // 将Gid转换为Noteid通过哈希表建立映射 mGidToNid = new HashMap(); + // 将Noteid转换为Gid通过哈希表建立映射 mNidToGid = new HashMap(); } - + // synchronizedy语言级同步,用于表述该方法可能运行于多线程环境之下 + // 该方法用于初始化mInstance + // @return GTaskManager public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); } return mInstance; } - + // synchronizedy语言级同步,用于表述该方法可能运行于多线程环境之下 public synchronized void setActivityContext(Activity activity) { // used for getting authtoken mActivity = activity; } - + // 用于本地化和远端同步的方法 + // @param context-----获取上下文 + // @param assyncTask-----用于同步的异步操作类 + // @return int public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { + // 创建同步的日志文件 Log.d(TAG, "Sync is in progress"); return STATE_SYNC_IN_PROGRESS; } @@ -128,11 +139,14 @@ public class GTaskManager { mNidToGid.clear(); try { + // 创建用户机实例 GTaskClient client = GTaskClient.getInstance(); + // JSON类型,用于置空NULL client.resetUpdateArray(); // login google task if (!mCancelled) { + // 谷歌登录操作,若非则抛出登陆失败异常 if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } @@ -140,14 +154,17 @@ public class GTaskManager { // get the task list from google asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); + // 将谷歌上获取的JSONTasklist转换为本地Tasklist initGTaskList(); // do content sync work asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); + // 抓取网络异常并创建调试日志抛出error } catch (NetworkFailureException e) { Log.e(TAG, e.toString()); return STATE_NETWORK_ERROR; + // 抓取操作异常并创建调试日志抛出error } catch (ActionFailureException e) { Log.e(TAG, e.toString()); return STATE_INTERNAL_ERROR; @@ -167,32 +184,44 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } - + // 初始化GTaskList,获取Google上JSONTaskList并转换为本地TaskList + // 将获取的数据储存在mMetaList,mGTaskListHashMap,MGTaskHashmap中 + // @exception NetworkFailureException + // @return void private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; GTaskClient client = GTaskClient.getInstance(); try { + // Json对象是子元素的无序集合,相当于创建一个Map对象, + // bantouyan-json库对Json对象的抽象概念,提供操纵json对象的各种方法, + // 其格式为("key1": value1,"key2": value2...)key为字符串 + // ajax请求不刷新页面,因此配合js可实现局部刷新,所以json常用作异步请求返回对象使用 JSONArray jsTaskLists = client.getTaskLists(); // init meta list first + // TaskList类型 mMetaList = null; for (int i = 0; i < jsTaskLists.length(); i++) { + // JSONObject与JSONArray一个为对象,一个为数组。此处取出单个JSONObject JSONObject object = jsTaskLists.getJSONObject(i); String 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)) { + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + // MetaList为元表,此处为初始化TaskList mMetaList = new TaskList(); + // 由远端JSON获取对象信息 mMetaList.setContentByRemoteJSON(object); // load meta data + // 获取用户端的TaskList的gid JSONArray jsMetas = client.getTaskList(gid); for (int j = 0; j < jsMetas.length(); j++) { object = (JSONObject) jsMetas.getJSONObject(j); MetaData metaData = new MetaData(); metaData.setContentByRemoteJSON(object); + // 判断值是否值得存储,为否则不加入mMetaList if (metaData.isWorthSaving()) { mMetaList.addChildTask(metaData); if (metaData.getGid() != null) { @@ -214,18 +243,21 @@ public class GTaskManager { // init task list for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); + // 通过GetString传入本地某标志数据的名称,获取其在远端的名称 String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); 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 tasklist = new TaskList(); tasklist.setContentByRemoteJSON(object); mGTaskListHashMap.put(gid, tasklist); mGTaskHashMap.put(gid, tasklist); // load tasks + // 加载tasks JSONArray jsTasks = client.getTaskList(gid); for (int j = 0; j < jsTasks.length(); j++) { object = (JSONObject) jsTasks.getJSONObject(j); @@ -246,7 +278,8 @@ public class GTaskManager { throw new ActionFailureException("initGTaskList: handing JSONObject failed"); } } - + // 本地内容同步操作 + // @throw NetWorkFailureException private void syncContent() throws NetworkFailureException { int syncType; Cursor c = null; @@ -300,6 +333,7 @@ public class GTaskManager { gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 通过哈希表获取gid mGTaskHashMap.remove(gid); mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); @@ -350,7 +384,7 @@ public class GTaskManager { } } - + // 同步文件夹 private void syncFolder() throws NetworkFailureException { Cursor c = null; String gid; @@ -475,7 +509,7 @@ public class GTaskManager { if (!mCancelled) GTaskClient.getInstance().commitUpdate(); } - + // 为同步类型分类 private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -521,7 +555,7 @@ public class GTaskManager { throw new ActionFailureException("unkown sync action type"); } } - + // 本地增加新的Node private void addLocalNode(Node node) throws NetworkFailureException { if (mCancelled) { return; @@ -595,7 +629,7 @@ public class GTaskManager { // update meta updateRemoteMeta(node.getGid(), sqlNote); } - + // 更新本地Node private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -618,12 +652,12 @@ public class GTaskManager { // update meta info updateRemoteMeta(node.getGid(), sqlNote); } - + // 添加远端node private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; } - + // 从本地数据库中获取内容 SqlNote sqlNote = new SqlNote(mContext, c); Node n; @@ -637,8 +671,9 @@ public class GTaskManager { Log.e(TAG, "cannot find task's parent tasklist"); throw new ActionFailureException("cannot add remote task"); } + // 在本地生成的GTaskList中添加子节点 mGTaskListHashMap.get(parentGid).addChildTask(task); - + // 登录远端服务器创建task GTaskClient.getInstance().createTask(task); n = (Node) task; @@ -655,7 +690,7 @@ public class GTaskManager { folderName += GTaskStringUtils.FOLDER_CALL_NOTE; else folderName += sqlNote.getSnippet(); - + // 迭代器,通过统一接口迭代所有map元素 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -691,7 +726,7 @@ public class GTaskManager { mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } - + // 更新远端node private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -709,15 +744,17 @@ public class GTaskManager { // move task if necessary if (sqlNote.isNoteType()) { Task task = (Task) node; + // preParentList通过node获取的父节点列表 TaskList preParentList = task.getParent(); - + // curParentGid为通过光标在数据库中找到sqlNote的mParentId,再通过mNidToGid由long类型转为String类型的Gid String curParentGid = mNidToGid.get(sqlNote.getParentId()); if (curParentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); throw new ActionFailureException("cannot update remote task"); } + // 通过HashMap找到对应Gid的TaskList TaskList curParentList = mGTaskListHashMap.get(curParentGid); - + // 判断父上一个节点是否与本节点相符,用于更新操作 if (preParentList != curParentList) { preParentList.removeChildTask(task); curParentList.addChildTask(task); @@ -729,7 +766,7 @@ public class GTaskManager { sqlNote.resetLocalModified(); sqlNote.commit(true); } - + // 升级远程meta private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { if (sqlNote != null && sqlNote.isNoteType()) { MetaData metaData = mMetaHashMap.get(gid); @@ -745,7 +782,7 @@ public class GTaskManager { } } } - + // 刷新本地syncid以对应更改后的对象 private void refreshLocalSyncId() throws NetworkFailureException { if (mCancelled) { return; @@ -769,8 +806,10 @@ public class GTaskManager { Node node = mGTaskHashMap.get(gid); if (node != null) { mGTaskHashMap.remove(gid); + // 在ContentValues中创建键值对。准备通过contentResolver写入数据 ContentValues values = new ContentValues(); values.put(NoteColumns.SYNC_ID, node.getLastModified()); + // 进行批量更改,选择参数为NULL,应该可以用insert替换,参数分别为表名和需要更新的value对象。 mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(SqlNote.ID_COLUMN)), values, null, null); } else { diff --git a/src/gtask/remote/GTaskSyncService.java b/src/gtask/remote/GTaskSyncService.java index cca36f7..a23452b 100644 --- a/src/gtask/remote/GTaskSyncService.java +++ b/src/gtask/remote/GTaskSyncService.java @@ -16,6 +16,23 @@ 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() 获取当前进度的信息 + */ + + import android.app.Activity; import android.app.Service; import android.content.Context; @@ -41,7 +58,7 @@ public class GTaskSyncService extends Service { private static GTaskASyncTask mSyncTask = null; private static String mSyncProgress = ""; - + // 开始进行一个同的步 private void startSync() { if (mSyncTask == null) { mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { @@ -52,6 +69,7 @@ public class GTaskSyncService extends Service { } }); sendBroadcast(""); + // 该函数主打的是一个让任务以单线程队列或者线程池队列方式运行 mSyncTask.execute(); } } @@ -63,6 +81,7 @@ public class GTaskSyncService extends Service { } @Override + // 对Service进行一个初始化 public void onCreate() { mSyncTask = null; } @@ -71,6 +90,7 @@ public class GTaskSyncService extends Service { public 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(); @@ -92,26 +112,28 @@ public class GTaskSyncService extends Service { mSyncTask.cancelSync(); } } - + // 重制客户端的服务绑定 public IBinder onBind(Intent intent) { return null; } public void sendBroadcast(String msg) { mSyncProgress = msg; + // 创建新的新意图 Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); sendBroadcast(intent); } - + // 对同步进行一个开始 public static void startSync(Activity activity) { 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) { Intent intent = new Intent(context, GTaskSyncService.class); intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); @@ -125,4 +147,4 @@ public class GTaskSyncService extends Service { public static String getProgressString() { return mSyncProgress; } -} +} \ No newline at end of file From 311f66332565d0cb753e75a6dbd73c3539fa2084 Mon Sep 17 00:00:00 2001 From: KasumizawaMiyu Date: Fri, 31 Mar 2023 17:04:16 +0800 Subject: [PATCH 2/2] =?UTF-8?q?kuso!=F0=9F=A4=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: KasumizawaMiyu --- src/data/Contact.java | 36 +++-- src/data/NotesDatabaseHelper.java | 108 ++++++------- src/data/NotesProvider.java | 147 +++++++++--------- src/gtask/data/MetaData.java | 20 +-- src/gtask/data/Node.java | 23 +-- src/gtask/data/SqlData.java | 27 ++-- src/gtask/data/SqlNote.java | 37 +++-- src/gtask/data/Task.java | 24 +-- src/gtask/data/TaskList.java | 26 ++-- .../exception/ActionFailureException.java | 4 +- .../exception/NetworkFailureException.java | 3 + src/gtask/remote/GTaskASyncTask.java | 38 ++++- src/gtask/remote/GTaskClient.java | 93 ++++++++--- src/gtask/remote/GTaskManager.java | 81 +++++++--- src/gtask/remote/GTaskSyncService.java | 32 +++- 15 files changed, 425 insertions(+), 274 deletions(-) diff --git a/src/data/Contact.java b/src/data/Contact.java index 00b51e9..94b6b45 100644 --- a/src/data/Contact.java +++ b/src/data/Contact.java @@ -25,6 +25,7 @@ import android.util.Log; import java.util.HashMap; +<<<<<<< HEAD <<<<<<< HEAD:app/src/main/java/net/micode/notes/data/Contact.java public class Contact { private static HashMap sContactCache;//建立哈希表 @@ -34,46 +35,51 @@ public class Contact {//连接类 private static HashMap sContactCache;//建立哈希表 private static final String TAG = "Contact";//设置TAG的值为'连接' >>>>>>> 0444a65d4e44c509f57ad301a5a2b59200d62177:src/data/Contact.java +======= +public class Contact { //连接类 + private static HashMap sContactCache; //定义连接哈希表 + private static final String TAG = "Contact"; //设置TAG的值为'连接' +>>>>>>> b12b9a8449498593360310c554053628b31cc8c9 private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + " AND " + Data.RAW_CONTACT_ID + " IN " + "(SELECT raw_contact_id " + " FROM phone_lookup" - + " WHERE min_match = '+')"; + + " WHERE min_match = '+')"; //SQL语句 - public static String getContact(Context context, String phoneNumber) { + public static String getContact(Context context, String phoneNumber) { //获取连接 if(sContactCache == null) { - sContactCache = new HashMap(); + sContactCache = new HashMap(); //连接哈希表为空时创建连接哈希表 } if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); + return sContactCache.get(phoneNumber); //连接哈希表存在电话号码时获取值 } String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, + PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); //将电话号码进行函数处理并代替'+'符号 + Cursor cursor = context.getContentResolver().query( //用于查询的结果集 + Data.CONTENT_URI, //通话记录uri new String [] { Phone.DISPLAY_NAME }, selection, new String[] { phoneNumber }, - null); + null); //查询指定号码相关联系人名字 if (cursor != null && cursor.moveToFirst()) { - try { - String name = cursor.getString(0); - sContactCache.put(phoneNumber, name); + try { //有结果时 + String name = cursor.getString(0); //获取联系人名字 + sContactCache.put(phoneNumber, name); //缓存电话号码与联系人名字 return name; } catch (IndexOutOfBoundsException e) { - Log.e(TAG, " Cursor get string error " + e.toString()); + Log.e(TAG, " Cursor get string error " + e.toString()); //日志记录信息 return null; } finally { - cursor.close(); + cursor.close(); //关闭结果集 } } else { - Log.d(TAG, "No contact matched with number:" + phoneNumber); - return null; + Log.d(TAG, "No contact matched with number:" + phoneNumber); //日志记录信息 + return null; //没找到,返回NULL } } } diff --git a/src/data/NotesDatabaseHelper.java b/src/data/NotesDatabaseHelper.java index ffe5d57..57805ab 100644 --- a/src/data/NotesDatabaseHelper.java +++ b/src/data/NotesDatabaseHelper.java @@ -26,23 +26,23 @@ import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; + //引入Notes中接口 +public class NotesDatabaseHelper extends SQLiteOpenHelper { //该类为便签SQL表的定义以及操作,便于进行文件夹与便签的各种操作,例如添加或删除的行为 + private static final String DB_NAME = "note.db"; //数据库名称 -public class NotesDatabaseHelper extends SQLiteOpenHelper { - private static final String DB_NAME = "note.db"; + private static final int DB_VERSION = 4; //数据库版本 - private static final int DB_VERSION = 4; + public interface TABLE { //定义一个数据库表接口 + public static final String NOTE = "note"; //便签名 - public interface TABLE { - public static final String NOTE = "note"; - - public static final String DATA = "data"; + public static final String DATA = "data"; //便签数据 } - private static final String TAG = "NotesDatabaseHelper"; + private static final String TAG = "NotesDatabaseHelper"; //日志类型 - private static NotesDatabaseHelper mInstance; + private static NotesDatabaseHelper mInstance; //创建NotesDatabaseHelper类对象 - private static final String CREATE_NOTE_TABLE_SQL = + private static final String CREATE_NOTE_TABLE_SQL = //SQL语句,创建便签表,包含ID、最后修改日期、背景颜色、便签数等在Notes类中的内容 "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + @@ -63,7 +63,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")"; - private static final String CREATE_DATA_TABLE_SQL = + private static final String CREATE_DATA_TABLE_SQL = //创建数据表的SQL语句 "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + DataColumns.MIME_TYPE + " TEXT NOT NULL," + @@ -80,7 +80,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + - TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");"; //创建查询操作表索引,用于查找 /** * Increase folder's note count when move note to the folder @@ -92,7 +92,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; + " END"; //创建触发器,方便进行操作,当移动便签时统计新的父文件夹内便签数量 /** * Decrease folder's note count when move note from folder @@ -105,7 +105,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + - " END"; + " END"; //与上一个方法作用相反,统计旧的父文件夹便签数量 /** * Increase folder's note count when insert new note to the folder @@ -117,7 +117,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + - " END"; + " END"; //创建便签时增加统计数量 /** * Decrease folder's note count when delete note from the folder @@ -130,7 +130,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0;" + - " END"; + " END"; //删除时减少数量 /** * Update note's content when insert data with type {@link DataConstants#NOTE} @@ -143,7 +143,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; + " END"; //更新便签数据时更改table表内容 /** * Update note's content when data with {@link DataConstants#NOTE} type has changed @@ -156,7 +156,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + - " END"; + " END"; //改变便签数据时更改table表内容 /** * Update note's content when data with {@link DataConstants#NOTE} type has deleted @@ -169,7 +169,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=''" + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + - " END"; + " END"; //删除便签数据时改变table表内容 /** * Delete datas belong to note which has been deleted @@ -180,7 +180,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " BEGIN" + " DELETE FROM " + TABLE.DATA + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + - " END"; + " END"; //删除便签时删除便签内容 /** * Delete notes belong to folder which has been deleted @@ -191,7 +191,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " BEGIN" + " DELETE FROM " + TABLE.NOTE + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; + " END"; //删除文件夹时删除内部的便签 /** * Move notes belong to folder which has been moved to trash folder @@ -204,20 +204,20 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + - " END"; + " END"; //移动便签的父文件夹时便签也一起更改 public NotesDatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); - } + } //创建一个数据库 public void createNoteTable(SQLiteDatabase db) { db.execSQL(CREATE_NOTE_TABLE_SQL); - reCreateNoteTableTriggers(db); - createSystemFolder(db); - Log.d(TAG, "note table has been created"); + reCreateNoteTableTriggers(db); //重新创建触发器 + createSystemFolder(db); //创建系统文件夹 + Log.d(TAG, "note table has been created"); //创建一个新的便签表,返回日志 } - private void reCreateNoteTableTriggers(SQLiteDatabase db) { + private void reCreateNoteTableTriggers(SQLiteDatabase db) { //数据库对象DB db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update"); db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete"); @@ -233,17 +233,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER); db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER); db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER); - } + } //用于执行SQL语句,运行重新创建便签表触发器函数 - private void createSystemFolder(SQLiteDatabase db) { - ContentValues values = new ContentValues(); + private void createSystemFolder(SQLiteDatabase db) { //创建系统级文件夹 + ContentValues values = new ContentValues(); //为字典类创建对象 /** * call record foler for call notes */ values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //为通讯便签创建记录文件夹,并添加键值对 /** * root folder which is default folder @@ -251,7 +251,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.clear(); values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //创建根文件夹,是默认的、最终的父文件夹 /** * temporary folder which is used for moving note @@ -259,7 +259,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.clear(); values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //为移动中的便签创建的临时文件夹 /** * create trash folder @@ -267,24 +267,24 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.clear(); values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); - db.insert(TABLE.NOTE, null, values); + db.insert(TABLE.NOTE, null, values); //创建垃圾桶 } - public void createDataTable(SQLiteDatabase db) { - db.execSQL(CREATE_DATA_TABLE_SQL); + public void createDataTable(SQLiteDatabase db) { //创建数据表 + db.execSQL(CREATE_DATA_TABLE_SQL); //SQL输入保存的语句 reCreateDataTableTriggers(db); db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL); - Log.d(TAG, "data table has been created"); + Log.d(TAG, "data table has been created"); //日志记录 } - private void reCreateDataTableTriggers(SQLiteDatabase db) { + private void reCreateDataTableTriggers(SQLiteDatabase db) { //为数据表重新创建触发器 db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update"); - db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); + db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete"); //删除触发器 db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER); db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER); - db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); + db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER); //重新创建被删除的触发器 } static synchronized NotesDatabaseHelper getInstance(Context context) { @@ -292,16 +292,16 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { mInstance = new NotesDatabaseHelper(context); } return mInstance; - } + } //静态同步方法,用于返回NotesDatabaseHelper的对象实例mInstance @Override public void onCreate(SQLiteDatabase db) { - createNoteTable(db); - createDataTable(db); - } + createNoteTable(db); //创建便签表 + createDataTable(db); //创建数据表 + } //用于初始化表 @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { //用于检查并升级数据库版本 boolean reCreateTriggers = false; boolean skipV2 = false; @@ -309,31 +309,31 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { upgradeToV2(db); skipV2 = true; // this upgrade including the upgrade from v2 to v3 oldVersion++; - } + } //检测到版本为1,升级版本 if (oldVersion == 2 && !skipV2) { upgradeToV3(db); - reCreateTriggers = true; - oldVersion++; + reCreateTriggers = true; //重建触发器标志 + oldVersion++; //检测到版本为2,升级版本 } if (oldVersion == 3) { upgradeToV4(db); oldVersion++; - } + } //检测到版本为3,升级版本 if (reCreateTriggers) { reCreateNoteTableTriggers(db); reCreateDataTableTriggers(db); - } + } //进行触发器的重建 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion - + "fails"); + + "fails"); //版本不匹配则抛出异常 } } - private void upgradeToV2(SQLiteDatabase db) { + private void upgradeToV2(SQLiteDatabase db) { //升级版本并重建表 db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); createNoteTable(db); @@ -353,10 +353,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER); values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); db.insert(TABLE.NOTE, null, values); - } + } //删除不用的触发器,并添加不为空的新列,添加键值对 private void upgradeToV4(SQLiteDatabase db) { db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0"); - } + } //添加新的不为空的列 } diff --git a/src/data/NotesProvider.java b/src/data/NotesProvider.java index edb0a60..9ae1528 100644 --- a/src/data/NotesProvider.java +++ b/src/data/NotesProvider.java @@ -36,22 +36,22 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE; public class NotesProvider extends ContentProvider { - private static final UriMatcher mMatcher; + private static final UriMatcher mMatcher; //UriMatcher类用于分辨数据表 - private NotesDatabaseHelper mHelper; + private NotesDatabaseHelper mHelper; //建立NotesDatabaseHelper类对象 - private static final String TAG = "NotesProvider"; + private static final String TAG = "NotesProvider"; //设置类名值 - private static final int URI_NOTE = 1; + private static final int URI_NOTE = 1; //设置便签uri private static final int URI_NOTE_ITEM = 2; - private static final int URI_DATA = 3; + private static final int URI_DATA = 3; //设置数据uri private static final int URI_DATA_ITEM = 4; - private static final int URI_SEARCH = 5; + private static final int URI_SEARCH = 5; //设置搜索uri private static final int URI_SEARCH_SUGGEST = 6; static { - mMatcher = new UriMatcher(UriMatcher.NO_MATCH); + mMatcher = new UriMatcher(UriMatcher.NO_MATCH); //进行初始化 mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); @@ -59,48 +59,48 @@ public class NotesProvider extends ContentProvider { mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); - } + } //将不同的uri与数值相匹配 /** * x'0A' represents the '\n' character in sqlite. For title and content in the search result, * we will trim '\n' and white space in order to show more information. - */ + */ //用0A代表\n,为搜索结果换行 private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," - + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; //... private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER - + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; //检索便签的sql语句,在列表中搜寻。使用Notes类中的接口与变量 @Override public boolean onCreate() { mHelper = NotesDatabaseHelper.getInstance(getContext()); - return true; + return true; //创建NotesDatabaseHelper类并返回成果标识 } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { - Cursor c = null; - SQLiteDatabase db = mHelper.getReadableDatabase(); + String sortOrder) { //负责查询数据,接受uri、返回烈、选择、排列方式 + Cursor c = null; //创建空游标,表示数据库操作结果集合 + SQLiteDatabase db = mHelper.getReadableDatabase(); //获取数据库对象 String id = null; - switch (mMatcher.match(uri)) { + switch (mMatcher.match(uri)) { //确定uri类型 case URI_NOTE: c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, - sortOrder); + sortOrder); //传参,进行标准查询 break; case URI_NOTE_ITEM: id = uri.getPathSegments().get(1); c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); - break; + break; //传参,对id进行查询 case URI_DATA: c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder); @@ -112,13 +112,13 @@ public class NotesProvider extends ContentProvider { break; case URI_SEARCH: case URI_SEARCH_SUGGEST: - if (sortOrder != null || projection != null) { + if (sortOrder != null || projection != null) { //检查是否指定排序方式 throw new IllegalArgumentException( "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); } String searchString = null; - if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { + if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { //提取uri中搜索模式 if (uri.getPathSegments().size() > 1) { searchString = uri.getPathSegments().get(1); } @@ -133,43 +133,43 @@ public class NotesProvider extends ContentProvider { try { searchString = String.format("%%%s%%", searchString); c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, - new String[] { searchString }); + new String[] { searchString }); //在Notes表进行搜索 } catch (IllegalStateException ex) { - Log.e(TAG, "got exception: " + ex.toString()); + Log.e(TAG, "got exception: " + ex.toString()); //日志 } break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); //抛出异常 } if (c != null) { - c.setNotificationUri(getContext().getContentResolver(), uri); - } + c.setNotificationUri(getContext().getContentResolver(), uri); //在游标查询的数据变化时进行通知 + } //通知uri是标识查询结果的uri,setNotificationUri方法可注册通知uri,与对象c相关联 return c; } @Override - public Uri insert(Uri uri, ContentValues values) { - SQLiteDatabase db = mHelper.getWritableDatabase(); + public Uri insert(Uri uri, ContentValues values) { //uri表示要插入的uri,values表示要插入的数据 + SQLiteDatabase db = mHelper.getWritableDatabase(); //打开或创建一个数据库 long dataId = 0, noteId = 0, insertedId = 0; - switch (mMatcher.match(uri)) { + switch (mMatcher.match(uri)) { //匹配uri case URI_NOTE: - insertedId = noteId = db.insert(TABLE.NOTE, null, values); + insertedId = noteId = db.insert(TABLE.NOTE, null, values); //将数据插入到Notes表中 break; case URI_DATA: - if (values.containsKey(DataColumns.NOTE_ID)) { - noteId = values.getAsLong(DataColumns.NOTE_ID); + if (values.containsKey(DataColumns.NOTE_ID)) { //检查values是否含有NOTE_ID内容,返回bool值 + noteId = values.getAsLong(DataColumns.NOTE_ID); //关联noteId } else { - Log.d(TAG, "Wrong data format without note id:" + values.toString()); + Log.d(TAG, "Wrong data format without note id:" + values.toString()); //日志记录 } - insertedId = dataId = db.insert(TABLE.DATA, null, values); + insertedId = dataId = db.insert(TABLE.DATA, null, values); //数据库插入新行的id返回到两个变量中 break; default: throw new IllegalArgumentException("Unknown URI " + uri); } // Notify the note uri - if (noteId > 0) { + if (noteId > 0) { //不为零表示插入成功, getContext().getContentResolver().notifyChange( - ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); //通知uri发生变化 } // Notify the data uri @@ -178,22 +178,22 @@ public class NotesProvider extends ContentProvider { ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); } - return ContentUris.withAppendedId(uri, insertedId); + return ContentUris.withAppendedId(uri, insertedId); //返回新的uri,表示插入位置 } @Override - public int delete(Uri uri, String selection, String[] selectionArgs) { - int count = 0; + public int delete(Uri uri, String selection, String[] selectionArgs) { //表示要删除的uri、SQL中的WHERE与参数 + int count = 0; //表示删除记录数 String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); + SQLiteDatabase db = mHelper.getWritableDatabase(); //打开数据库 boolean deleteData = false; - switch (mMatcher.match(uri)) { + switch (mMatcher.match(uri)) { //uri匹配 case URI_NOTE: - selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; - count = db.delete(TABLE.NOTE, selection, selectionArgs); + selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; //设置WHERE + count = db.delete(TABLE.NOTE, selection, selectionArgs); //删除,并计数 break; case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); + id = uri.getPathSegments().get(1); //获取id /** * ID that smaller than 0 is system folder which is not allowed to * trash @@ -204,45 +204,45 @@ public class NotesProvider extends ContentProvider { } count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - break; + break; //删除指定id,并计数 case URI_DATA: - count = db.delete(TABLE.DATA, selection, selectionArgs); + count = db.delete(TABLE.DATA, selection, selectionArgs); //删除,并计数 deleteData = true; break; case URI_DATA_ITEM: - id = uri.getPathSegments().get(1); + id = uri.getPathSegments().get(1); //获取id count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); - deleteData = true; + deleteData = true; //删除指定id,并计数 break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); //报错 } - if (count > 0) { + if (count > 0) { //表示有删除操作,通知uri发生变化 if (deleteData) { getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } getContext().getContentResolver().notifyChange(uri, null); } - return count; + return count; //返回删除的记录数 } @Override - public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - int count = 0; + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { //表示更新的uri、values为新的列值、where以及参数 + int count = 0; //更新条数 String id = null; - SQLiteDatabase db = mHelper.getWritableDatabase(); - boolean updateData = false; - switch (mMatcher.match(uri)) { + SQLiteDatabase db = mHelper.getWritableDatabase(); //打开数据库 + boolean updateData = false; //设置数据表更新表示 + switch (mMatcher.match(uri)) { //匹配uri case URI_NOTE: - increaseNoteVersion(-1, selection, selectionArgs); - count = db.update(TABLE.NOTE, values, selection, selectionArgs); + increaseNoteVersion(-1, selection, selectionArgs); //跟新便签 + count = db.update(TABLE.NOTE, values, selection, selectionArgs); //更新指定表的行,并计数 break; case URI_NOTE_ITEM: - id = uri.getPathSegments().get(1); + id = uri.getPathSegments().get(1); //提取id increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id - + parseSelection(selection), selectionArgs); + + parseSelection(selection), selectionArgs); //增加指定的id条件 break; case URI_DATA: count = db.update(TABLE.DATA, values, selection, selectionArgs); @@ -255,51 +255,50 @@ public class NotesProvider extends ContentProvider { updateData = true; break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri); //抛出异常 } if (count > 0) { if (updateData) { - getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); + getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);//通知指定uri数据更改 } - getContext().getContentResolver().notifyChange(uri, null); + getContext().getContentResolver().notifyChange(uri, null); //通知uri数据更改 } return count; } - private String parseSelection(String selection) { - return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); + private String parseSelection(String selection) { //检查selection是否为空 + return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); //为空则返回“” } - private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { + private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { //使用数据库更新便签版本 StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); sql.append(TABLE.NOTE); sql.append(" SET "); sql.append(NoteColumns.VERSION); - sql.append("=" + NoteColumns.VERSION + "+1 "); + sql.append("=" + NoteColumns.VERSION + "+1 "); //升级便签版本号 - if (id > 0 || !TextUtils.isEmpty(selection)) { + if (id > 0 || !TextUtils.isEmpty(selection)) { //selection不为空或存在id则增加where条件 sql.append(" WHERE "); } if (id > 0) { sql.append(NoteColumns.ID + "=" + String.valueOf(id)); } if (!TextUtils.isEmpty(selection)) { - String selectString = id > 0 ? parseSelection(selection) : selection; - for (String args : selectionArgs) { - selectString = selectString.replaceFirst("\\?", args); + String selectString = id > 0 ? parseSelection(selection) : selection; //parseSelection将传入的参数中的占位符替换为实际的值 + for (String args : selectionArgs) { // + selectString = selectString.replaceFirst("\\?", args); //replaceFirst选择参数数组中的值替换语句中的占位符 } sql.append(selectString); } - mHelper.getWritableDatabase().execSQL(sql.toString()); + mHelper.getWritableDatabase().execSQL(sql.toString()); //执行SQL语句 } @Override - public String getType(Uri uri) { - // TODO Auto-generated method stub + public String getType(Uri uri) { //获取指定uri的MIME类型 + // TODO Auto-generated method stub //表示该方法没有实现 return null; } - } diff --git a/src/gtask/data/MetaData.java b/src/gtask/data/MetaData.java index 3a2050b..c4683e4 100644 --- a/src/gtask/data/MetaData.java +++ b/src/gtask/data/MetaData.java @@ -24,31 +24,33 @@ import net.micode.notes.tool.GTaskStringUtils; import org.json.JSONException; import org.json.JSONObject; - public class MetaData extends Task { - private final static String TAG = MetaData.class.getSimpleName(); + // 通过getSimpleName()获得类的gid并存入字符串中 + private final static String TAG = MetaData.class.getSimpleName(); private String mRelatedGid = null; - + // 设置元数据,生成元数据库 public void setMeta(String gid, JSONObject metaInfo) { try { + // 注释方法块 metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); } catch (JSONException e) { + // 生成无法创建关联gid的日志 Log.e(TAG, "failed to put related gid"); } setNotes(metaInfo.toString()); setName(GTaskStringUtils.META_NOTE_NAME); } - + // 获取关联的gid public String getRelatedGid() { return mRelatedGid; } - + // 判断数据是否为空是否值得保存 @Override public boolean isWorthSaving() { return getNotes() != null; } - + // 使用远程json设置元数据内容 @Override public void setContentByRemoteJSON(JSONObject js) { super.setContentByRemoteJSON(js); @@ -62,18 +64,18 @@ public class MetaData extends Task { } } } - + // 使用本地json对象设置数据内容,该方法不应该被调用,若调用则抛出异常 @Override public void setContentByLocalJSON(JSONObject js) { // this function should not be called throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); } - + // 从元数据中获取本地json对象,该方法不应该被调用,若调用则抛出异常 @Override public JSONObject getLocalJSONFromContent() { throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); } - + // 获取同步动作状态,该方法不应该被调用,若调用则抛出异常 @Override public int getSyncAction(Cursor c) { throw new IllegalAccessError("MetaData:getSyncAction should not be called"); diff --git a/src/gtask/data/Node.java b/src/gtask/data/Node.java index 63950e0..1484c14 100644 --- a/src/gtask/data/Node.java +++ b/src/gtask/data/Node.java @@ -19,32 +19,33 @@ package net.micode.notes.gtask.data; import android.database.Cursor; import org.json.JSONObject; - +// 对同步操作的基本节点进行一个定义 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() { diff --git a/src/gtask/data/SqlData.java b/src/gtask/data/SqlData.java index d3ec3be..72ba013 100644 --- a/src/gtask/data/SqlData.java +++ b/src/gtask/data/SqlData.java @@ -13,7 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +// Description:用于支持小米便签最底层的数据库相关操作,和sqlnote的关系上是子集关系,即data是note的子集(节点)。 +// SqlData其实就是也就是所谓数据中的数据 package net.micode.notes.gtask.data; import android.content.ContentResolver; @@ -34,17 +35,17 @@ import net.micode.notes.gtask.exception.ActionFailureException; import org.json.JSONException; import org.json.JSONObject; - public class SqlData { + // 将得到的内容写入字符串tag中 private static final String TAG = SqlData.class.getSimpleName(); - + // 设置无效id为-99999 private static final int INVALID_ID = -99999; - + // 集合interface DataColumns中所有sf常量 public static final String[] PROJECTION_DATA = new String[] { DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, DataColumns.DATA3 }; - + // 为sql表编号 public static final int DATA_ID_COLUMN = 0; public static final int DATA_MIME_TYPE_COLUMN = 1; @@ -56,7 +57,7 @@ public class SqlData { public static final int DATA_CONTENT_DATA_3_COLUMN = 4; private ContentResolver mContentResolver; - + // 判断是否用content生成,真为true,假为false private boolean mIsCreate; private long mDataId; @@ -70,7 +71,7 @@ public class SqlData { private String mDataContentData3; private ContentValues mDiffDataValues; - + // 初始化数据库的构造函数 public SqlData(Context context) { mContentResolver = context.getContentResolver(); mIsCreate = true; @@ -81,14 +82,14 @@ public class SqlData { mDataContentData3 = ""; mDiffDataValues = new ContentValues(); } - + // 初始化数据库的构造函数 public SqlData(Context context, Cursor c) { mContentResolver = context.getContentResolver(); mIsCreate = false; loadFromCursor(c); mDiffDataValues = new ContentValues(); } - + // 从游标处加载数据 private void loadFromCursor(Cursor c) { mDataId = c.getLong(DATA_ID_COLUMN); mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); @@ -96,7 +97,7 @@ public class SqlData { mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); } - + // 设置用于共享的数据 public void setContent(JSONObject js) throws JSONException { long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; if (mIsCreate || mDataId != dataId) { @@ -129,7 +130,7 @@ public class SqlData { } mDataContentData3 = dataContentData3; } - + // 获取共享数据的内容 public JSONObject getContent() throws JSONException { if (mIsCreate) { Log.e(TAG, "it seems that we haven't created this in database yet"); @@ -143,7 +144,7 @@ public class SqlData { js.put(DataColumns.DATA3, mDataContentData3); return js; } - + // 提交更改至数据库 public void commit(long noteId, boolean validateVersion, long version) { if (mIsCreate) { @@ -182,7 +183,7 @@ public class SqlData { mDiffDataValues.clear(); mIsCreate = false; } - + // 获取当前id public long getId() { return mDataId; } diff --git a/src/gtask/data/SqlNote.java b/src/gtask/data/SqlNote.java index 79a4095..be42a61 100644 --- a/src/gtask/data/SqlNote.java +++ b/src/gtask/data/SqlNote.java @@ -37,12 +37,15 @@ import org.json.JSONObject; import java.util.ArrayList; +// 用于支持小米便签最底层的数据库相关操作,和sqldata的关系上是父集关系,即note是data的子父集 +// 和SqlData相比SqlNote算是真正意义上的数据 public class SqlNote { + // 得到的类名写入tag中 private static final String TAG = SqlNote.class.getSimpleName(); private static final int INVALID_ID = -99999; - + // 集合了interface NoteColumns中所有SF常量 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, @@ -121,7 +124,7 @@ public class SqlNote { private ContentValues mDiffNoteValues; private ArrayList mDataList; - + // 构造函数,初始化context参数 public SqlNote(Context context) { mContext = context; mContentResolver = context.getContentResolver(); @@ -142,7 +145,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); mDataList = new ArrayList(); } - + // 通过游标初始化context public SqlNote(Context context, Cursor c) { mContext = context; mContentResolver = context.getContentResolver(); @@ -165,7 +168,7 @@ public class SqlNote { mDiffNoteValues = new ContentValues(); } - + // 从游标加载数据 private void loadFromCursor(long id) { Cursor c = null; try { @@ -184,7 +187,7 @@ public class SqlNote { c.close(); } } - + // 从游标加载数据 private void loadFromCursor(Cursor c) { mId = c.getLong(ID_COLUMN); mAlertDate = c.getLong(ALERTED_DATE_COLUMN); @@ -199,7 +202,7 @@ public class SqlNote { mWidgetType = c.getInt(WIDGET_TYPE_COLUMN); mVersion = c.getLong(VERSION_COLUMN); } - + // 获取共享数据并加载到数据库当前游标处 private void loadDataContent() { Cursor c = null; mDataList.clear(); @@ -225,7 +228,7 @@ public class SqlNote { c.close(); } } - + // 设置通过content机制用于共享的数据信息 public boolean setContent(JSONObject js) { try { JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); @@ -358,7 +361,7 @@ public class SqlNote { } return true; } - + // 获取content机制提供的数据并加载到note中 public JSONObject getContent() { try { JSONObject js = new JSONObject(); @@ -406,40 +409,40 @@ public class SqlNote { } return null; } - + //给当前id设置父id public void setParentId(long id) { mParentId = id; mDiffNoteValues.put(NoteColumns.PARENT_ID, id); } - + // 给当前id设置Gtaskid public void setGtaskId(String gid) { mDiffNoteValues.put(NoteColumns.GTASK_ID, gid); } - + // 给当前id设置同步id public void setSyncId(long syncId) { mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId); } - + // 初始化本地修改,即撤销 public void resetLocalModified() { mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0); } - + // 获得当前id public long getId() { return mId; } - + // 获得id的父id public long getParentId() { return mParentId; } - + // 获取小部分内容以显示部分便签内容 public String getSnippet() { return mSnippet; } - + // 判断是否为便签类型 public boolean isNoteType() { return mType == Notes.TYPE_NOTE; } - + // 提交更改到数据库 public void commit(boolean validateVersion) { if (mIsCreate) { if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) { diff --git a/src/gtask/data/Task.java b/src/gtask/data/Task.java index 6a19454..58097db 100644 --- a/src/gtask/data/Task.java +++ b/src/gtask/data/Task.java @@ -34,17 +34,17 @@ import org.json.JSONObject; 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; - + // 父类指针 private TaskList mParent; - + // 初始化构造方法 public Task() { super(); mCompleted = false; @@ -53,7 +53,7 @@ public class Task extends Node { mParent = null; mMetaInfo = null; } - + // 用于创建jsonobject对象,获取创建新行为的操作 public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -102,7 +102,7 @@ public class Task extends Node { return js; } - + // 用于创建jsonobject对象,实现创建更新行为的操作 public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -134,7 +134,7 @@ public class Task extends Node { return js; } - + // 用于从远端目录创建 public void setContentByRemoteJSON(JSONObject js) { if (js != null) { try { @@ -174,7 +174,7 @@ public class Task extends Node { } } } - + // 本地创建 public void setContentByLocalJSON(JSONObject js) { if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE) || !js.has(GTaskStringUtils.META_HEAD_DATA)) { @@ -203,7 +203,7 @@ public class Task extends Node { e.printStackTrace(); } } - + // 从目录获取本地json public JSONObject getLocalJSONFromContent() { String name = getName(); try { @@ -246,7 +246,7 @@ public class Task extends Node { return null; } } - + // 设置meta信息 public void setMetaInfo(MetaData metaData) { if (metaData != null && metaData.getNotes() != null) { try { @@ -257,7 +257,7 @@ public class Task extends Node { } } } - + // 获取同步行为 public int getSyncAction(Cursor c) { try { JSONObject noteInfo = null; diff --git a/src/gtask/data/TaskList.java b/src/gtask/data/TaskList.java index 4ea21c5..5f48d1d 100644 --- a/src/gtask/data/TaskList.java +++ b/src/gtask/data/TaskList.java @@ -32,9 +32,9 @@ import java.util.ArrayList; public class TaskList extends Node { private static final String TAG = TaskList.class.getSimpleName(); - + // 当前TaskList的指针 private int mIndex; - + // 类中主要的保存数据的单元,用来实现一个以Task为元素的ArrayList private ArrayList mChildren; public TaskList() { @@ -42,7 +42,7 @@ public class TaskList extends Node { mChildren = new ArrayList(); mIndex = 1; } - + // 生成并返回一个包含了一定数据的JSONObject实体 public JSONObject getCreateAction(int actionId) { JSONObject js = new JSONObject(); @@ -73,7 +73,7 @@ public class TaskList extends Node { return js; } - + // 更新一个包含了一定数据的JSONObject实体 public JSONObject getUpdateAction(int actionId) { JSONObject js = new JSONObject(); @@ -215,11 +215,11 @@ public class TaskList extends Node { return SYNC_ACTION_ERROR; } - + // 获得TaskList的大小 public int getChildTaskCount() { return mChildren.size(); } - + // 在当前任务表末尾添加新的任务 public boolean addChildTask(Task task) { boolean ret = false; if (task != null && !mChildren.contains(task)) { @@ -233,7 +233,7 @@ public class TaskList extends Node { } return ret; } - + // 在当前任务表的指定位置添加新的任务 public boolean addChildTask(Task task, int index) { if (index < 0 || index > mChildren.size()) { Log.e(TAG, "add child task: invalid index"); @@ -259,7 +259,7 @@ public class TaskList extends Node { return true; } - + // 删除TaskList中的一个Task public boolean removeChildTask(Task task) { boolean ret = false; int index = mChildren.indexOf(task); @@ -280,7 +280,7 @@ public class TaskList extends Node { } return ret; } - + // 移动TaskList中的一个Task public boolean moveChildTask(Task task, int index) { if (index < 0 || index >= mChildren.size()) { @@ -298,7 +298,7 @@ public class TaskList extends Node { return true; return (removeChildTask(task) && addChildTask(task, index)); } - + // 按gid寻找Task public Task findChildTaskByGid(String gid) { for (int i = 0; i < mChildren.size(); i++) { Task t = mChildren.get(i); @@ -308,11 +308,11 @@ public class TaskList extends Node { } return null; } - + // 返回指定Task的index public int getChildTaskIndex(Task task) { return mChildren.indexOf(task); } - + // 返回指定index的Task public Task getChildTaskByIndex(int index) { if (index < 0 || index >= mChildren.size()) { Log.e(TAG, "getTaskByIndex: invalid index"); @@ -320,7 +320,7 @@ public class TaskList extends Node { } return mChildren.get(index); } - + // 返回指定gid的task public Task getChilTaskByGid(String gid) { for (Task task : mChildren) { if (task.getGid().equals(gid)) diff --git a/src/gtask/exception/ActionFailureException.java b/src/gtask/exception/ActionFailureException.java index 15504be..7787d25 100644 --- a/src/gtask/exception/ActionFailureException.java +++ b/src/gtask/exception/ActionFailureException.java @@ -14,15 +14,17 @@ * limitations under the License. */ +// 小米便签运行过程中的运行异常处理 package net.micode.notes.gtask.exception; public class ActionFailureException extends RuntimeException { + // 版本控制用,反序列化版本升级时仍保持对象唯一性 private static final long serialVersionUID = 4425249765923293627L; + // 通过super()来引用父类成分 public ActionFailureException() { super(); } - public ActionFailureException(String paramString) { super(paramString); } diff --git a/src/gtask/exception/NetworkFailureException.java b/src/gtask/exception/NetworkFailureException.java index b08cfb1..6f67afe 100644 --- a/src/gtask/exception/NetworkFailureException.java +++ b/src/gtask/exception/NetworkFailureException.java @@ -14,11 +14,14 @@ * limitations under the License. */ +// 运行过程中的网络异常处理 package net.micode.notes.gtask.exception; public class NetworkFailureException extends Exception { + // 版本控制用,反序列化版本升级时仍保持对象唯一性 private static final long serialVersionUID = 2107610287180234136L; + // 通过super()来引用父类成分 public NetworkFailureException() { super(); } diff --git a/src/gtask/remote/GTaskASyncTask.java b/src/gtask/remote/GTaskASyncTask.java index b3b61e7..7981605 100644 --- a/src/gtask/remote/GTaskASyncTask.java +++ b/src/gtask/remote/GTaskASyncTask.java @@ -15,6 +15,14 @@ * limitations under the License. */ +/* + *异步操作类,实现Gtask异步操作过程 + *主要方法: + *private void showNotification(int tickerId, String content) 用于为用户同步当前事件状态 + *protected Integer doInBackground(Void... unused) 后台线程执行,完成任务主要工作 + *protected void onProgressUpdate(String... progress) 主线程运行,以进度条显示用户工作完成状态 + *protected void onPostExecute(Integer result) 更新UI + */ package net.micode.notes.gtask.remote; import android.app.Notification; @@ -44,7 +52,7 @@ public class GTaskASyncTask extends AsyncTask { private GTaskManager mTaskManager; private OnCompleteListener mOnCompleteListener; - + // GTask的一个同步进程类,包含上下文信息,事件完成进度监听方法,通知管理方法,和进程管理方法 public GTaskASyncTask(Context context, OnCompleteListener listener) { mContext = context; mOnCompleteListener = listener; @@ -52,56 +60,70 @@ public class GTaskASyncTask extends AsyncTask { .getSystemService(Context.NOTIFICATION_SERVICE); mTaskManager = GTaskManager.getInstance(); } - + //取消同步 public void cancelSync() { mTaskManager.cancelSync(); } - + // 发布并更新事件处理进程 public void publishProgess(String message) { 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; + // 同步失败挂起活动信息 if (tickerId != R.string.ticker_success) { pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); - + // 同步成功显示活动信息列表 } else { + pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), 0); } - notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, - pendingIntent); + // 该方法疑似为设置显示最新事件信息,但运行时编译器报错,暂时注释以规避报错选项 + /*notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, + pendingIntent);*/ + // mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } @Override protected Integer doInBackground(Void... unused) { + //利用getString将NotesPreferenceActivity.getSyncAccountName(mContext)的字符串内容 + //传进sync_progress_login中 publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity .getSyncAccountName(mContext))); + //返回后台同步的具体操作 return mTaskManager.sync(mContext, this); } @Override protected void onProgressUpdate(String... progress) { showNotification(R.string.ticker_syncing, progress[0]); + //判断mContext是否为GTaskSyncService的实例 if (mContext instanceof GTaskSyncService) { ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } @Override + //后台运行完后更新ui,显示更新后结果 protected void onPostExecute(Integer result) { 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)); @@ -111,9 +133,11 @@ public class GTaskASyncTask extends AsyncTask { showNotification(R.string.ticker_cancel, mContext .getString(R.string.error_sync_cancelled)); } + //不同状态下的结果显示 if (mOnCompleteListener != null) { + //新增可运行线程 new Thread(new Runnable() { - + //线程运行,初始化操作 public void run() { mOnCompleteListener.onComplete(); } diff --git a/src/gtask/remote/GTaskClient.java b/src/gtask/remote/GTaskClient.java index c67dfdf..fee4803 100644 --- a/src/gtask/remote/GTaskClient.java +++ b/src/gtask/remote/GTaskClient.java @@ -60,10 +60,13 @@ import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; - +/* + *实现GTask登录操作,创建GTask任务,与谷歌服务联网获取任务和任务列表 + *主要用类:accountManager JSONObject HttpParams authToken Gid + */ public class GTaskClient { private static final String TAG = GTaskClient.class.getSimpleName(); - + //指定登录URL地址 private static final String GTASK_URL = "https://mail.google.com/tasks/"; private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; @@ -89,7 +92,7 @@ public class GTaskClient { private Account mAccount; private JSONArray mUpdateArray; - + // 创建GTask构造方法 private GTaskClient() { mHttpClient = null; mGetUrl = GTASK_GET_URL; @@ -101,35 +104,38 @@ public class GTaskClient { mAccount = null; mUpdateArray = null; } - + // 实例化并锁定GTaskClient,使用getInstance()返回mInstance public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); } return mInstance; } - + // 用于实现登录操作的布尔方法,提供了账号URL密码登录和谷歌官方邮箱URL登录两种登陆方法 public boolean login(Activity activity) { // we suppose that the cookie would expire after 5 minutes // then we need to re-login + // 五分钟后需要重新登录 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(); + // 返回的Token为空则登陆失败 String authToken = loginGoogleAccount(activity, false); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -137,6 +143,7 @@ public class GTaskClient { } // 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/"); @@ -152,6 +159,7 @@ public class GTaskClient { } // try to login with google official url + // 调取谷歌邮箱官方URL登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -163,25 +171,30 @@ public class GTaskClient { mLoggedin = true; return true; } - + // 实现谷歌登录的方法,以AccountManager管理账号,Token登录 private String loginGoogleAccount(Activity activity, boolean invalidateToken) { + // 登录Token String authToken; + // 账号管理,提供账号注册接口 AccountManager accountManager = AccountManager.get(activity); + // 获取以com.google结尾的账号列表 Account[] accounts = accountManager.getAccountsByType("com.google"); - + // 如果账号长度为空则返回无可用账号 if (accounts.length == 0) { Log.e(TAG, "there is no available google account"); return null; } - + // 获取账户名称 String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; + // 遍历返回的账户信息,寻找记录的账户信息 for (Account a : accounts) { if (a.name.equals(accountName)) { account = a; break; } } + if (account != null) { mAccount = account; } else { @@ -190,11 +203,13 @@ public class GTaskClient { } // get the token now + // 取得登录Token AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { Bundle authTokenBundle = accountManagerFuture.getResult(); authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); + // 若Token无效,则通过invalidateAuthToken方法废除该Token if (invalidateToken) { accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); @@ -206,11 +221,12 @@ public class GTaskClient { return authToken; } - + // 尝试登录的布尔方法需要预先判断Token是否有效 private boolean tryToLoginGtask(Activity activity, String authToken) { if (!loginGtask(authToken)) { // maybe the auth token is out of date, now let's invalidate the // token and try again + // 若Token则废弃Token且重试 authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -224,26 +240,35 @@ public class GTaskClient { } return true; } - + // 登录GTask具体操作 private boolean loginGtask(String authToken) { int timeoutConnection = 10000; + // socket为一种通信数据交换的端口 int timeoutSocket = 15000; + // 实现一个新的HTTP参数类 HttpParams httpParameters = new BasicHttpParams(); + // 设置链接超时时间 HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); + // 设置设置端口超时时间 HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); mHttpClient = new DefaultHttpClient(httpParameters); + // 存储新的本地cookie BasicCookieStore localBasicCookieStore = new BasicCookieStore(); mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); // login gtask + // 登录GTask具体操作 try { + // 设置登录URL String loginUrl = mGetUrl + "?auth=" + authToken; + // 通过已实例化URL网页中的资源查找 HttpGet httpGet = new HttpGet(loginUrl); HttpResponse response = null; response = mHttpClient.execute(httpGet); // get the cookie now + // 遍历已存储的cookie以验证是否与登录cookie相符,若相符则匹配 List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -256,6 +281,7 @@ public class GTaskClient { } // get the client version + // 以脚本获取返回的Content中GTask_Url的内容 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -273,40 +299,47 @@ public class GTaskClient { return false; } catch (Exception e) { // simply catch all exceptions + // 仅捕获到异常则返回捕获失败 Log.e(TAG, "httpget gtask_url failed"); return false; } return true; } - + // 获取行为ID private int getActionId() { return mActionId++; } + // 实例化创建用于网络传输的对向,使用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; } - + // 获取响应的资源目录 private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; + // 荣国URL获得HttpEntity对象,若返回值不为空,则创建数据流获取返回对象 if (entity.getContentEncoding() != null) { contentEncoding = entity.getContentEncoding().getValue(); Log.d(TAG, "encoding: " + contentEncoding); } InputStream input = entity.getContent(); + // Gzip为使用DEFLATE压缩数据的另一个压缩库 if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { input = new GZIPInputStream(entity.getContent()); - } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { + } + // Deflate为一个无专利的无损数据压缩算法 + else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("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(); @@ -322,7 +355,10 @@ public class GTaskClient { input.close(); } } - + /* + * 以json发送请求,请求的内容在json中的实例化对象传入,利用json获取task中内容 + * 并创捷对应jspost,利用postrequest得到返回的任务信息并用task_setGid设置task的新id + */ private JSONObject postRequest(JSONObject js) throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -360,6 +396,8 @@ public class GTaskClient { } } + // 创建单个任务,传入task类的对象、使用json获取task中的内容,并创建相应的jspost,利用postRequest获得任务返回信 + // 息并且使用task.setGid设置task的new_id public void createTask(Task task) throws NetworkFailureException { commitUpdate(); try { @@ -385,7 +423,7 @@ public class GTaskClient { throw new ActionFailureException("create task: handing jsonobject failed"); } } - + // 创建任务列表,设置tasklist_Gid public void createTaskList(TaskList tasklist) throws NetworkFailureException { commitUpdate(); try { @@ -411,7 +449,8 @@ public class GTaskClient { 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 { @@ -432,7 +471,7 @@ public class GTaskClient { } } } - + // 添加更新事项,通过调用 commitUpdate()实现 public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { // too many update items may result in an error @@ -446,7 +485,9 @@ public class GTaskClient { mUpdateArray.put(node.getUpdateAction(getActionId())); } } - + // 移动task至不同的任务列表中去,通过getgid获取所属不同任务列表的gid,通过 + // JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的 + // 最后通过postRequest进行更新后的任务列表的发送 public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { commitUpdate(); @@ -463,6 +504,7 @@ public class GTaskClient { 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()); @@ -472,6 +514,7 @@ public class GTaskClient { action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } actionList.put(action); + //最后将ACTION_LIST加入到jsPost中 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // client_version @@ -486,6 +529,7 @@ public class GTaskClient { } } + //删除操作节点,利用JSON,删除后使用postRequest发送删除后的结果 public void deleteNode(Node node) throws NetworkFailureException { commitUpdate(); try { @@ -494,6 +538,7 @@ public class GTaskClient { // action_list node.setDeleted(true); + // 这里会获取到删除操作的ID,加入到actionLiast中 actionList.put(node.getUpdateAction(getActionId())); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); @@ -508,7 +553,8 @@ public class GTaskClient { throw new ActionFailureException("delete node: handing jsonobject failed"); } } - + //获取任务列表,首先通过GetURL使用getResponseContent联网获取数据,然后筛选出"_setup("到)}的部分, + // 并且从中获取GTASK_JSON_LISTS的内容返回 public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -521,6 +567,7 @@ public class GTaskClient { response = mHttpClient.execute(httpGet); // get the task list + // 获取任务列表并存储进jsString中 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -547,6 +594,7 @@ public class GTaskClient { } } + // 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -558,6 +606,7 @@ public class GTaskClient { action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); + // 设置为传入的listGid action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); actionList.put(action); @@ -578,7 +627,7 @@ public class GTaskClient { public Account getSyncAccount() { return mAccount; } - + // 重装更新后的内容 public void resetUpdateArray() { mUpdateArray = null; } diff --git a/src/gtask/remote/GTaskManager.java b/src/gtask/remote/GTaskManager.java index d2b4082..d514ada 100644 --- a/src/gtask/remote/GTaskManager.java +++ b/src/gtask/remote/GTaskManager.java @@ -86,33 +86,44 @@ public class GTaskManager { private HashMap mGidToNid; private HashMap mNidToGid; - + // 初始化Google任务管理器的函数 private GTaskManager() { + // 初始化同步状态为未执行 mSyncing = false; + // 全局状态标识为可执行 mCancelled = false; + // java泛型类,用于创建一个用类作为参数的类 mGTaskListHashMap = new HashMap(); mGTaskHashMap = new HashMap(); mMetaHashMap = new HashMap(); mMetaList = null; mLocalDeleteIdMap = new HashSet(); + // 将Gid转换为Noteid通过哈希表建立映射 mGidToNid = new HashMap(); + // 将Noteid转换为Gid通过哈希表建立映射 mNidToGid = new HashMap(); } - + // synchronizedy语言级同步,用于表述该方法可能运行于多线程环境之下 + // 该方法用于初始化mInstance + // @return GTaskManager public static synchronized GTaskManager getInstance() { if (mInstance == null) { mInstance = new GTaskManager(); } return mInstance; } - + // synchronizedy语言级同步,用于表述该方法可能运行于多线程环境之下 public synchronized void setActivityContext(Activity activity) { // used for getting authtoken mActivity = activity; } - + // 用于本地化和远端同步的方法 + // @param context-----获取上下文 + // @param assyncTask-----用于同步的异步操作类 + // @return int public int sync(Context context, GTaskASyncTask asyncTask) { if (mSyncing) { + // 创建同步的日志文件 Log.d(TAG, "Sync is in progress"); return STATE_SYNC_IN_PROGRESS; } @@ -128,11 +139,14 @@ public class GTaskManager { mNidToGid.clear(); try { + // 创建用户机实例 GTaskClient client = GTaskClient.getInstance(); + // JSON类型,用于置空NULL client.resetUpdateArray(); // login google task if (!mCancelled) { + // 谷歌登录操作,若非则抛出登陆失败异常 if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } @@ -140,14 +154,17 @@ public class GTaskManager { // get the task list from google asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); + // 将谷歌上获取的JSONTasklist转换为本地Tasklist initGTaskList(); // do content sync work asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); + // 抓取网络异常并创建调试日志抛出error } catch (NetworkFailureException e) { Log.e(TAG, e.toString()); return STATE_NETWORK_ERROR; + // 抓取操作异常并创建调试日志抛出error } catch (ActionFailureException e) { Log.e(TAG, e.toString()); return STATE_INTERNAL_ERROR; @@ -167,32 +184,44 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } - + // 初始化GTaskList,获取Google上JSONTaskList并转换为本地TaskList + // 将获取的数据储存在mMetaList,mGTaskListHashMap,MGTaskHashmap中 + // @exception NetworkFailureException + // @return void private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; GTaskClient client = GTaskClient.getInstance(); try { + // Json对象是子元素的无序集合,相当于创建一个Map对象, + // bantouyan-json库对Json对象的抽象概念,提供操纵json对象的各种方法, + // 其格式为("key1": value1,"key2": value2...)key为字符串 + // ajax请求不刷新页面,因此配合js可实现局部刷新,所以json常用作异步请求返回对象使用 JSONArray jsTaskLists = client.getTaskLists(); // init meta list first + // TaskList类型 mMetaList = null; for (int i = 0; i < jsTaskLists.length(); i++) { + // JSONObject与JSONArray一个为对象,一个为数组。此处取出单个JSONObject JSONObject object = jsTaskLists.getJSONObject(i); String 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)) { + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + // MetaList为元表,此处为初始化TaskList mMetaList = new TaskList(); + // 由远端JSON获取对象信息 mMetaList.setContentByRemoteJSON(object); // load meta data + // 获取用户端的TaskList的gid JSONArray jsMetas = client.getTaskList(gid); for (int j = 0; j < jsMetas.length(); j++) { object = (JSONObject) jsMetas.getJSONObject(j); MetaData metaData = new MetaData(); metaData.setContentByRemoteJSON(object); + // 判断值是否值得存储,为否则不加入mMetaList if (metaData.isWorthSaving()) { mMetaList.addChildTask(metaData); if (metaData.getGid() != null) { @@ -214,18 +243,21 @@ public class GTaskManager { // init task list for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); + // 通过GetString传入本地某标志数据的名称,获取其在远端的名称 String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); 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 tasklist = new TaskList(); tasklist.setContentByRemoteJSON(object); mGTaskListHashMap.put(gid, tasklist); mGTaskHashMap.put(gid, tasklist); // load tasks + // 加载tasks JSONArray jsTasks = client.getTaskList(gid); for (int j = 0; j < jsTasks.length(); j++) { object = (JSONObject) jsTasks.getJSONObject(j); @@ -246,7 +278,8 @@ public class GTaskManager { throw new ActionFailureException("initGTaskList: handing JSONObject failed"); } } - + // 本地内容同步操作 + // @throw NetWorkFailureException private void syncContent() throws NetworkFailureException { int syncType; Cursor c = null; @@ -300,6 +333,7 @@ public class GTaskManager { gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { + // 通过哈希表获取gid mGTaskHashMap.remove(gid); mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); @@ -350,7 +384,7 @@ public class GTaskManager { } } - + // 同步文件夹 private void syncFolder() throws NetworkFailureException { Cursor c = null; String gid; @@ -475,7 +509,7 @@ public class GTaskManager { if (!mCancelled) GTaskClient.getInstance().commitUpdate(); } - + // 为同步类型分类 private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -521,7 +555,7 @@ public class GTaskManager { throw new ActionFailureException("unkown sync action type"); } } - + // 本地增加新的Node private void addLocalNode(Node node) throws NetworkFailureException { if (mCancelled) { return; @@ -595,7 +629,7 @@ public class GTaskManager { // update meta updateRemoteMeta(node.getGid(), sqlNote); } - + // 更新本地Node private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -618,12 +652,12 @@ public class GTaskManager { // update meta info updateRemoteMeta(node.getGid(), sqlNote); } - + // 添加远端node private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; } - + // 从本地数据库中获取内容 SqlNote sqlNote = new SqlNote(mContext, c); Node n; @@ -637,8 +671,9 @@ public class GTaskManager { Log.e(TAG, "cannot find task's parent tasklist"); throw new ActionFailureException("cannot add remote task"); } + // 在本地生成的GTaskList中添加子节点 mGTaskListHashMap.get(parentGid).addChildTask(task); - + // 登录远端服务器创建task GTaskClient.getInstance().createTask(task); n = (Node) task; @@ -655,7 +690,7 @@ public class GTaskManager { folderName += GTaskStringUtils.FOLDER_CALL_NOTE; else folderName += sqlNote.getSnippet(); - + // 迭代器,通过统一接口迭代所有map元素 Iterator> iter = mGTaskListHashMap.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = iter.next(); @@ -691,7 +726,7 @@ public class GTaskManager { mGidToNid.put(n.getGid(), sqlNote.getId()); mNidToGid.put(sqlNote.getId(), n.getGid()); } - + // 更新远端node private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { if (mCancelled) { return; @@ -709,15 +744,17 @@ public class GTaskManager { // move task if necessary if (sqlNote.isNoteType()) { Task task = (Task) node; + // preParentList通过node获取的父节点列表 TaskList preParentList = task.getParent(); - + // curParentGid为通过光标在数据库中找到sqlNote的mParentId,再通过mNidToGid由long类型转为String类型的Gid String curParentGid = mNidToGid.get(sqlNote.getParentId()); if (curParentGid == null) { Log.e(TAG, "cannot find task's parent tasklist"); throw new ActionFailureException("cannot update remote task"); } + // 通过HashMap找到对应Gid的TaskList TaskList curParentList = mGTaskListHashMap.get(curParentGid); - + // 判断父上一个节点是否与本节点相符,用于更新操作 if (preParentList != curParentList) { preParentList.removeChildTask(task); curParentList.addChildTask(task); @@ -729,7 +766,7 @@ public class GTaskManager { sqlNote.resetLocalModified(); sqlNote.commit(true); } - + // 升级远程meta private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { if (sqlNote != null && sqlNote.isNoteType()) { MetaData metaData = mMetaHashMap.get(gid); @@ -745,7 +782,7 @@ public class GTaskManager { } } } - + // 刷新本地syncid以对应更改后的对象 private void refreshLocalSyncId() throws NetworkFailureException { if (mCancelled) { return; @@ -769,8 +806,10 @@ public class GTaskManager { Node node = mGTaskHashMap.get(gid); if (node != null) { mGTaskHashMap.remove(gid); + // 在ContentValues中创建键值对。准备通过contentResolver写入数据 ContentValues values = new ContentValues(); values.put(NoteColumns.SYNC_ID, node.getLastModified()); + // 进行批量更改,选择参数为NULL,应该可以用insert替换,参数分别为表名和需要更新的value对象。 mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(SqlNote.ID_COLUMN)), values, null, null); } else { diff --git a/src/gtask/remote/GTaskSyncService.java b/src/gtask/remote/GTaskSyncService.java index cca36f7..a23452b 100644 --- a/src/gtask/remote/GTaskSyncService.java +++ b/src/gtask/remote/GTaskSyncService.java @@ -16,6 +16,23 @@ 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() 获取当前进度的信息 + */ + + import android.app.Activity; import android.app.Service; import android.content.Context; @@ -41,7 +58,7 @@ public class GTaskSyncService extends Service { private static GTaskASyncTask mSyncTask = null; private static String mSyncProgress = ""; - + // 开始进行一个同的步 private void startSync() { if (mSyncTask == null) { mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { @@ -52,6 +69,7 @@ public class GTaskSyncService extends Service { } }); sendBroadcast(""); + // 该函数主打的是一个让任务以单线程队列或者线程池队列方式运行 mSyncTask.execute(); } } @@ -63,6 +81,7 @@ public class GTaskSyncService extends Service { } @Override + // 对Service进行一个初始化 public void onCreate() { mSyncTask = null; } @@ -71,6 +90,7 @@ public class GTaskSyncService extends Service { public 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(); @@ -92,26 +112,28 @@ public class GTaskSyncService extends Service { mSyncTask.cancelSync(); } } - + // 重制客户端的服务绑定 public IBinder onBind(Intent intent) { return null; } public void sendBroadcast(String msg) { mSyncProgress = msg; + // 创建新的新意图 Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); sendBroadcast(intent); } - + // 对同步进行一个开始 public static void startSync(Activity activity) { 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) { Intent intent = new Intent(context, GTaskSyncService.class); intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); @@ -125,4 +147,4 @@ public class GTaskSyncService extends Service { public static String getProgressString() { return mSyncProgress; } -} +} \ No newline at end of file