From 39626256da49b0dc9e6f660cd3321cbe8f3ea9f0 Mon Sep 17 00:00:00 2001 From: KasumizawaMiyu Date: Tue, 28 Mar 2023 19:43:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=93=BC=E5=93=BC=E5=93=BC=E5=95=8A=E5=95=8A?= =?UTF-8?q?=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A?= =?UTF-8?q?=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A=E5=95=8A?= =?UTF-8?q?=E5=95=8A=E5=95=8A=E5=95=8A=20=E8=BF=9B=E8=A1=8C=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=8F=90=E7=9A=84=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: KasumizawaMiyu --- .../exception/ActionFailureException.java | 4 +- .../exception/NetworkFailureException.java | 3 + .../notes/gtask/remote/GTaskASyncTask.java | 38 ++++++-- .../notes/gtask/remote/GTaskClient.java | 93 ++++++++++++++----- .../notes/gtask/remote/GTaskManager.java | 81 +++++++++++----- .../notes/gtask/remote/GTaskSyncService.java | 32 ++++++- 6 files changed, 195 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java b/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java index 15504be..7787d25 100644 --- a/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java +++ b/app/src/main/java/net/micode/notes/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/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java b/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java index b08cfb1..6f67afe 100644 --- a/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java +++ b/app/src/main/java/net/micode/notes/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/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java index b3b61e7..7981605 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/app/src/main/java/net/micode/notes/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/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java index c67dfdf..fee4803 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java +++ b/app/src/main/java/net/micode/notes/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/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java index d2b4082..d514ada 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskManager.java +++ b/app/src/main/java/net/micode/notes/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/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java b/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java index cca36f7..a23452b 100644 --- a/app/src/main/java/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/app/src/main/java/net/micode/notes/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