diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index de96205..7fb321c 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -10,6 +10,7 @@
+<<<<<<< HEAD
<<<<<<< remotes/origin/cyx_branch
@@ -85,13 +86,37 @@
=======
>>>>>>> local
+=======
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+>>>>>>> 97f59e709a754d9ac92f018b602c051baead5aac
-
+
@@ -119,7 +144,7 @@
"RunOnceActivity.cidr.known.project.marker": "true",
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
"cidr.known.project.marker": "true",
- "last_opened_file_path": "D:/softwareengineering/Notes-master",
+ "last_opened_file_path": "D:/TOUGE/gitProject",
"project.structure.last.edited": "Modules",
"project.structure.proportion": "0.17",
"project.structure.side.proportion": "0.2",
@@ -181,9 +206,7 @@
-
-
-
+
diff --git a/doc/蔡玉祥注释的代码/ActionFailureException.java b/doc/蔡玉祥注释的代码/ActionFailureException.java
new file mode 100644
index 0000000..3579e44
--- /dev/null
+++ b/doc/蔡玉祥注释的代码/ActionFailureException.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.micode.notes.gtask.exception;
+
+public class ActionFailureException extends RuntimeException {
+
+ private static final long serialVersionUID = 4425249765923293627L;
+
+ public ActionFailureException() {
+ super(); // 调用父类的构造函数
+ }
+
+ public ActionFailureException(String paramString) {
+ super(paramString); // 调用父类的构造函数,并传入异常信息
+ }
+
+ public ActionFailureException(String paramString, Throwable paramThrowable) {
+ super(paramString, paramThrowable); // 调用父类的构造函数,并传入异常信息和原始异常
+ }
+}
diff --git a/doc/蔡玉祥注释的代码/GTaskASyncTask.java b/doc/蔡玉祥注释的代码/GTaskASyncTask.java
new file mode 100644
index 0000000..c88aef0
--- /dev/null
+++ b/doc/蔡玉祥注释的代码/GTaskASyncTask.java
@@ -0,0 +1,123 @@
+
+/*
+ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.micode.notes.gtask.remote;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+
+import net.micode.notes.R;
+import net.micode.notes.ui.NotesListActivity;
+import net.micode.notes.ui.NotesPreferenceActivity;
+
+
+public class GTaskASyncTask extends AsyncTask {
+
+ private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;
+
+ public interface OnCompleteListener {
+ void onComplete();
+ }
+
+ private Context mContext; // 上下文对象
+
+ private NotificationManager mNotifiManager; // 通知管理器对象
+
+ private GTaskManager mTaskManager; // GTask 管理器对象
+
+ private OnCompleteListener mOnCompleteListener; // 异步任务完成后的回调接口
+
+ public GTaskASyncTask(Context context, OnCompleteListener listener) {
+ mContext = context; // 初始化上下文对象
+ mOnCompleteListener = listener; // 初始化回调接口
+ mNotifiManager = (NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE); // 初始化通知管理器对象
+ mTaskManager = GTaskManager.getInstance(); // 获取 GTask 管理器对象的单例
+ }
+
+ public void cancelSync() {
+ mTaskManager.cancelSync(); // 取消 GTask 同步
+ }
+
+ 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); // 点击通知后打开 NotesPreferenceActivity
+
+ } else { // 如果是同步成功的通知
+ pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
+ NotesListActivity.class), 0); // 点击通知后打开 NotesListActivity
+ }
+ //notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
+ // pendingIntent); // 设置通知的标题、内容和点击后的操作
+ mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); // 发送通知
+ }
+
+ @Override
+ protected Integer doInBackground(Void... unused) {
+ publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
+ .getSyncAccountName(mContext))); // 向主线程发布进度更新,显示正在登录的提示信息
+ return mTaskManager.sync(mContext, this); // 开始 GTask 同步,并返回同步结果
+ }
+
+ @Override
+ protected void onProgressUpdate(String... progress) {
+ showNotification(R.string.ticker_syncing, progress[0]); // 显示同步进度的通知
+ if (mContext instanceof GTaskSyncService) {
+ ((GTaskSyncService) mContext).sendBroadcast(progress[0]); // 向 GTaskSyncService 发送广播,以便更新 UI
+ }
+ }
+
+ @Override
+ 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)); // 显示同步失败的通知,提示网络错误
+ } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { // 如果内部错误
+ showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); // 显示同步失败的通知,提示内部错误
+ } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { // 如果同步被取消
+ showNotification(R.string.ticker_cancel, mContext
+ .getString(R.string.error_sync_cancelled)); // 显示同步被取消的通知
+ }
+ if (mOnCompleteListener != null) { // 如果设置了 OnCompleteListener
+ new Thread(new Runnable() { // 在新线程中执行 OnCompleteListener
+
+ public void run() {
+ mOnCompleteListener.onComplete();
+ }
+ }).start();
+ }
+ }
+}
\ No newline at end of file
diff --git a/doc/蔡玉祥注释的代码/GTaskClient.java b/doc/蔡玉祥注释的代码/GTaskClient.java
new file mode 100644
index 0000000..91314f8
--- /dev/null
+++ b/doc/蔡玉祥注释的代码/GTaskClient.java
@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.micode.notes.gtask.remote;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.app.Activity;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import net.micode.notes.gtask.data.Node;
+import net.micode.notes.gtask.data.Task;
+import net.micode.notes.gtask.data.TaskList;
+import net.micode.notes.gtask.exception.ActionFailureException;
+import net.micode.notes.gtask.exception.NetworkFailureException;
+import net.micode.notes.tool.GTaskStringUtils;
+import net.micode.notes.ui.NotesPreferenceActivity;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.cookie.Cookie;
+import org.apache.http.impl.client.BasicCookieStore;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
+import java.util.zip.InflaterInputStream;
+
+
+public class GTaskClient {
+ private static final String TAG = GTaskClient.class.getSimpleName();
+
+ private static final String GTASK_URL = "https://mail.google.com/tasks/"; // GTask 的基础 URL
+
+ private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; // 获取 GTask 数据的 URL
+
+ private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; // 提交 GTask 数据的 URL
+
+ private static GTaskClient mInstance = null; // 单例模式,保存 GTaskClient 的唯一实例
+
+ private DefaultHttpClient mHttpClient; // HTTP 客户端
+
+ private String mGetUrl; // 获取 GTask 数据的完整 URL
+
+ private String mPostUrl; // 提交 GTask 数据的完整 URL
+
+ private long mClientVersion; // 客户端版本号
+
+ private boolean mLoggedin; // 是否已登录
+
+ private long mLastLoginTime; // 上次登录时间
+
+ private int mActionId; // 操作 ID
+
+ private Account mAccount; // GTask 帐户
+
+ private JSONArray mUpdateArray; // 待更新的 GTask 数据
+ private GTaskClient() {
+ mHttpClient = null; // 初始化 HTTP 客户端为 null
+ mGetUrl = GTASK_GET_URL; // 初始化获取 GTask 数据的 URL
+ mPostUrl = GTASK_POST_URL; // 初始化提交 GTask 数据的 URL
+ mClientVersion = -1; // 初始化客户端版本号为 -1
+ mLoggedin = false; // 初始化登录状态为 false
+ mLastLoginTime = 0; // 初始化上次登录时间为 0
+ mActionId = 1; // 初始化操作 ID 为 1
+ mAccount = null; // 初始化 GTask 帐户为 null
+ mUpdateArray = null; // 初始化待更新的 GTask 数据为 null
+ }/*该构造方法用于创建GTaskClient的实例,其中将mHttpClient、mAccount、mUpdateArray等成员变量初始化为 null 或默认值,将mGetUrl和mPostUrl初始化为 GTask 的默认 URL,将mClientVersion初始化为 -1,将mLoggedin初始化为 false,将mLastLoginTime初始化为 0,将mActionId初始化为 1。
+ 这里使用了默认访问控制符private,意味着该构造方法只能在GTaskClient类内部使用,不能在其他类中创建GTaskClient的实例。*/
+
+ public static synchronized GTaskClient getInstance() {
+ if (mInstance == null) { // 如果唯一实例不存在
+ mInstance = new GTaskClient(); // 则创建一个新实例
+ }
+ return mInstance; // 返回唯一实例
+ }/*该方法是单例模式的实现,用于获取GTaskClient的唯一实例。在该方法内部,首先判断唯一实例是否已经存在,如果不存在则创建一个新实例,并将其赋值给mInstance。最后返回唯一实例。
+ 由于该方法可能被多个线程同时调用,所以使用了synchronized关键字来保证在同一时刻只有一个线程能够访问该方法。
+ 同时,该方法返回的是静态成员变量mInstance,因此可以通过GTaskClient.getInstance()的方式在任意位置获取GTaskClient的唯一实例。*/
+
+ 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(); // 记录登录时间
+ String authToken = loginGoogleAccount(activity, false); // 登录 Google 帐户,获取授权令牌
+ if (authToken == null) { // 如果登录失败,则返回 false
+ Log.e(TAG, "login google account failed");
+ return false;
+ }
+
+ // login with custom domain if necessary
+ if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
+ .endsWith("googlemail.com"))) { // 如果不是 Gmail 或 Googlemail 帐户,则使用自定义域名登录
+ StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); // 构造自定义域名的 URL
+ int index = mAccount.name.indexOf('@') + 1;
+ String suffix = mAccount.name.substring(index);
+ url.append(suffix + "/");
+ mGetUrl = url.toString() + "ig"; // 更新获取 GTask 数据的 URL
+ mPostUrl = url.toString() + "r/ig"; // 更新提交 GTask 数据的 URL
+
+ if (tryToLoginGtask(activity, authToken)) { // 尝试登录 GTask
+ mLoggedin = true; // 登录成功
+ }
+ }
+
+ // 如果自定义域名登录失败,则使用 Google 官方 URL 登录
+ if (!mLoggedin) {
+ mGetUrl = GTASK_GET_URL;
+ mPostUrl = GTASK_POST_URL;
+ if (!tryToLoginGtask(activity, authToken)) {
+ return false;
+ }
+ }
+
+ mLoggedin = true; // 登录成功
+ return true;
+ }/*该方法用于登录 GTask,首先检查上次登录时间是否超过 5 分钟,如果超过则需要重新登录,将mLoggedin设置为 false。
+ 然后判断当前帐户是否发生切换,如果发生切换也需要重新登录,同样将mLoggedin设置为 false。
+ 如果已经登录,则直接返回 true。否则,记录本次登录时间,然后使用loginGoogleAccount()方法登录 Google 帐户,获取授权令牌。
+ 如果登录失败,则返回 false。接下来,如果当前帐户不是 Gmail 或 Googlemail 帐户,则使用自定义域名登录,更新获取 GTask 数据和提交 GTask 数据的 URL,然后尝试登录 GTask。
+ 如果自定义域名登录失败,则使用 Google 官方 URL 登录。
+ 无论使用哪种方式登录成功,最后将mLoggedin设置为 true,表示已经登录成功。*/
+
+ private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
+ String authToken;
+ AccountManager accountManager = AccountManager.get(activity); // 获取 AccountManager 实例
+ Account[] accounts = accountManager.getAccountsByType("com.google"); // 获取所有 Google 帐户
+
+ if (accounts.length == 0) { // 如果没有可用的 Google 帐户,则返回 null
+ 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 {
+ Log.e(TAG, "unable to get an account with the same name in the settings");
+ return null;
+ }
+
+ // get the token now
+ AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account,
+ "goanna_mobile", null, activity, null, null); // 获取 token
+ try {
+ Bundle authTokenBundle = accountManagerFuture.getResult();
+ authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); // 从 Bundle 中获取 token
+ if (invalidateToken) { // 如果需要使 token 失效
+ accountManager.invalidateAuthToken("com.google", authToken); // 使 token 失效
+ loginGoogleAccount(activity, false); // 重新登录
+ }
+ } catch (Exception e) { // 获取 token 失败
+ Log.e(TAG, "get auth token failed");
+ authToken = null;
+ }
+
+ return authToken; // 返回 token
+ }
+ /*该方法的作用是获取 Google 帐户的 token,以用于访问 Google 服务。
+ 它首先获取所有的 Google 帐户,然后根据设置中的同步帐户名称选择使用哪个帐户。
+ 接着,它使用AccountManager获取该帐户的 token,并返回该 token。
+ 如果invalidateToken参数为true,则该方法会使 token 失效,并重新登录,以获取新的 token。
+ */
+
+ private boolean tryToLoginGtask(Activity activity, String authToken) {
+ if (!loginGtask(authToken)) { // 如果登录 GTask 失败
+ // maybe the auth token is out of date, now let's invalidate the
+ // token and try again
+ authToken = loginGoogleAccount(activity, true); // 使 token 失效并重新登录
+ if (authToken == null) { // 如果重新登录失败,则返回 false
+ Log.e(TAG, "login google account failed");
+ return false;
+ }
+
+ if (!loginGtask(authToken)) { // 如果重新登录 GTask 仍然失败,则返回 false
+ Log.e(TAG, "login gtask failed");
+ return false;
+ }
+ }
+ return true; // 登录 GTask 成功,返回 true
+ }
+ /*该方法的作用是尝试登录 GTask,它接收一个authToken参数,该参数是通过loginGoogleAccount()方法获取的 Google 帐户的 token。
+ 如果登录 GTask 失败,则会使 token 失效并重新登录,再次尝试登录 GTask。
+ 如果重新登录失败,则返回false,否则返回true。
+ */
+
+ private boolean loginGtask(String authToken) {
+ int timeoutConnection = 10000;
+ int timeoutSocket = 15000;
+ HttpParams httpParameters = new BasicHttpParams();
+ HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
+ HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
+
+ // 设置 HttpClient 的参数
+ mHttpClient = new DefaultHttpClient(httpParameters);
+ BasicCookieStore localBasicCookieStore = new BasicCookieStore();
+ mHttpClient.setCookieStore(localBasicCookieStore);
+ HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);
+
+ // login gtask
+ try {
+ String loginUrl = mGetUrl + "?auth=" + authToken;
+ HttpGet httpGet = new HttpGet(loginUrl); // 创建 HTTP GET 请求
+ HttpResponse response = mHttpClient.execute(httpGet); // 执行请求
+
+ // 获取 cookie
+ List cookies = mHttpClient.getCookieStore().getCookies();
+ boolean hasAuthCookie = false;
+ for (Cookie cookie : cookies) {
+ if (cookie.getName().contains("GTL")) {
+ hasAuthCookie = true;
+ }
+ }
+ if (!hasAuthCookie) {
+ Log.w(TAG, "it seems that there is no auth cookie");
+ }
+
+ // 获取客户端版本
+ String resString = getResponseContent(response.getEntity());
+ String jsBegin = "_setup(";
+ String jsEnd = ")}";
+ int begin = resString.indexOf(jsBegin);
+ int end = resString.lastIndexOf(jsEnd);
+ String jsString = null;
+ if (begin != -1 && end != -1 && begin < end) {
+ jsString = resString.substring(begin + jsBegin.length(), end);
+ }
+ JSONObject js = new JSONObject(jsString);
+ mClientVersion = js.getLong("v");
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ return false;
+ } catch (Exception e) {
+ // simply catch all exceptions
+ Log.e(TAG, "httpget gtask_url failed");
+ return false;
+ }
+
+ return true;
+ }
+ /*该方法的作用是使用给定的authToken登录 GTask。
+ 它创建了一个 HTTP GET 请求,并将authToken添加到 URL 末尾,然后执行该请求并获取响应。
+ 它还获取了响应中包含的 cookie,并将客户端版本存储在mClientVersion中。
+ 如果登录成功,则返回true,否则返回false。如果发生异常,则返回false。
+ */
+
+ private int getActionId() {
+ return mActionId++; // 返回下一个 action ID,并将 mActionId 加 1
+ }
+
+ private HttpPost createHttpPost() {
+ HttpPost httpPost = new HttpPost(mPostUrl); // 创建一个 HTTP POST 请求
+ httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); // 设置请求头的 Content-Type
+ httpPost.setHeader("AT", "1"); // 设置请求头的 AT 字段为 1
+ return httpPost; // 返回创建的 HTTP POST 请求
+ }/*getActionId()的作用是获取下一个 action ID,每次调用它都会将mActionId加 1,并返回加 1 后的值。
+ createHttpPost()的作用是创建一个 HTTP POST 请求,并设置请求头的 Content-Type 为application/x-www-form-urlencoded;charset=utf-8,设置请求头的 AT 字段为 1。
+ 它返回创建的 HTTP POST 请求对象。
+ */
+
+ private String getResponseContent(HttpEntity entity) throws IOException {
+ String contentEncoding = null;
+ if (entity.getContentEncoding() != null) {
+ contentEncoding = entity.getContentEncoding().getValue(); // 获取响应内容的编码方式
+ Log.d(TAG, "encoding: " + contentEncoding);
+ }
+
+ InputStream input = entity.getContent(); // 获取响应内容的输入流
+ if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
+ input = new GZIPInputStream(entity.getContent()); // 如果响应内容被 gzip 压缩了,则创建一个 GZIPInputStream 解压缩
+ } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
+ Inflater inflater = new Inflater(true);
+ input = new InflaterInputStream(entity.getContent(), inflater); // 如果响应内容被 deflate 压缩了,则创建一个 InflaterInputStream 解压缩
+ }
+
+ try {
+ InputStreamReader isr = new InputStreamReader(input); // 创建一个 InputStreamReader 对象
+ BufferedReader br = new BufferedReader(isr); // 创建一个 BufferedReader 对象
+ StringBuilder sb = new StringBuilder(); // 创建一个 StringBuilder 对象
+
+ while (true) {
+ String buff = br.readLine(); // 逐行读取响应内容
+ if (buff == null) {
+ return sb.toString(); // 如果读到了末尾,则返回读取到的响应内容
+ }
+ sb = sb.append(buff); // 将读取到的响应内容追加到 StringBuilder 对象中
+ }
+ } finally {
+ input.close(); // 关闭输入流
+ }
+ }
+ /*getResponseContent(HttpEntity entity)的作用是从HttpEntity对象中获取响应内容,并将其解压(如果响应内容被压缩了)。它返回解压后的响应内容。
+ 首先获取响应内容的编码方式,然后根据编码方式创建对应的输入流。
+ 如果响应内容被 gzip 压缩了,则创建一个 GZIPInputStream 对象解压缩;如果响应内容被 deflate 压缩了,则创建一个 InflaterInputStream 对象解压缩。
+ 接着使用 InputStreamReader 和 BufferedReader 逐行读取响应内容,并将其追加到 StringBuilder 对象中。
+ 最后返回读取到的响应内容,并关闭输入流。
+ */
+
+ private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
+ if (!mLoggedin) {
+ Log.e(TAG, "please login first");
+ throw new ActionFailureException("not logged in");
+ }
+
+ HttpPost httpPost = createHttpPost(); // 创建 HTTP POST 请求
+ try {
+ LinkedList list = new LinkedList();
+ list.add(new BasicNameValuePair("r", js.toString())); // 将传入的 JSONObject 对象转为字符串,并添加到请求参数中
+ UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); // 创建一个 UrlEncodedFormEntity 对象,用于封装请求参数
+ httpPost.setEntity(entity); // 将 UrlEncodedFormEntity 对象设置为 HTTP POST 请求的实体
+
+ // execute the post
+ HttpResponse response = mHttpClient.execute(httpPost); // 执行 HTTP POST 请求
+ String jsString = getResponseContent(response.getEntity()); // 获取响应内容,并将其解压(如果响应内容被压缩了),然后转为字符串
+ return new JSONObject(jsString); // 将响应内容转为 JSONObject 对象
+
+ } catch (ClientProtocolException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new NetworkFailureException("postRequest failed");
+ } catch (IOException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new NetworkFailureException("postRequest failed");
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("unable to convert response content to jsonobject");
+ } catch (Exception e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("error occurs when posting request");
+ }
+ }
+ /*postRequest(JSONObject js)的作用是向服务器发送 HTTP POST 请求,并将响应内容转为JSONObject对象返回。
+ 首先检查用户是否已经登录,如果没有登录则抛出异常。然后创建一个 HTTP POST 请求,并将传入的 JSONObject 对象转为字符串,并添加到请求参数中。接着,创建一个 UrlEncodedFormEntity 对象,用于封装请求参数,并将其设置为 HTTP POST 请求的实体。
+ 执行 HTTP POST 请求,并获取响应内容。将响应内容解压(如果响应内容被压缩了),然后将其转为字符串,并通过 JSONObject 构造方法将其转为 JSONObject 对象。如果转换失败,则抛出异常。
+ 如果在执行 HTTP POST 请求或转换响应内容为 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
+ public void createTask(Task task) throws NetworkFailureException {
+ commitUpdate(); // 提交所有未提交的更新操作
+
+ try {
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储操作列表
+
+ // action_list
+ actionList.put(task.getCreateAction(getActionId())); // 将新增任务的操作添加到操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将操作列表添加到 JSONObject 对象中
+
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ // post
+ JSONObject jsResponse = postRequest(jsPost); // 向服务器发送 HTTP POST 请求,并获取响应内容
+ JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
+ GTaskStringUtils.GTASK_JSON_RESULTS).get(0); // 从响应内容中获取结果列表,并获取第一个结果
+ task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); // 获取新任务的 ID,并将其设置为 Task 对象的 gid 属性
+
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("create task: handing jsonobject failed");
+ }
+ }
+ /*createTask(Task task)的作用是创建新任务。首先调用commitUpdate()方法提交所有未提交的更新操作。
+ 然后创建一个新的 JSONObject 对象,并创建一个新的 JSONArray 对象,用于存储操作列表。将新增任务的操作添加到操作列表中,并将操作列表添加到 JSONObject 对象中。将客户端版本号也添加到 JSONObject 对象中。
+ 向服务器发送 HTTP POST 请求,并获取响应内容。从响应内容中获取结果列表,并获取第一个结果。从结果中获取新任务的 ID,并将其设置为 Task 对象的 gid 属性。
+ 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
+ public void createTaskList(TaskList tasklist) throws NetworkFailureException {
+ commitUpdate(); // 提交所有未提交的更新操作
+
+ try {
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储操作列表
+
+ // action_list
+ actionList.put(tasklist.getCreateAction(getActionId())); // 将新增任务列表的操作添加到操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将操作列表添加到 JSONObject 对象中
+
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ // post
+ JSONObject jsResponse = postRequest(jsPost); // 向服务器发送 HTTP POST 请求,并获取响应内容
+ JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
+ GTaskStringUtils.GTASK_JSON_RESULTS).get(0); // 从响应内容中获取结果列表,并获取第一个结果
+ tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); // 获取新任务列表的 ID,并将其设置为 TaskList 对象的 gid 属性
+
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("create tasklist: handing jsonobject failed");
+ }
+ }
+ /*createTaskList(TaskList tasklist)的作用是创建新任务列表。首先调用commitUpdate()方法提交所有未提交的更新操作。
+ 然后创建一个新的 JSONObject 对象,并创建一个新的 JSONArray 对象,用于存储操作列表。将新增任务列表的操作添加到操作列表中,并将操作列表添加到 JSONObject 对象中。将客户端版本号也添加到 JSONObject 对象中。
+ 向服务器发送 HTTP POST 请求,并获取响应内容。从响应内容中获取结果列表,并获取第一个结果。从结果中获取新任务列表的 ID,并将其设置为 TaskList 对象的 gid 属性。
+ 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
+ public void commitUpdate() throws NetworkFailureException {
+ if (mUpdateArray != null) { // 判断更新操作列表是否为空
+ try {
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+
+ // action_list
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); // 将更新操作列表添加到 JSONObject 对象中
+
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作
+ mUpdateArray = null; // 更新操作提交成功后,清空更新操作列表
+
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("commit update: handing jsonobject failed");
+ }
+ }
+ }
+ /*commitUpdate()的作用是提交所有未提交的更新操作。如果更新操作列表不为空,则创建一个新的 JSONObject 对象,将更新操作列表添加到 JSONObject 对象中,并将客户端版本号也添加到 JSONObject 对象中。
+ 向服务器发送 HTTP POST 请求,提交更新操作。提交成功后,清空更新操作列表。
+ 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
+ public void addUpdateNode(Node node) throws NetworkFailureException {
+ if (node != null) { // 判断 Node 对象是否为空
+ // too many update items may result in an error
+ // set max to 10 items
+ if (mUpdateArray != null && mUpdateArray.length() > 10) { // 判断更新操作列表是否已满
+ commitUpdate(); // 如果已满,则提交所有未提交的更新操作
+ }
+
+ if (mUpdateArray == null)
+ mUpdateArray = new JSONArray(); // 如果更新操作列表还未创建,则创建一个新的 JSONArray 对象
+ mUpdateArray.put(node.getUpdateAction(getActionId())); // 将 Node 对象的更新操作添加到更新操作列表中
+ }
+ }
+ /*addUpdateNode(Node node)的作用是向更新操作列表中添加一个新的更新操作。首先判断 Node 对象是否为空。
+ 如果更新操作列表已满(长度大于 10),则调用commitUpdate()方法提交所有未提交的更新操作。
+ 如果更新操作列表还未创建,则创建一个新的 JSONArray 对象。将 节点
+ 如果 Node 对象为空,则不执行任何操作。
+ */
+ public void moveTask(Task task, TaskList preParent, TaskList curParent)
+ throws NetworkFailureException {
+ commitUpdate(); // 先提交所有未提交的更新操作
+ try {
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储更新操作
+ JSONObject action = new JSONObject(); // 创建一个新的 JSONObject 对象,用于存储移动任务的操作
+
+ // action_list
+ action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
+ GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); // 设置操作类型为移动任务
+ action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置操作 ID
+ action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); // 设置任务的 GID
+
+ if (preParent == curParent && task.getPriorSibling() != null) {
+ // put prioring_sibing_id only if moving within the tasklist and
+ // it is not the first one
+ action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); // 如果是在同一任务列表中移动任务,则设置前一个任务的 GID
+ }
+
+ action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); // 设置任务的原始任务列表的 GID
+ action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); // 设置任务的目标任务列表的 GID
+
+ if (preParent != curParent) {
+ // put the dest_list only if moving between tasklists
+ action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); // 如果是在不同的任务列表之间移动任务,则设置任务的目标任务列表的 GID
+ }
+
+ actionList.put(action); // 将移动任务的操作添加到更新操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将更新操作列表添加到 JSONObject 对象中
+
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作
+
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("move task: handing jsonobject failed");
+ }
+ }
+ /*moveTask(Task task, TaskList preParent, TaskList curParent)的作用是移动一个任务到另一个任务列表中。
+ 首先调用commitUpdate()方法提交所有未提交的更新操作。然后,创建一个新的 JSONObject 对象,用于存储移动任务的操作。
+ 在移动任务的操作中,设置操作类型为移动任务。设置操作 ID 和任务的 GID。如果是在同一任务列表中移动任务,则设置前一个任务的 GID。设置任务的原始任务列表的 GID 和任务的目标任务列表的 GID。如果是在不同的任务列表之间移动任务,则设置任务的目标任务列表的 GID。
+ 将移动任务的操作添加到更新操作列表中,然后将更新操作列表添加到 JSONObject 对象中。最后,添加客户端版本号到 JSONObject 对象中,向服务器发送 HTTP POST 请求,提交更新操作。
+ 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常。
+ */
+ public void deleteNode(Node node) throws NetworkFailureException {
+ commitUpdate(); // 先提交所有未提交的更新操作
+ try {
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储更新操作
+
+ // action_list
+ node.setDeleted(true); // 将节点标记为已删除
+ actionList.put(node.getUpdateAction(getActionId())); // 将节点的更新操作添加到更新操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将更新操作列表添加到 JSONObject 对象中
+
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作
+ mUpdateArray = null; // 将更新操作数组置为空
+
+ } catch (JSONException e) {
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("delete node: handing jsonobject failed"); // 处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常
+ }
+ }
+ /*此方法的主要目的是删除一个节点,并将删除操作提交到服务器。
+ 方法首先提交所有未提交的更新操作,然后创建一个新的 JSONObject 对象,将节点的删除操作添加到该对象中,同时添加客户端版本号。
+ 最后,方法通过向服务器发送 HTTP POST 请求来提交更新操作,如果在处理 JSONObject 对象时出现异常,则会抛出 ActionFailureException 异常。
+ */
+
+ public JSONArray getTaskLists() throws NetworkFailureException {
+ if (!mLoggedin) { // 如果用户没有登录,则抛出 ActionFailureException 异常
+ Log.e(TAG, "please login first");
+ throw new ActionFailureException("not logged in");
+ }
+
+ try {
+ HttpGet httpGet = new HttpGet(mGetUrl); // 创建一个新的 HttpGet 请求对象
+ HttpResponse response = null;
+ response = mHttpClient.execute(httpGet); // 执行 HttpGet 请求
+
+ // get the task list
+ String resString = getResponseContent(response.getEntity()); // 获取响应内容
+ String jsBegin = "_setup(";
+ String jsEnd = ")}";
+ int begin = resString.indexOf(jsBegin);
+ int end = resString.lastIndexOf(jsEnd);
+ String jsString = null;
+ if (begin != -1 && end != -1 && begin < end) { // 如果响应内容中包含任务列表,那么提取出来
+ jsString = resString.substring(begin + jsBegin.length(), end);
+ }
+ JSONObject js = new JSONObject(jsString); // 将任务列表转换成 JSONObject 对象
+ return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); // 返回任务列表数组
+
+ } catch (ClientProtocolException e) { // 如果发生协议错误,则抛出 NetworkFailureException 异常
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new NetworkFailureException("gettasklists: httpget failed");
+ } catch (IOException e) { // 如果发生 I/O 错误,则抛出 NetworkFailureException 异常
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new NetworkFailureException("gettasklists: httpget failed");
+ } catch (JSONException e) { // 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("get task lists: handing jasonobject failed");
+ }
+ }
+ /*此方法的主要目的是从服务器获取用户的任务列表,并将其作为 JSONArray 对象返回。
+ 方法首先检查用户是否已登录,然后创建一个新的 HttpGet 请求对象,并通过执行该请求来获取响应内容。
+ 接下来,方法从响应内容中提取出任务列表,并将其转换为 JSONObject 对象,最后返回任务列表数组。
+ 如果在执行 HttpGet 请求或处理 JSONObject 对象时发生错误,则会抛出 NetworkFailureException 或 ActionFailureException 异常。
+ */
+
+ public JSONArray getTaskList(String listGid) throws NetworkFailureException {
+ commitUpdate(); // 提交所有未提交的更改
+ try {
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象
+ JSONObject action = new JSONObject(); // 创建一个新的 JSONObject 对象
+
+ // action_list
+ action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
+ GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); // 设置 action 的类型为 "getall"
+ action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置 action 的 ID
+ action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); // 设置 action 操作的任务列表 ID
+ action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); // 设置是否获取已删除的任务
+ actionList.put(action); // 将 action 添加到 action_list 中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将 action_list 添加到 jsPost 中
+
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 设置客户端版本号
+
+ JSONObject jsResponse = postRequest(jsPost); // 发送请求并获取响应
+ return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); // 从响应中获取任务列表并返回
+
+ } catch (JSONException e) { // 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常
+ Log.e(TAG, e.toString());
+ e.printStackTrace();
+ throw new ActionFailureException("get task list: handing jsonobject failed");
+ }
+ }
+ /*此方法的主要目的是从服务器获取特定任务列表的任务,并将其作为 JSONArray 对象返回。
+ 方法首先提交所有未提交的更改,然后构造一个包含获取任务列表的请求并发送它。
+ 接下来,方法从响应中提取出任务列表,并将其作为 JSONArray 对象返回。
+ 如果在处理 JSONObject 对象时发生错误,则会抛出 ActionFailureException 异常。
+ */
+
+ public Account getSyncAccount() {
+ return mAccount;
+ }
+ //这个方法返回GTaskClient的同步账户(即当前使用的 Google 帐户)。
+
+ public void resetUpdateArray() {
+ mUpdateArray = null;
+ }
+}
+ /*这个方法将GTaskClient的更新数组mUpdateArray设置为null,以清除未提交的更改。
+ 在更新任务列表之前,需要调用commitUpdate()方法提交所有未提交的更改,如果您想丢弃这些更改,可以调用resetUpdateArray()方法以清除它们。
+ */
\ No newline at end of file
diff --git a/doc/蔡玉祥注释的代码/NetworkFailureException.java b/doc/蔡玉祥注释的代码/NetworkFailureException.java
index b08cfb1..c6a2691 100644
--- a/doc/蔡玉祥注释的代码/NetworkFailureException.java
+++ b/doc/蔡玉祥注释的代码/NetworkFailureException.java
@@ -17,17 +17,18 @@
package net.micode.notes.gtask.exception;
public class NetworkFailureException extends Exception {
+
private static final long serialVersionUID = 2107610287180234136L;
public NetworkFailureException() {
- super();
+ super(); // 调用父类的构造函数
}
public NetworkFailureException(String paramString) {
- super(paramString);
+ super(paramString); // 调用父类的构造函数,并传入异常信息
}
public NetworkFailureException(String paramString, Throwable paramThrowable) {
- super(paramString, paramThrowable);
+ super(paramString, paramThrowable); // 调用父类的构造函数,并传入异常信息和原始异常
}
}
diff --git a/src/.idea/deploymentTargetDropDown.xml b/src/.idea/deploymentTargetDropDown.xml
index 8e3647d..152075b 100644
--- a/src/.idea/deploymentTargetDropDown.xml
+++ b/src/.idea/deploymentTargetDropDown.xml
@@ -12,10 +12,18 @@
+<<<<<<< HEAD
+<<<<<<< HEAD:src/.idea/deploymentTargetDropDown.xml
+
+=======
+
+>>>>>>> cyx_branch:.idea/deploymentTargetDropDown.xml
+=======
<<<<<<< HEAD:.idea/deploymentTargetDropDown.xml
=======
>>>>>>> master:src/.idea/deploymentTargetDropDown.xml
+>>>>>>> 25eb5a04c09307c5edd9569e8d491a90234c9d82
\ No newline at end of file
diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java b/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java
index e6a6be8..04001de 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/data/SqlData.java
@@ -45,6 +45,13 @@ public class SqlData {
DataColumns.DATA3
};
/*这是一个Java类,名称为SqlData,其中定义了一些静态变量和常量,用于在类内和类外引用。
+<<<<<<< HEAD
+第一行定义了一个名为TAG的静态常量字符串,用于在日志中标识该类。这个字符串的值是SqlData类的简单名称。
+第二行定义了一个名为INVALID_ID的私有静态常量整数,用于表示无效的ID。该值被设置为-99999。
+第三行定义了一个名为PROJECTION_DATA的公共静态常量字符串数组,用于定义一个查询所需返回的列。这些列包括DataColumns类中定义的ID、MIME_TYPE、CONTENT、DATA1和DATA3。
+这些变量和常量都被声明为静态的,这意味着它们属于类本身,而不是类的实例。因此,它们可以在类的所有实例之间共享和访问。
+这些变量和常量的使用可以提高代码的可读性和可维护性,并避免在代码中多次重复相同的值。*/
+=======
第一行定义了一个名为TAG的静态常量字符串,用于在日志中标识该类。这个字符串的值是SqlData类的简单名称。
@@ -53,6 +60,7 @@ public class SqlData {
第三行定义了一个名为PROJECTION_DATA的公共静态常量字符串数组,用于定义一个查询所需返回的列。这些列包括DataColumns类中定义的ID、MIME_TYPE、CONTENT、DATA1和DATA3。
这些变量和常量都被声明为静态的,这意味着它们属于类本身,而不是类的实例。因此,它们可以在类的所有实例之间共享和访问。这些变量和常量的使用可以提高代码的可读性和可维护性,并避免在代码中多次重复相同的值。*/
+>>>>>>> 25eb5a04c09307c5edd9569e8d491a90234c9d82
public static final int DATA_ID_COLUMN = 0;
public static final int DATA_MIME_TYPE_COLUMN = 1;
diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java b/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java
index 79a4095..ec251ec 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/data/SqlNote.java
@@ -51,7 +51,28 @@ public class SqlNote {
NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID,
NoteColumns.VERSION
};
-
+/*定义了一个名为SqlNote的类。这个类包含了一些静态常量和一个名为PROJECTION_NOTE的公共静态字符串数组,该数组包含了用于查询笔记数据的列名。
+
+具体来说,PROJECTION_NOTE数组包含了以下列名:
+
+ID: 笔记的唯一标识符
+ALERTED_DATE: 笔记提醒的日期
+BG_COLOR_ID: 笔记背景颜色的标识符
+CREATED_DATE: 笔记创建的日期
+HAS_ATTACHMENT: 笔记是否有附件
+MODIFIED_DATE: 笔记最后修改的日期
+NOTES_COUNT: 笔记下的子笔记数量
+PARENT_ID: 父笔记的唯一标识符
+片段: 笔记的摘要
+类型: 笔记的类型
+WIDGET_ID: 关联的小部件的唯一标识符
+WIDGET_TYPE: 关联的小部件的类型
+SYNC_ID: 与笔记相关的同步服务的唯一标识符
+LOCAL_MODIFIED: 笔记是否在本地被修改过
+ORIGIN_PARENT_ID: 笔记的原始父笔记的唯一标识符
+GTASK_ID: 与Google Tasks相关的唯一标识符
+版本: 笔记的版本号
+这些列名可以用于查询笔记数据,并且在SqlNote类中被定义为静态常量,以便在整个应用程序中使用。*/
public static final int ID_COLUMN = 0;
public static final int ALERTED_DATE_COLUMN = 1;
@@ -85,7 +106,9 @@ public class SqlNote {
public static final int GTASK_ID_COLUMN = 15;
public static final int VERSION_COLUMN = 16;
-
+/*这是SqlNote类中定义的一些静态常量,它们表示在PROJECTION_NOTE数组中每个列名的索引位置。
+这些常量被用于访问查询结果中特定列的值。
+ */
private Context mContext;
private ContentResolver mContentResolver;
@@ -121,7 +144,28 @@ public class SqlNote {
private ContentValues mDiffNoteValues;
private ArrayList mDataList;
-
+/*这是SqlNote类中的一些成员变量,它们被用于存储笔记的数据。下面是每个变量的含义:
+mContext: 上下文对象,用于访问应用程序的资源和服务。
+mContentResolver: 内容解析器对象,用于访问应用程序的数据。
+mIsCreate: 表示这个对象是否代表一个新创建的笔记。
+mId: 笔记的唯一标识符。
+mAlertDate: 笔记提醒的日期。
+mBgColorId: 笔记背景颜色的标识符。
+mCreatedDate: 笔记创建的日期。
+mHasAttachment: 表示笔记是否有附件。
+mModifiedDate: 笔记最后修改的
+mParentId: 父笔记的唯一标识符。
+mSnippet: 笔记的摘要。
+mType: 笔记的类型。
+mWidgetId: 关联的小部件的唯一标识符。
+mWidgetType: 关联的小部件的类型。
+mOriginParent: 笔记的原始父笔记的唯一标识符。
+mVersion: 笔记的版本号。
+mDiffNoteValues: 一个ContentValues对象,包含了与这个笔记相关的差异数据。
+mDataList: 一个ArrayList对象,包含了这个笔记的子笔记数据。
+这些成员变量被用于存储SqlNote对象的状态,并且可以用于从数据库中读取和写入笔记数据。
+其中一些成员变量还可以用于在应用程序中显示笔记的相关信息。
+ */
public SqlNote(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -142,7 +186,26 @@ public class SqlNote {
mDiffNoteValues = new ContentValues();
mDataList = new ArrayList();
}
-
+/*这是SqlNote类的构造函数,它用于创建一个新的SqlNote对象。在构造函数中,SqlNote对象的所有成员变量都被初始化为它们的默认值。具体来说,它们的初始值如下:
+mContext: 传入的上下文对象。
+mContentResolver: 从上下文对象中获取的内容解析器对象。
+mIsCreate: 设置为true,表示这是一个新创建
+mId: 设置为INVALID_ID,表示这个笔记还没有在数据库中分配一个有效的唯一标识符。
+mAlertDate: 设置为0,表示这个笔记没有提醒日期。
+mBgColorId: 设置为应用程序的默认背景颜色。
+mCreatedDate: 设置为当前时间的毫秒数,表示这个笔记的创建日期。
+mHasAttachment: 设置为0,表示这个笔记没有附件。
+mModifiedDate: 设置为当前时间的毫秒数,表示这个笔记的最后修改日期。
+mParentId: 设置为0,表示这个笔记没有父笔记。
+mSnippet: 设置为空字符串,表示这个笔记没有摘要。
+mType: 设置为Notes.TYPE_NOTE,表示这个笔记是一个普通笔记。
+mWidgetId: 设置为AppWidgetManager.INVALID_APPWIDGET_ID,表示这个笔记没有关联的小部件。
+mWidgetType: 设置为Notes.TYPE_WIDGET_INVALIDE,表示这个笔记没有关联的小部件类型。
+mOriginParent: 设置为0,表示这个笔记没有原始父笔记。
+mVersion: 设置为0,表示这个笔记的版本号为0。
+mDiffNoteValues: 创建一个新的ContentValues对象,用于存储这个笔记的差异数据。
+mDataList: 创建一个新的ArrayList对象,用于存储这个笔记的子笔记数据。
+在构造函数中,所有的成员变量都被初始化为它们的默认值,因此这个SqlNote对象代表了一个刚刚创建的新笔记。*/
public SqlNote(Context context, Cursor c) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -153,7 +216,15 @@ public class SqlNote {
loadDataContent();
mDiffNoteValues = new ContentValues();
}
-
+/*这是SqlNote类的另一个构造函数,用于从数据库游标中加载已有的SqlNote对象。在构造函数中,SqlNote对象的所有成员变量都被初始化为它们从数据库中读取的值。具体来说:
+mContext: 传入的
+mContentResolver: 从上下文对象中获取的内容解析器
+mIsCreate: 设置为false,表示这个SqlNote对象代表的是一个已经存在于数据库中的笔记。
+loadFromCursor(c): 调用loadFromCursor()方法,从游标c中加载所有的笔记数据,包括笔记的标题、内容、创建日期、修改日期等等。
+mDataList: 创建一个新的ArrayList对象,用于存储
+loadDataContent(): 如果这个笔记是一个普通笔记,则调用loadDataContent()方法,从数据库中加载笔记的内容。
+mDiffNoteValues: 创建一个新的ContentValues对象,用于存储这个笔记的差异数据。
+通过这个构造函数,SqlNote对象可以从数据库中读取已有的笔记数据,并在内存中表示这个笔记。*/
public SqlNote(Context context, long id) {
mContext = context;
mContentResolver = context.getContentResolver();
@@ -165,7 +236,15 @@ public class SqlNote {
mDiffNoteValues = new ContentValues();
}
-
+/*这是SqlNote类的另一个构造函数,用于从数据库中加载指定id的SqlNote对象。在构造函数中,SqlNote对象的所有成员变量都被初始化为它们从数据库中读取的值。具体来说:
+mContext: 传入的上下文对象。
+mContentResolver: 从上下文对象中获取的内容解析器对象。
+mIsCreate: 设置为false,表示这个SqlNote对象代表的是一个已经存在于
+loadFromCursor(id): 调用loadFromCursor()方法,从数据库中加载指定id的笔记数据,包括笔记的标题、内容、创建日期、修改日期等等。
+mDataList: 创建一个新的ArrayList对象,用于存储这个笔记的子笔记数据。
+loadDataContent(): 如果这个笔记是一个普通笔记,则调用loadDataContent()方法,从数据库中加载笔记的内容。
+mDiffNoteValues: 创建一个新的ContentValues对象,用于存储这个笔记的差异数据。
+通过这个构造函数,SqlNote对象可以从数据库中读取指定id的笔记数据,并在内存中表示这个笔记。*/
private void loadFromCursor(long id) {
Cursor c = null;
try {
@@ -184,7 +263,11 @@ public class SqlNote {
c.close();
}
}
-
+/*这是SqlNote类的一个私有方法,用于从数据库中加载指定id的笔记数据。具体来说:
+首先,通过查询内容提供器Notes.CONTENT_NOTE_URI获取指定ID
+然后,如果游标不为null,将游标移到第一条记录,并调用loadFromCursor(Cursor c)方法,将游标中的所有记录加载到SqlNote对象中。
+最后,关闭游标对象。
+通过这个方法,SqlNote对象可以从数据库中查询指定id的笔记数据,并在内存中表示这个笔记。需要注意的是,在加载数据之后一定要及时关闭游标对象,以释放资源。*/
private void loadFromCursor(Cursor c) {
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
@@ -199,7 +282,22 @@ public class SqlNote {
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);
mVersion = c.getLong(VERSION_COLUMN);
}
-
+/*这是SqlNote类的一个私有方法,用于从游标中加载笔记数据。具体来说:
+通过游标对象c获取每个属性的值,并将其赋值给SqlNote对象的对应成员变量。
+其中,这些属性的含义如下:
+mId: 笔记的唯一标识符。
+mAlertDate: 笔记提醒时间,以毫秒为单位。
+mBgColorId: 笔记背景颜色的标识符。
+mCreatedDate: 笔记创建时间,以毫秒为单位。
+mHasAttachment: 笔记是否有附件(0表示没有,1表示有)。
+mModifiedDate: 笔记最近修改时间,以毫秒为单位。
+mParentId: 笔记的父笔记的唯一标识符。
+mSnippet: 笔记的摘要。
+mType: 笔记的类型,可以是普通笔记、清单笔记、便签等。
+mWidgetId: 笔记所关联的小部件的唯一标识符。
+mWidgetType: 笔记所关联的小部件的类型。
+m版本: 笔记的
+通过这个方法,SqlNote对象可以从游标中加载所有的笔记数据,并在内存中表示这个笔记。*/
private void loadDataContent() {
Cursor c = null;
mDataList.clear();
@@ -225,13 +323,24 @@ public class SqlNote {
c.close();
}
}
-
+/*这是SqlNote类的一个私有方法,用于从数据库中加载笔记的数据内容。具体来说:
+首先,通过查询内容提供器Notes.CONTENT_DATA_URI获取指定笔记ID的所有
+然后,清空数据列表mDataList。
+接着,如果游标不为null,遍历游标中的所有记录,并使用SqlData对象将每条记录转换成一个数据对象。将这些数据对象添加到数据列表mDataList中。
+最后,关闭游标对象。
+通过这个方法,SqlNote对象可以从数据库中查询指定笔记id的所有数据,将其转换成数据对象,并存储在内存中。需要注意的是,在加载数据之后一定要及时关闭游标对象,以释放资源。*/
public boolean setContent(JSONObject js) {
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
Log.w(TAG, "cannot set system folder");
- } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
+ }
+ /*这是SqlNote类的一个公有方法,用于设置笔记的内容。具体来说:
+ 首先,从Json对象js中获取笔记的元数据信息,即note对象。
+ 然后,判断获取的笔记类型是否为系统类型(Notes.TYPE_SYSTEM),如果是则输出警告信息并返回false。
+ 如果不是系统类型,则继续执行以下步骤。
+ 在这个方法中,对于非法的系统类型的笔记,将输出警告信息并返回false,不会更改SqlNote对象的内容。对于合法的笔记,该方法将根据传入的Json对象设置笔记的内容。但是,这个方法的具体实现并没有展示出来,需要查看该方法的后续代码才能了解更多信息。*/
+ else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
// for folder we can only update the snnipet and type
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
@@ -246,42 +355,60 @@ public class SqlNote {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
- } else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
+ }
+ /*如果获取的笔记类型是文件夹类型(Notes.TYPE_FOLDER),则该方法只能更新文件夹的片段(NoteColumns.SNIPPET)和类型(NoteColumns.TYPE)属性。
+ 如果传入的Json对象中包含片段属性(NoteColumns.SNIPPET),则将其值赋给片段变量,否则将其设置为空字符串。
+ 如果 SqlNote
+ 将当前的片段值(mSnippet)设置为获取的片段值(snippet)。
+ 如果传入的Json对象中包含类型属性(NoteColumns.TYPE),则将其值赋给type变量,否则将其设置为Notes.TYPE_NOTE(默认值)。
+ 如果 SqlNote
+ 将当前的类型值(mType)设置为获取的类型值(type)。
+ 通过这个方法,SqlNote对象可以根据传入的Json对象更新笔记的片段和类型属性。需要注意的是,对于文件夹类型的笔记,只能更新片段和类型属性,其他属性不能更改。*/
+ else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;
if (mIsCreate || mId != id) {
mDiffNoteValues.put(NoteColumns.ID, id);
}
mId = id;
-
+ /*代码检索到JSONArray叫dataArray从命名的 JSON 对象js.
+ 然后,代码检查是否
+ 如果mIsCreate为 true 或当前注释 ID 为mId不等于检索到的 ID,则代码将 ID 放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.ID常量作为键和检索到的 ID作为值。*/
long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note
.getLong(NoteColumns.ALERTED_DATE) : 0;
if (mIsCreate || mAlertDate != alertDate) {
mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate);
}
mAlertDate = alertDate;
-
+ /*通过调用has()方法上的方法NoteColumns.ALERTED_DATE不断。如果注释有警报日期,则警报日期通过调用getLong()方法上NoteColumns.ALERTED_DATE不断。否则,它将警报日期设置为 0。
+ 如果mIsCreate为 true 或当前警报日期mAlertDate不等于检索到的警报日期,则代码将警报日期放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.ALERTED_DATE常量作为键,检索到的警报日期作为值。
+ 最后,代码将检索到的警报日期分配给名为mAlertDate.仅从此代码块中不清楚此变量的用途,但它可以在程序的其他地方使用。*/
int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);
if (mIsCreate || mBgColorId != bgColorId) {
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);
}
mBgColorId = bgColorId;
-
+ /*代码检查
+ 如果mIsCreate为 true 或当前背景颜色 ID 为 truemBgColorId不等于检索到的背景颜色 ID,则代码将背景颜色 ID 放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.BG_COLOR_ID常量作为键和检索到的背景色标识为
+ 最后,代码将检索到的背景颜色 ID 分配给名为mBgColorId.仅从此代码块中不清楚此变量的用途,但它可以在程序的其他地方使用。*/
long createDate = note.has(NoteColumns.CREATED_DATE) ? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate != createDate) {
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);
}
mCreatedDate = createDate;
-
+ /*调用has()方法上的方法NoteColumns.CREATED_DATE不断。如果注释具有创建日期,代码通过调用getLong()方法上NoteColumns.CREATED_DATE不断。否则,它将创建日期设置为当前系统时间以毫秒为单位,通过调用System.currentTimeMillis()方法。
+ 如果是mIsCreatemCreatedDate不等于检索到的创建日期,则代码将创建日期放在HashMap叫mDiffNoteValues使用put()方法与NoteColumns.CREATED_DATE常量作为键,检索到的创建日期作为值。
+ 最后,代码将检索到的创建日期分配给名为mCreatedDate.*/
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment != hasAttachment) {
mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment);
}
mHasAttachment = hasAttachment;
-
+ /*检查注释是否具有附件。如果注释具有附件,则代码通过对常量调用方法来检索值。否则,它将值设置为 0。
+ 如果为 true,或者如果 的当前值不等于检索到的值,则代码使用以常量为键,检索到的值作为值的方法将值放入调用中。*/
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
if (mIsCreate || mModifiedDate != modifiedDate) {
@@ -323,14 +450,22 @@ public class SqlNote {
mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);
}
mWidgetType = widgetType;
-
+ /*这段代码在一个笔记应用中用于更新笔记的不同属性。下面是每个段的注释:
+ 首先检查笔记对象中是否包含最后修改日期属性,如果是则获取该属性的值,否则将当前时间作为最后修改日期。如果笔记对象是新创建的或最后修改日期与之前不同,则将其放入待更新的笔记属性集合中。最后将最后修改日期赋值给实例变量mModifiedDate。
+ 然后检查笔记对象中是否包含父笔记ID属性,如果是则获取该属性的值,否则将0作为父笔记ID。如果笔记对象是新创建的或父笔记ID与之前不同,则将其放入待更新的笔记属性集合中。最后将父笔记ID赋值给实例变量mParentId。
+ 接下来检查笔记对象中是否包含摘要属性,如果是则获取该属性的值,否则将空字符串作为摘要。如果笔记对象是新创建的或摘要与之前不同,则将其放入待更新的笔记属性集合中。最后将摘要赋值给实例变量mSnippet。
+ 然后检查笔记对象中是否包含类型属性,如果是则获取该属性的值,否则将默认类型Note作为类型。如果笔记对象是新创建的或类型与之前不同,则将其放入待更新的笔记属性集合中。最后将类型赋值给实例变量mType。
+ 接着检查笔记对象中是否包含小部件ID属性,如果是则获取该属性的值,否则将无效的小部件ID作为小部件ID。如果笔记对象是新创建的或小部件ID与之前不同,则将其放入待更新的笔记属性集合中。最后将小部件ID赋值给实例变量mWidgetId。
+ 最后检查笔记对象中是否包含小部件类型属性,如果是则获取该属性的值,否则将无效的小部件类型作为小部件类型。如果笔记对象是新创建的或小部件类型与之前不同,则将其放入待更新的笔记属性集合中。最后将小部件类型赋值给实例变量mWidgetType。*/
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;
if (mIsCreate || mOriginParent != originParent) {
mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent);
}
mOriginParent = originParent;
-
+ /*首先检查笔记对象中是否包含原始父笔记ID属性,如果是则获取该属性的值,否则将0作为原始父笔记ID
+ 如果笔记对象是新创建的或原始父笔记ID与之前不同,则将其放入待更新的笔记属性集合中。
+ 最后将原始父笔记ID赋值给实例变量mOriginParent。*/
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
SqlData sqlData = null;
@@ -342,12 +477,15 @@ public class SqlNote {
}
}
}
-
+ /*首先,使用for循环遍历数据数组中的每个JSON对象。
+ 然后,检查JSON对象是否具有ID属性。如果有,将其与数据列表中的每个SqlData对象进行比较,以查找具有相同ID的SqlData对象。如果找到了匹配的SqlData对象,则将其赋值给sqlData变量。
+ 如果未找到匹配项,则sqlData变量将保持为null。*/
if (sqlData == null) {
sqlData = new SqlData(mContext);
mDataList.add(sqlData);
}
-
+ /*如果在数据列表中未找到具有与JSON对象相同ID的SqlData对象,则创建一个新的SqlData对象,并将其添加到数据列表中。
+ 如果找到了匹配的SqlData对象,则sqlData变量已经被赋值为该对象,不需要进行其他处理。*/
sqlData.setContent(data);
}
}
@@ -358,7 +496,9 @@ public class SqlNote {
}
return true;
}
-
+/*如果找到了具有与JSON对象相同ID的SqlData对象,则调用该对象的setContent方法,并将JSON对象作为参数传递给该方法。该方法将使用JSON对象更新SqlData对象的属性值。如果未找到匹配的SqlData对象,则不需要进行任何处理。
+最后,try-catch语句用于捕获可能的JSONException异常,并在发生异常时打印错误信息。
+如果没有发生异常,则返回值为true。*/
public JSONObject getContent() {
try {
JSONObject js = new JSONObject();
@@ -367,7 +507,10 @@ public class SqlNote {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
-
+/*首先创建一个新的JSONObject对象。然后检查mIsCreate属性的值。
+如果为true,则表示该SqlData对象尚未被创建到数据库中,此时将打印一个错误信息,并返回null。
+否则,将使用put方法将SqlData对象的属性值逐个添加到JSONObject对象中。
+最后,返回包含SqlData对象属性值的JSONObject对象。*/
JSONObject note = new JSONObject();
if (mType == Notes.TYPE_NOTE) {
note.put(NoteColumns.ID, mId);
@@ -392,7 +535,11 @@ public class SqlNote {
}
}
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
- } else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {
+ }
+ /*首先创建一个新的JSONObject对象note,并使用put方法将SqlData对象的属性值逐个添加到该对象中。然后,将note对象添加到新创建的JSONObject对象js中,并使用put方法将其作为GTaskStringUtils.META_HEAD_NOTE键的值。
+ 接下来,创建一个新的JSONArray对象dataArray,并使用for循环遍历mDataList列表中的每个SqlData对象。对于每个SqlData对象,调用其getContent方法获取一个JSON对象,并检查该对象是否为null。如果不为null,则将其添加到dataArray数组中。
+ 最后,将dataArray数组添加到js对象中,并使用put方法将其作为GTaskStringUtils.META_HEAD_DATA键的值。如果mType属性不等于Notes.TYPE_NOTE,则不会将任何数据添加到js对象中。*/
+ else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.SNIPPET, mSnippet);
@@ -406,7 +553,9 @@ public class SqlNote {
}
return null;
}
-
+ /*如果mType属性等于Notes.TYPE_FOLDER或Notes.TYPE_SYSTEM,则创建一个新的JSONObject对象note,并使用put方法将SqlData对象的属性值逐个添加到该对象中。然后,将note对象添加到新创建的JSONObject对象js中,并使用put方法将其作为GTaskStringUtils.META_HEAD_NOTE键的值。
+ 如果发生JSONException异常,则在控制台中打印错误信息,并返回null。如果没有发生异常,则返回包含SqlData对象属性值的JSONObject对象。js
+ 总的来说,这段代码的作用是将SqlData对象的属性值转换为JSON格式,并将其添加到新创建的JSONObject对象中。*/
public void setParentId(long id) {
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
@@ -439,7 +588,14 @@ public class SqlNote {
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}
-
+ /*setParentId(long id): 将id参数值赋给mParentId属性,并使用put方法将NoteColumns.PARENT_ID和id添加到mDiffNoteValues对象中。
+ setGtaskId(String gid): 使用put方法将NoteColumns.GTASK_ID和gid添加到mDiffNoteValues对象中。
+ setSyncId(long syncId): 使用put方法将NoteColumns.SYNC_ID和syncId添加到mDiffNoteValues对象中。
+ resetLocalModified(): 使用put方法将和0添加到NoteColumns.LOCAL_MODIFIEDmDiffNoteValues对象中。该方法用于重置SqlData对象的本地修改标志。
+ getId(): 返回mId属性的值。
+ getParentId(): 返回mParentId属性的值。
+ getSnippet(): 返回mSnippet属性的值。
+ isNoteType(): 如果mType属性等于,则返回Notes.TYPE_NOTEtrue,否则返回false。该方法用于判断该SqlData对象是否是一个笔记类型的对象。*/
public void commit(boolean validateVersion) {
if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
@@ -462,7 +618,11 @@ public class SqlNote {
sqlData.commit(mId, false, -1);
}
}
- } else {
+ }
+ /*如果mIsCreate属性为true,则表示该SqlData对象是新创建的,需要将其写入数据库。如果mId属性的值等于INVALID_ID(即-1)并且mDiffNoteValues对象中包含NoteColumns.ID键,那么将该键从mDiffNoteValues对象中移除。然后,使用insert方法将mDiffNoteValues对象中的属性值添加到Notes.CONTENT_NOTE_URI中,并将返回的Uri对象赋给uri变量。
+ 接下来,使用getPathSegments方法获取uri对象中的路径段,并将第二个路径段(即路径中的第二个元素)转换为long类型,并将其赋给mId属性。如果在转换过程中发生NumberFormatException异常,则在控制台中打印错误信息并抛出ActionFailureException异常。如果mId属性的值等于0,则抛出IllegalStateException异常。
+ 如果属性等于,则表示该mTypeNotes.TYPE_NOTESqlData对象是一个笔记类型的对象,并且它包含一个mDataList列表,该列表中包含其他SqlData对象。在这种情况下,需要递归调用每个SqlData对象的commit方法,并将mId的值作为参数传递给该方法,以便将这些子对象插入到数据库中。*/
+ else {
if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {
Log.e(TAG, "No such note");
throw new IllegalStateException("Try to update note with invalid id");
@@ -503,3 +663,8 @@ public class SqlNote {
mIsCreate = false;
}
}
+/*如果mIsCreate属性为false,则表示该SqlData对象是已存在于数据库中的对象,需要更新其属性值。首先,需要检查mId属性的值是否为有效值。如果mId属性的值小于等于0且不等于Notes.ID_ROOT_FOLDER和Notes.ID_CALL_RECORD_FOLDER,则表示该笔记不存在,会打印错误信息并抛出IllegalStateException异常。然后,检查mDiffNoteValues对象是否包含要更新的属性值,如果包含,则需要更新笔记的版本号mVersion,并使用update方法将更改后的属性值写入数据库中。
+如果参数为validateVersiontrue,则表示需要验证版本号。在这种情况下,会将笔记的版本号mVersion作为参数传递给update方法,并在WHERE子句中添加一个条件,以确保要更新的笔记版本号小于等于当前版本号。如果validateVersion参数为false,则不需要验证版本号。
+如果更新操作成功,则方法会返回受影响的行数。如果返回值为0,则表示更新操作没有修改任何行,会在控制台中打印警告信息。update
+如果mType属性等于Notes.TYPE_NOTE,则表示该SqlData对象是一个笔记类型的对象,并且它包含一个mDataList列表,该列表中包含其他SqlData对象。在这种情况下,需要递归调用每个SqlData对象的commit方法,并将mId和validateVersion的值作为参数传递给该方法。
+最后,刷新本地信息,清空mDiffNoteValues对象中的属性值,将mIsCreate属性设置为false,并完成方法的执行。*/
\ No newline at end of file
diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/Task.java b/src/app/src/main/java/net/micode/notes/gtask/data/Task.java
index 6a19454..71cff3f 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/data/Task.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/data/Task.java
@@ -53,10 +53,22 @@ public class Task extends Node {
mParent = null;
mMetaInfo = null;
}
-
+/*这是一个名为Task的Java类,它继承自Node类。Task类有以下成员变量:
+mCompleted:表示任务是否已完成,类型为布尔值。
+mNotes:表示任务的笔记,类型为字符串。
+mMetaInfo:表示任务的元信息,类型为JSONObject对象。
+mPriorSibling:表示前一个同级任务,类型为Task对象。
+mParent:表示任务所属的任务列表,类型为TaskList对象。
+Task类还有一个无参数构造函数,它会将mCompleted、mNotes、、mPriorSiblingmParent和mMetaInfo都初始化为null或false。
+继承自Node类的成员变量和方法没有在这个代码片段中给出,但是可以推测出Node类是一个表示树节点的基类,TaskList类是一个表示任务列表的类。在Task类中,mPriorSibling和mParent成员变量用于表示任务在任务列表中的位置,mMetaInfo成员变量用于存储一些其他的任务信息。*/
public JSONObject getCreateAction(int actionId) {
JSONObject js = new JSONObject();
-
+/*该方法返回一个JSONObject对象,用于表示创建一个动作的操作。
+该方法有一个整数类型的参数actionId,用于指定要创建的动作的ID。
+方法主体中,首先创建一个空的JSONObject对象js。
+然后,会往该对象中添加一个表示要执行的操作类型的键值对,该键值对的键为"type",值为"action"。
+接着,会添加一个表示要创建的动作ID的键值对,该键值对的键为"action_id",值为actionId参数的值。
+最后,将js对象返回。*/
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
@@ -74,6 +86,12 @@ public class Task extends Node {
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK);
+ /*在上述代码中,getCreateAction方法中的JSONObject js对象被初始化之后,首先向其中添加一个表示操作类型的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_ACTION_TYPE,值为GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE。
+ 接着,会添加一个表示要创建的动作ID的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_ACTION_ID,值为actionId参数的值。
+ 然后,会添加一个表示任务在任务列表中的位置的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_INDEX,值为当前任务在其父任务列表中的位置,通过调用mParent.getChildTaskIndex(this)方法获得。
+ 最后,会添加一个表示任务实体的键值对,该键值对的键为"entity_delta",值为一个新的JSONObject对象entity。entity对象中包含三个键值对,分别为任务名称、创建者ID和任务类型。
+ 其中,任务名称通过getName()方法获取,创建者ID为"null",任务类型为GTaskStringUtils.GTASK_JSON_TYPE_TASK。
+ 最终,js对象中包含了所有要创建动作所需的信息,并将其返回。*/
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
@@ -88,7 +106,11 @@ public class Task extends Node {
// list_id
js.put(GTaskStringUtils.GTASK_JSON_LIST_ID, mParent.getGid());
-
+ /*在上述代码中,如果当前任务存在笔记,则会向entity对象中添加一个表示笔记内容的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_NOTES,值为当前任务的笔记内容,通过调用getNotes()方法获取。然后,将entity对象添加为js对象的一个子对象,键为GTaskStringUtils.GTASK_JSON_ENTITY_DELTA。
+ 接着,会添加一个表示当前任务所属的任务列表ID的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_PARENT_ID,值为当前任务所属任务列表的GID,通过调用mParent.getGid()方法获取。
+ 然后,会添加一个表示当前任务所属的任务列表类型的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_DEST_PARENT_TYPE,值为GTaskStringUtils.GTASK_JSON_TYPE_GROUP,表示当前任务所属的任务列表是一个组。
+ 最后,会添加一个表示当前任务所属的任务列表ID的键值对,该键值对的键为GTaskStringUtils.GTASK_JSON_LIST_ID,值为当前任务所属任务列表的GID。
+ 最终,js对象中包含了所有创建动作所需的信息,并将其返回。*/
// prior_sibling_id
if (mPriorSibling != null) {
js.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, mPriorSibling.getGid());
@@ -101,69 +123,75 @@ public class Task extends Node {
}
return js;
- }
+ }/*添加一个表示当前任务的前一个兄弟任务ID的键值对。
+ 如果当前任务的前一个兄弟任务不为空,则会向 js 对象中添加一个表示前一个兄弟任务ID的键值对,该键值对的键为 GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID,值为前一个兄弟任务的 GID,通过调用 mPriorSibling.getGid() 方法获取。
+ 这个键值对表示当前任务是前一个兄弟任务的下一个兄弟任务,也就是将当前任务插入到前一个兄弟任务后面。如果添加键值对时出现 JSONException 异常,则会打印异常信息,并抛出 ActionFailureException 异常。
+ 最后,返回表示创建任务的动作的 JSONObject 对象。*/
public JSONObject getUpdateAction(int actionId) {
JSONObject js = new JSONObject();
try {
- // action_type
+ // 将 action_type 字段设置为 GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
- // action_id
+ // 将 action_id 字段设置为传入的 actionId 参数
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
- // id
+ // 将 id 字段设置为当前任务的 GID
js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
- // entity_delta
+ // 将 entity_delta 字段设置为一个 JSONObject 对象,
+ // 该对象表示要更新的任务的属性和值
JSONObject entity = new JSONObject();
- entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
- if (getNotes() != null) {
+ entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 任务名称
+ if (getNotes() != null) { // 如果任务的注释不为空,则添加注释字段
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
- entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
+ entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 任务是否被删除
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
} catch (JSONException e) {
+ // 如果出现 JSONException 异常,则打印异常信息,并抛出 ActionFailureException 异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-update jsonobject");
}
+ // 返回表示更新任务的动作的 JSONObject 对象
return js;
}
public void setContentByRemoteJSON(JSONObject js) {
if (js != null) {
try {
- // id
+ // 解析 id 字段,将其设置为本地任务对象的 GID
if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
}
- // last_modified
+ // 解析 last_modified 字段,将其设置为本地任务对象的最后修改时间
if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
}
- // name
+ // 解析 name 字段,将其设置为本地任务对象的名称
if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
}
- // notes
+ // 解析 notes 字段,将其设置为本地任务对象的注释
if (js.has(GTaskStringUtils.GTASK_JSON_NOTES)) {
setNotes(js.getString(GTaskStringUtils.GTASK_JSON_NOTES));
}
- // deleted
+ // 解析 deleted 字段,将其设置为本地任务对象的删除状态
if (js.has(GTaskStringUtils.GTASK_JSON_DELETED)) {
setDeleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_DELETED));
}
- // completed
+ // 解析 completed 字段,将其设置为本地任务对象的完成状态
if (js.has(GTaskStringUtils.GTASK_JSON_COMPLETED)) {
setCompleted(js.getBoolean(GTaskStringUtils.GTASK_JSON_COMPLETED));
}
@@ -182,14 +210,19 @@ public class Task extends Node {
}
try {
+ // 解析任务的注释信息
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
+
+ // 解析任务的数据信息
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
+ // 检查任务的类型是否为 Notes.TYPE_NOTE
if (note.getInt(NoteColumns.TYPE) != Notes.TYPE_NOTE) {
Log.e(TAG, "invalid type");
return;
}
+ // 解析任务的名称
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
@@ -206,14 +239,16 @@ public class Task extends Node {
public JSONObject getLocalJSONFromContent() {
String name = getName();
+
try {
if (mMetaInfo == null) {
- // new task created from web
+ // 如果当前任务对象没有元信息,则表示该任务是从 Web 创建的
if (name == null) {
Log.w(TAG, "the note seems to be an empty one");
return null;
}
+ // 创建一个新的 JSONObject,并将任务的名称添加到其中
JSONObject js = new JSONObject();
JSONObject note = new JSONObject();
JSONArray dataArray = new JSONArray();
@@ -225,10 +260,11 @@ public class Task extends Node {
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
return js;
} else {
- // synced task
+ // 如果当前任务对象有元信息,则表示该任务是同步过来的
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
+ // 遍历任务的数据信息,找到 MIME_TYPE 为 DataConstants.NOTE 的 JSONObject,并将其 CONTENT 字段设置为任务的名称
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
@@ -237,6 +273,7 @@ public class Task extends Node {
}
}
+ // 将任务的类型设置为 Notes.TYPE_NOTE,并返回元信息对象
note.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
return mMetaInfo;
}
@@ -247,9 +284,11 @@ public class Task extends Node {
}
}
+
public void setMetaInfo(MetaData metaData) {
if (metaData != null && metaData.getNotes() != null) {
try {
+ // 将元数据对象的 notes 字段转换为 JSONObject 对象,并存储在当前对象的 mMetaInfo 变量中
mMetaInfo = new JSONObject(metaData.getNotes());
} catch (JSONException e) {
Log.w(TAG, e.toString());
@@ -261,45 +300,49 @@ public class Task extends Node {
public int getSyncAction(Cursor c) {
try {
JSONObject noteInfo = null;
+ // 从 mMetaInfo 变量中获取笔记的元数据信息
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {
+ // 如果笔记的元数据信息不存在,则需要更新远程数据
Log.w(TAG, "it seems that note meta has been deleted");
return SYNC_ACTION_UPDATE_REMOTE;
}
if (!noteInfo.has(NoteColumns.ID)) {
+ // 如果笔记的元数据信息中没有 ID 字段,则需要更新本地数据
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
}
- // validate the note id now
+ // 检查笔记的 ID 是否匹配
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
Log.w(TAG, "note id doesn't match");
return SYNC_ACTION_UPDATE_LOCAL;
}
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
- // there is no local update
+ // 如果本地没有修改笔记,则比较修改时间来判断是否需要更新数据
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
- // no update both side
+ // 本地和远程都没有修改,无需同步
return SYNC_ACTION_NONE;
} else {
- // apply remote to local
+ // 将远程数据应用到本地
return SYNC_ACTION_UPDATE_LOCAL;
}
} else {
- // validate gtask id
+ // 如果本地有修改笔记,则需要比较修改时间和 GTask ID 来判断同步操作
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
return SYNC_ACTION_ERROR;
}
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
- // local modification only
+ // 只有本地有修改,将本地数据更新到远程
return SYNC_ACTION_UPDATE_REMOTE;
} else {
+ // 本地和远程都有修改,需要解决冲突
return SYNC_ACTION_UPDATE_CONFLICT;
}
}
@@ -312,39 +355,49 @@ public class Task extends Node {
}
public boolean isWorthSaving() {
- return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
- || (getNotes() != null && getNotes().trim().length() > 0);
+ // 判断对象是否值得保存
+ return mMetaInfo != null // 如果 mMetaInfo 不为空
+ || (getName() != null && getName().trim().length() > 0) // 或者 name 不为空且去除空格后长度大于 0
+ || (getNotes() != null && getNotes().trim().length() > 0); // 或者 notes 不为空且去除空格后长度大于 0
}
public void setCompleted(boolean completed) {
+ // 设置对象的 mCompleted 变量为给定的布尔值
this.mCompleted = completed;
}
public void setNotes(String notes) {
+ // 设置对象的 mNotes 变量为给定的字符串
this.mNotes = notes;
}
public void setPriorSibling(Task priorSibling) {
+ // 设置对象的 mPriorSibling 变量为给定的 Task 对象
this.mPriorSibling = priorSibling;
}
public void setParent(TaskList parent) {
+ // 设置对象的 mParent 变量为给定的 TaskList 对象
this.mParent = parent;
}
public boolean getCompleted() {
+ // 返回对象的 mCompleted 变量
return this.mCompleted;
}
public String getNotes() {
+ // 返回对象的 mNotes 变量
return this.mNotes;
}
public Task getPriorSibling() {
+ // 返回对象的 mPriorSibling 变量,其中 mPriorSibling 是一个 Task 对象
return this.mPriorSibling;
}
public TaskList getParent() {
+ // 返回对象的 mParent 变量,其中 mParent 是一个 TaskList 对象
return this.mParent;
}
diff --git a/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java b/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java
index 4ea21c5..579f8f8 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/data/TaskList.java
@@ -31,180 +31,189 @@ import java.util.ArrayList;
public class TaskList extends Node {
+ // 定义一个 TaskList 类,继承自 Node 类
+
private static final String TAG = TaskList.class.getSimpleName();
+ // 定义一个 TAG 常量,类型为字符串,值为 TaskList 类的简单名称
private int mIndex;
+ // 定义一个整型变量 mIndex,用于存储任务列表的索引值
private ArrayList mChildren;
+ // 定义一个 ArrayList 类型的 mChildren 变量,用于存储该任务列表的子任务列表
public TaskList() {
+ // 默认构造方法
+
super();
+ // 调用父类的默认构造方法
+
mChildren = new ArrayList();
+ // 初始化 mChildren 变量为一个新的空的 ArrayList
+
mIndex = 1;
+ // 初始化 mIndex 变量为 1
}
public JSONObject getCreateAction(int actionId) {
- JSONObject js = new JSONObject();
+ JSONObject js = new JSONObject(); // 创建一个新的 JSONObject 对象
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
- GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
+ GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE); // 添加 action_type 键值对,值为 "create"
// action_id
- js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
+ js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 添加 action_id 键值对,值为传入的参数 actionId
// index
- js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex);
+ js.put(GTaskStringUtils.GTASK_JSON_INDEX, mIndex); // 添加 index 键值对,值为成员变量 mIndex 的值
// entity_delta
- JSONObject entity = new JSONObject();
- entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
- entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
+ JSONObject entity = new JSONObject(); // 创建一个新的 JSONObject 对象,用于表示实体的 delta
+ entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 添加 name 键值对,值为 getName() 方法的返回值
+ entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null"); // 添加 creator_id 键值对,值为 "null"
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
- GTaskStringUtils.GTASK_JSON_TYPE_GROUP);
- js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
+ GTaskStringUtils.GTASK_JSON_TYPE_GROUP); // 添加 entity_type 键值对,值为 "GROUP"
+ js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加 entity_delta 键值对,值为上面创建的 entity 对象
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
+ } catch (JSONException e) { // 如果在添加键值对的过程中出现 JSONException 异常
+ Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息
e.printStackTrace();
- throw new ActionFailureException("fail to generate tasklist-create jsonobject");
+ throw new ActionFailureException("fail to generate tasklist-create jsonobject"); // 抛出一个自定义异常 ActionFailureException,并传递一个异常信息字符串
}
- return js;
+ return js; // 返回创建的 JSONObject 对象
}
public JSONObject getUpdateAction(int actionId) {
- JSONObject js = new JSONObject();
+ JSONObject js = new JSONObject(); // 创建一个新的 JSONObject 对象
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
- GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE);
+ GTaskStringUtils.GTASK_JSON_ACTION_TYPE_UPDATE); // 添加 action_type 键值对,值为 "update"
// action_id
- js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
+ js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId); // 添加 action_id 键值对,值为传入的参数 actionId
// id
- js.put(GTaskStringUtils.GTASK_JSON_ID, getGid());
+ js.put(GTaskStringUtils.GTASK_JSON_ID, getGid()); // 添加 id 键值对,值为调用 getGid() 方法的返回值,表示任务列表的全局唯一标识符
// entity_delta
- JSONObject entity = new JSONObject();
- entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
- entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted());
- js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
+ JSONObject entity = new JSONObject(); // 创建一个新的 JSONObject 对象,用于表示实体的 delta
+ entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName()); // 添加 name 键值对,值为 getName() 方法的返回值,表示任务列表的名称
+ entity.put(GTaskStringUtils.GTASK_JSON_DELETED, getDeleted()); // 添加 deleted 键值对,值为 getDeleted() 方法的返回值,表示任务列表是否被删除
+ js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity); // 添加 entity_delta 键值对,值为上面创建的 entity 对象
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
+ } catch (JSONException e) { // 如果在添加键值对的过程中出现 JSONException 异常
+ Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息
e.printStackTrace();
- throw new ActionFailureException("fail to generate tasklist-update jsonobject");
+ throw new ActionFailureException("fail to generate tasklist-update jsonobject"); // 抛出一个自定义异常 ActionFailureException,并传递一个异常信息字符串
}
- return js;
+ return js; // 返回创建的 JSONObject 对象
}
public void setContentByRemoteJSON(JSONObject js) {
- if (js != null) {
+ if (js != null) { // 如果传入的 JSONObject 对象不为 null
try {
// id
- if (js.has(GTaskStringUtils.GTASK_JSON_ID)) {
- setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID));
+ if (js.has(GTaskStringUtils.GTASK_JSON_ID)) { // 如果 JSONObject 对象中包含 id 键值对
+ setGid(js.getString(GTaskStringUtils.GTASK_JSON_ID)); // 将 id 键对应的值作为参数调用 setGid() 方法,将任务列表的全局唯一标识符设置为该值
}
// last_modified
- if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) {
- setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED));
+ if (js.has(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)) { // 如果 JSONObject 对象中包含 last_modified 键值对
+ setLastModified(js.getLong(GTaskStringUtils.GTASK_JSON_LAST_MODIFIED)); // 将 last_modified 键对应的值作为参数调用 setLastModified() 方法,将任务列表的最后修改时间设置为该值
}
// name
- if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) {
- setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME));
+ if (js.has(GTaskStringUtils.GTASK_JSON_NAME)) { // 如果 JSONObject 对象中包含 name 键值对
+ setName(js.getString(GTaskStringUtils.GTASK_JSON_NAME)); // 将 name 键对应的值作为参数调用 setName() 方法,将任务列表的名称设置为该值
}
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
+ } catch (JSONException e) { // 如果在读取键值对的过程中出现 JSONException 异常
+ Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息
e.printStackTrace();
- throw new ActionFailureException("fail to get tasklist content from jsonobject");
+ throw new ActionFailureException("fail to get tasklist content from jsonobject"); // 抛出一个自定义异常 ActionFailureException,并传递一个异常信息字符串
}
}
}
public void setContentByLocalJSON(JSONObject js) {
- if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) {
- Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
+ if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)) { // 如果传入的 JSONObject 对象为 null,或者它不包含 META_HEAD_NOTE 键值对
+ Log.w(TAG, "setContentByLocalJSON: nothing is avaiable"); // 打印一条警告日志,表示没有可用的信息
}
try {
- JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
-
- if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
- String name = folder.getString(NoteColumns.SNIPPET);
- setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name);
- } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
- if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER)
- setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT);
- else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER)
- setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
- + GTaskStringUtils.FOLDER_CALL_NOTE);
+ JSONObject folder = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); // 获取 META_HEAD_NOTE 键对应的值,该值应该是一个 JSON 对象,表示笔记的元信息
+
+ if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) { // 如果元信息中的 TYPE 键对应的值为 TYPE_FOLDER,表示这是一个文件夹笔记
+ String name = folder.getString(NoteColumns.SNIPPET); // 获取元信息中的 SNIPPET 键对应的值,该值应该是文件夹的名称
+ setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + name); // 将文件夹名称加上一个前缀字符串,作为任务列表的名称
+ } else if (folder.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) { // 如果元信息中的 TYPE 键对应的值为 TYPE_SYSTEM,表示这是一个系统笔记
+ if (folder.getLong(NoteColumns.ID) == Notes.ID_ROOT_FOLDER) // 如果元信息中的 ID 键对应的值为 ID_ROOT_FOLDER,表示这是根文件夹笔记
+ setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT); // 将默认的任务列表名称设置为 MIUI_FOLDER_PREFFIX + FOLDER_DEFAULT
+ else if (folder.getLong(NoteColumns.ID) == Notes.ID_CALL_RECORD_FOLDER) // 如果元信息中的 ID 键对应的值为 ID_CALL_RECORD_FOLDER,表示这是一条来电记录笔记
+ setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE); // 将来电记录的任务列表名称设置为 MIUI_FOLDER_PREFFIX + FOLDER_CALL_NOTE
else
- Log.e(TAG, "invalid system folder");
+ Log.e(TAG, "invalid system folder"); // 如果元信息中的 TYPE 和 ID 值都不符合要求,打印一条错误日志
} else {
- Log.e(TAG, "error type");
+ Log.e(TAG, "error type"); // 如果元信息中的 TYPE 键对应的值既不是 TYPE_FOLDER,也不是 TYPE_SYSTEM,打印一条错误日志
}
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
+ } catch (JSONException e) { // 如果在读取元信息的过程中出现 JSONException 异常
+ Log.e(TAG, e.toString()); // 打印异常堆栈跟踪信息
e.printStackTrace();
}
}
public JSONObject getLocalJSONFromContent() {
try {
- JSONObject js = new JSONObject();
- JSONObject folder = new JSONObject();
-
- String folderName = getName();
- if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX))
- folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(),
- folderName.length());
- folder.put(NoteColumns.SNIPPET, folderName);
- if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT)
- || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE))
- folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
+ JSONObject js = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONObject folder = new JSONObject(); // 创建一个新的 JSONObject 对象,表示笔记的元信息
+
+ String folderName = getName(); // 获取任务列表名称
+ if (getName().startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)) // 如果任务列表名称以 MIUI_FOLDER_PREFFIX 开头
+ folderName = folderName.substring(GTaskStringUtils.MIUI_FOLDER_PREFFIX.length(), folderName.length()); // 将 MIUI_FOLDER_PREFFIX 从任务列表名称中去掉
+ folder.put(NoteColumns.SNIPPET, folderName); // 将去掉 MIUI_FOLDER_PREFFIX 的任务列表名称存入元信息中的 SNIPPET 键
+
+ if (folderName.equals(GTaskStringUtils.FOLDER_DEFAULT) || folderName.equals(GTaskStringUtils.FOLDER_CALL_NOTE)) // 如果任务列表名称是默认任务列表或来电记录任务列表
+ folder.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM); // 将元信息中的 TYPE 键设置为 TYPE_SYSTEM
else
- folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
+ folder.put(NoteColumns.TYPE, Notes.TYPE_FOLDER); // 否则将元信息中的 TYPE 键设置为 TYPE_FOLDER
- js.put(GTaskStringUtils.META_HEAD_NOTE, folder);
+ js.put(GTaskStringUtils.META_HEAD_NOTE, folder); // 将元信息对象存入 js 对象中,以 META_HEAD_NOTE 键为键名
- return js;
- } catch (JSONException e) {
- Log.e(TAG, e.toString());
+ return js; // 返回创建好的 JSONObject 对象
+ } catch (JSONException e) { // 如果在创建 JSONObject 对象的过程中出现异常
+ Log.e(TAG, e.toString()); // 打印异常信息
e.printStackTrace();
- return null;
+ return null; // 返回 null
}
}
public int getSyncAction(Cursor c) {
try {
- if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
- // there is no local update
- if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
- // no update both side
+ if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) { // 如果本地没有更新
+ if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { // 如果本地最后一次修改时间与云端最后一次修改时间相同
+ // 两边都没有更新
return SYNC_ACTION_NONE;
} else {
- // apply remote to local
+ // 将云端的修改应用到本地
return SYNC_ACTION_UPDATE_LOCAL;
}
- } else {
- // validate gtask id
+ } else { // 如果本地有更新
+ // 验证 gtask id 是否匹配
if (!c.getString(SqlNote.GTASK_ID_COLUMN).equals(getGid())) {
Log.e(TAG, "gtask id doesn't match");
return SYNC_ACTION_ERROR;
}
- if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
- // local modification only
+ if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) { // 如果本地最后一次修改时间与云端最后一次修改时间相同
+ // 只有本地修改
return SYNC_ACTION_UPDATE_REMOTE;
} else {
- // for folder conflicts, just apply local modification
+ // 对于文件夹冲突,只应用本地修改
return SYNC_ACTION_UPDATE_REMOTE;
}
}
@@ -213,38 +222,37 @@ public class TaskList extends Node {
e.printStackTrace();
}
- return SYNC_ACTION_ERROR;
+ return SYNC_ACTION_ERROR; // 如果在执行过程中出现异常,返回 SYNC_ACTION_ERROR
}
public int getChildTaskCount() {
return mChildren.size();
- }
+ }//返回一个私有成员变量mChildren中存储的子任务数量
public boolean addChildTask(Task task) {
boolean ret = false;
- if (task != null && !mChildren.contains(task)) {
- ret = mChildren.add(task);
+ if (task != null && !mChildren.contains(task)) { // 如果任务不为空且不包含在子任务列表中
+ ret = mChildren.add(task); // 添加任务到子任务列表中
if (ret) {
- // need to set prior sibling and parent
- task.setPriorSibling(mChildren.isEmpty() ? null : mChildren
- .get(mChildren.size() - 1));
- task.setParent(this);
+ // 需要设置前一个兄弟和父任务
+ task.setPriorSibling(mChildren.isEmpty() ? null : mChildren.get(mChildren.size() - 1)); // 设置前一个兄弟,如果子任务列表为空,则前一个兄弟为 null
+ task.setParent(this); // 设置父任务为当前任务
}
}
return ret;
}
public boolean addChildTask(Task task, int index) {
- if (index < 0 || index > mChildren.size()) {
- Log.e(TAG, "add child task: invalid index");
+ if (index < 0 || index > mChildren.size()) { // 如果索引位置小于 0 或大于子任务列表的大小
+ Log.e(TAG, "add child task: invalid index"); // 打印错误日志
return false;
}
- int pos = mChildren.indexOf(task);
- if (task != null && pos == -1) {
- mChildren.add(index, task);
+ int pos = mChildren.indexOf(task); // 获取任务在子任务列表中的位置
+ if (task != null && pos == -1) { // 如果任务不为空且不在子任务列表中
+ mChildren.add(index, task); // 在指定索引位置添加任务
- // update the task list
+ // 更新任务列表
Task preTask = null;
Task afterTask = null;
if (index != 0)
@@ -252,9 +260,9 @@ public class TaskList extends Node {
if (index != mChildren.size() - 1)
afterTask = mChildren.get(index + 1);
- task.setPriorSibling(preTask);
+ task.setPriorSibling(preTask); // 设置前一个兄弟任务
if (afterTask != null)
- afterTask.setPriorSibling(task);
+ afterTask.setPriorSibling(task); // 设置后一个兄弟任务的前一个兄弟任务为当前任务
}
return true;
@@ -262,16 +270,16 @@ public class TaskList extends Node {
public boolean removeChildTask(Task task) {
boolean ret = false;
- int index = mChildren.indexOf(task);
- if (index != -1) {
- ret = mChildren.remove(task);
+ int index = mChildren.indexOf(task); // 获取任务在子任务列表中的位置
+ if (index != -1) { // 如果任务在子任务列表中
+ ret = mChildren.remove(task); // 从子任务列表中移除任务
if (ret) {
- // reset prior sibling and parent
+ // 重置前一个兄弟任务和父任务
task.setPriorSibling(null);
task.setParent(null);
- // update the task list
+ // 更新任务列表
if (index != mChildren.size()) {
mChildren.get(index).setPriorSibling(
index == 0 ? null : mChildren.get(index - 1));
@@ -282,62 +290,61 @@ public class TaskList extends Node {
}
public boolean moveChildTask(Task task, int index) {
-
- if (index < 0 || index >= mChildren.size()) {
- Log.e(TAG, "move child task: invalid index");
+ if (index < 0 || index >= mChildren.size()) { // 如果索引位置小于 0 或大于等于子任务列表的大小
+ Log.e(TAG, "move child task: invalid index"); // 打印错误日志
return false;
}
- int pos = mChildren.indexOf(task);
- if (pos == -1) {
- Log.e(TAG, "move child task: the task should in the list");
+ int pos = mChildren.indexOf(task); // 获取任务在子任务列表中的位置
+ if (pos == -1) { // 如果任务不在子任务列表中
+ Log.e(TAG, "move child task: the task should in the list"); // 打印错误日志
return false;
}
if (pos == index)
return true;
- return (removeChildTask(task) && addChildTask(task, index));
+ return (removeChildTask(task) && addChildTask(task, index)); // 先将任务从原位置移除,再将其移动到新位置
}
public Task findChildTaskByGid(String gid) {
- for (int i = 0; i < mChildren.size(); i++) {
+ for (int i = 0; i < mChildren.size(); i++) { // 遍历子任务列表
Task t = mChildren.get(i);
- if (t.getGid().equals(gid)) {
- return t;
+ if (t.getGid().equals(gid)) { // 如果找到了 GID 匹配的任务
+ return t; // 返回该任务
}
}
- return null;
+ return null; // 如果没有找到匹配的任务,则返回 null
}
public int getChildTaskIndex(Task task) {
- return mChildren.indexOf(task);
+ return mChildren.indexOf(task); // 获取指定任务在子任务列表中的位置
}
public Task getChildTaskByIndex(int index) {
- if (index < 0 || index >= mChildren.size()) {
- Log.e(TAG, "getTaskByIndex: invalid index");
+ if (index < 0 || index >= mChildren.size()) { // 如果索引位置小于 0 或大于等于子任务列表的大小
+ Log.e(TAG, "getTaskByIndex: invalid index"); // 打印错误日志
return null;
}
- return mChildren.get(index);
+ return mChildren.get(index); // 返回指定位置的任务
}
public Task getChilTaskByGid(String gid) {
- for (Task task : mChildren) {
- if (task.getGid().equals(gid))
- return task;
+ for (Task task : mChildren) { // 遍历子任务列表中的所有任务
+ if (task.getGid().equals(gid)) // 如果找到了 GID 匹配的任务
+ return task; // 返回该任务
}
- return null;
+ return null; // 如果没有找到匹配的任务,则返回 null
}
public ArrayList getChildTaskList() {
- return this.mChildren;
+ return this.mChildren; // 返回子任务列表
}
public void setIndex(int index) {
- this.mIndex = index;
+ this.mIndex = index; // 设置任务列表的索引位置
}
public int getIndex() {
- return this.mIndex;
+ return this.mIndex; // 获取任务列表的索引位置
}
}
diff --git a/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java b/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java
index 15504be..3579e44 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/exception/ActionFailureException.java
@@ -17,17 +17,18 @@
package net.micode.notes.gtask.exception;
public class ActionFailureException extends RuntimeException {
+
private static final long serialVersionUID = 4425249765923293627L;
public ActionFailureException() {
- super();
+ super(); // 调用父类的构造函数
}
public ActionFailureException(String paramString) {
- super(paramString);
+ super(paramString); // 调用父类的构造函数,并传入异常信息
}
public ActionFailureException(String paramString, Throwable paramThrowable) {
- super(paramString, paramThrowable);
+ super(paramString, paramThrowable); // 调用父类的构造函数,并传入异常信息和原始异常
}
}
diff --git a/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java b/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java
index b08cfb1..c6a2691 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/exception/NetworkFailureException.java
@@ -17,17 +17,18 @@
package net.micode.notes.gtask.exception;
public class NetworkFailureException extends Exception {
+
private static final long serialVersionUID = 2107610287180234136L;
public NetworkFailureException() {
- super();
+ super(); // 调用父类的构造函数
}
public NetworkFailureException(String paramString) {
- super(paramString);
+ super(paramString); // 调用父类的构造函数,并传入异常信息
}
public NetworkFailureException(String paramString, Throwable paramThrowable) {
- super(paramString, paramThrowable);
+ super(paramString, paramThrowable); // 调用父类的构造函数,并传入异常信息和原始异常
}
}
diff --git a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
index 2315ef1..c88aef0 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskASyncTask.java
@@ -37,82 +37,82 @@ public class GTaskASyncTask extends AsyncTask {
void onComplete();
}
- private Context mContext;
+ private Context mContext; // 上下文对象
- private NotificationManager mNotifiManager;
+ private NotificationManager mNotifiManager; // 通知管理器对象
- private GTaskManager mTaskManager;
+ private GTaskManager mTaskManager; // GTask 管理器对象
- private OnCompleteListener mOnCompleteListener;
+ private OnCompleteListener mOnCompleteListener; // 异步任务完成后的回调接口
public GTaskASyncTask(Context context, OnCompleteListener listener) {
- mContext = context;
- mOnCompleteListener = listener;
+ mContext = context; // 初始化上下文对象
+ mOnCompleteListener = listener; // 初始化回调接口
mNotifiManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
- mTaskManager = GTaskManager.getInstance();
+ .getSystemService(Context.NOTIFICATION_SERVICE); // 初始化通知管理器对象
+ mTaskManager = GTaskManager.getInstance(); // 获取 GTask 管理器对象的单例
}
public void cancelSync() {
- mTaskManager.cancelSync();
+ mTaskManager.cancelSync(); // 取消 GTask 同步
}
public void publishProgess(String message) {
publishProgress(new String[] {
- message
- });
+ 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;
+ .getString(tickerId), System.currentTimeMillis()); // 创建通知
+ notification.defaults = Notification.DEFAULT_LIGHTS; // 设置默认的通知灯光
+ notification.flags = Notification.FLAG_AUTO_CANCEL; // 设置通知被点击后自动取消
PendingIntent pendingIntent;
- if (tickerId != R.string.ticker_success) {
+ if (tickerId != R.string.ticker_success) { // 如果是同步失败的通知
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
- NotesPreferenceActivity.class), 0);
+ NotesPreferenceActivity.class), 0); // 点击通知后打开 NotesPreferenceActivity
- } else {
+ } else { // 如果是同步成功的通知
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,
- NotesListActivity.class), 0);
+ NotesListActivity.class), 0); // 点击通知后打开 NotesListActivity
}
//notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
- // pendingIntent);
- mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);
+ // pendingIntent); // 设置通知的标题、内容和点击后的操作
+ mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); // 发送通知
}
@Override
protected Integer doInBackground(Void... unused) {
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity
- .getSyncAccountName(mContext)));
- return mTaskManager.sync(mContext, this);
+ .getSyncAccountName(mContext))); // 向主线程发布进度更新,显示正在登录的提示信息
+ return mTaskManager.sync(mContext, this); // 开始 GTask 同步,并返回同步结果
}
@Override
protected void onProgressUpdate(String... progress) {
- showNotification(R.string.ticker_syncing, progress[0]);
+ showNotification(R.string.ticker_syncing, progress[0]); // 显示同步进度的通知
if (mContext instanceof GTaskSyncService) {
- ((GTaskSyncService) mContext).sendBroadcast(progress[0]);
+ ((GTaskSyncService) mContext).sendBroadcast(progress[0]); // 向 GTaskSyncService 发送广播,以便更新 UI
}
}
@Override
protected void onPostExecute(Integer result) {
- if (result == GTaskManager.STATE_SUCCESS) {
+ if (result == GTaskManager.STATE_SUCCESS) { // 如果同步成功
showNotification(R.string.ticker_success, mContext.getString(
- R.string.success_sync_account, mTaskManager.getSyncAccount()));
- NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis());
- } else if (result == GTaskManager.STATE_NETWORK_ERROR) {
- showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network));
- } else if (result == GTaskManager.STATE_INTERNAL_ERROR) {
- showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal));
- } else if (result == GTaskManager.STATE_SYNC_CANCELLED) {
+ R.string.success_sync_account, mTaskManager.getSyncAccount())); // 显示同步成功的通知
+ NotesPreferenceActivity.setLastSyncTime(mContext, System.currentTimeMillis()); // 更新最后同步时间
+ } else if (result == GTaskManager.STATE_NETWORK_ERROR) { // 如果网络错误
+ showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_network)); // 显示同步失败的通知,提示网络错误
+ } else if (result == GTaskManager.STATE_INTERNAL_ERROR) { // 如果内部错误
+ showNotification(R.string.ticker_fail, mContext.getString(R.string.error_sync_internal)); // 显示同步失败的通知,提示内部错误
+ } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { // 如果同步被取消
showNotification(R.string.ticker_cancel, mContext
- .getString(R.string.error_sync_cancelled));
+ .getString(R.string.error_sync_cancelled)); // 显示同步被取消的通知
}
- if (mOnCompleteListener != null) {
- new Thread(new Runnable() {
+ if (mOnCompleteListener != null) { // 如果设置了 OnCompleteListener
+ new Thread(new Runnable() { // 在新线程中执行 OnCompleteListener
public void run() {
mOnCompleteListener.onComplete();
@@ -120,4 +120,4 @@ public class GTaskASyncTask extends AsyncTask {
}).start();
}
}
-}
+}
\ No newline at end of file
diff --git a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java
index c67dfdf..91314f8 100644
--- a/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java
+++ b/src/app/src/main/java/net/micode/notes/gtask/remote/GTaskClient.java
@@ -64,50 +64,52 @@ import java.util.zip.InflaterInputStream;
public class GTaskClient {
private static final String TAG = GTaskClient.class.getSimpleName();
- private static final String GTASK_URL = "https://mail.google.com/tasks/";
+ private static final String GTASK_URL = "https://mail.google.com/tasks/"; // GTask 的基础 URL
- private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";
+ private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; // 获取 GTask 数据的 URL
- private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";
+ private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig"; // 提交 GTask 数据的 URL
- private static GTaskClient mInstance = null;
+ private static GTaskClient mInstance = null; // 单例模式,保存 GTaskClient 的唯一实例
- private DefaultHttpClient mHttpClient;
+ private DefaultHttpClient mHttpClient; // HTTP 客户端
- private String mGetUrl;
+ private String mGetUrl; // 获取 GTask 数据的完整 URL
- private String mPostUrl;
+ private String mPostUrl; // 提交 GTask 数据的完整 URL
- private long mClientVersion;
+ private long mClientVersion; // 客户端版本号
- private boolean mLoggedin;
+ private boolean mLoggedin; // 是否已登录
- private long mLastLoginTime;
+ private long mLastLoginTime; // 上次登录时间
- private int mActionId;
+ private int mActionId; // 操作 ID
- private Account mAccount;
-
- private JSONArray mUpdateArray;
+ private Account mAccount; // GTask 帐户
+ private JSONArray mUpdateArray; // 待更新的 GTask 数据
private GTaskClient() {
- mHttpClient = null;
- mGetUrl = GTASK_GET_URL;
- mPostUrl = GTASK_POST_URL;
- mClientVersion = -1;
- mLoggedin = false;
- mLastLoginTime = 0;
- mActionId = 1;
- mAccount = null;
- mUpdateArray = null;
- }
+ mHttpClient = null; // 初始化 HTTP 客户端为 null
+ mGetUrl = GTASK_GET_URL; // 初始化获取 GTask 数据的 URL
+ mPostUrl = GTASK_POST_URL; // 初始化提交 GTask 数据的 URL
+ mClientVersion = -1; // 初始化客户端版本号为 -1
+ mLoggedin = false; // 初始化登录状态为 false
+ mLastLoginTime = 0; // 初始化上次登录时间为 0
+ mActionId = 1; // 初始化操作 ID 为 1
+ mAccount = null; // 初始化 GTask 帐户为 null
+ mUpdateArray = null; // 初始化待更新的 GTask 数据为 null
+ }/*该构造方法用于创建GTaskClient的实例,其中将mHttpClient、mAccount、mUpdateArray等成员变量初始化为 null 或默认值,将mGetUrl和mPostUrl初始化为 GTask 的默认 URL,将mClientVersion初始化为 -1,将mLoggedin初始化为 false,将mLastLoginTime初始化为 0,将mActionId初始化为 1。
+ 这里使用了默认访问控制符private,意味着该构造方法只能在GTaskClient类内部使用,不能在其他类中创建GTaskClient的实例。*/
public static synchronized GTaskClient getInstance() {
- if (mInstance == null) {
- mInstance = new GTaskClient();
+ if (mInstance == null) { // 如果唯一实例不存在
+ mInstance = new GTaskClient(); // 则创建一个新实例
}
- return mInstance;
- }
+ return mInstance; // 返回唯一实例
+ }/*该方法是单例模式的实现,用于获取GTaskClient的唯一实例。在该方法内部,首先判断唯一实例是否已经存在,如果不存在则创建一个新实例,并将其赋值给mInstance。最后返回唯一实例。
+ 由于该方法可能被多个线程同时调用,所以使用了synchronized关键字来保证在同一时刻只有一个线程能够访问该方法。
+ 同时,该方法返回的是静态成员变量mInstance,因此可以通过GTaskClient.getInstance()的方式在任意位置获取GTaskClient的唯一实例。*/
public boolean login(Activity activity) {
// we suppose that the cookie would expire after 5 minutes
@@ -120,38 +122,38 @@ public class GTaskClient {
// need to re-login after account switch
if (mLoggedin
&& !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity
- .getSyncAccountName(activity))) {
+ .getSyncAccountName(activity))) {
mLoggedin = false;
}
- if (mLoggedin) {
+ if (mLoggedin) { // 如果已登录,则直接返回
Log.d(TAG, "already logged in");
return true;
}
- mLastLoginTime = System.currentTimeMillis();
- String authToken = loginGoogleAccount(activity, false);
- if (authToken == null) {
+ mLastLoginTime = System.currentTimeMillis(); // 记录登录时间
+ String authToken = loginGoogleAccount(activity, false); // 登录 Google 帐户,获取授权令牌
+ if (authToken == null) { // 如果登录失败,则返回 false
Log.e(TAG, "login google account failed");
return false;
}
// login with custom domain if necessary
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()
- .endsWith("googlemail.com"))) {
- StringBuilder url = new StringBuilder(GTASK_URL).append("a/");
+ .endsWith("googlemail.com"))) { // 如果不是 Gmail 或 Googlemail 帐户,则使用自定义域名登录
+ StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); // 构造自定义域名的 URL
int index = mAccount.name.indexOf('@') + 1;
String suffix = mAccount.name.substring(index);
url.append(suffix + "/");
- mGetUrl = url.toString() + "ig";
- mPostUrl = url.toString() + "r/ig";
+ mGetUrl = url.toString() + "ig"; // 更新获取 GTask 数据的 URL
+ mPostUrl = url.toString() + "r/ig"; // 更新提交 GTask 数据的 URL
- if (tryToLoginGtask(activity, authToken)) {
- mLoggedin = true;
+ if (tryToLoginGtask(activity, authToken)) { // 尝试登录 GTask
+ mLoggedin = true; // 登录成功
}
}
- // try to login with google official url
+ // 如果自定义域名登录失败,则使用 Google 官方 URL 登录
if (!mLoggedin) {
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
@@ -160,30 +162,35 @@ public class GTaskClient {
}
}
- mLoggedin = true;
+ mLoggedin = true; // 登录成功
return true;
- }
+ }/*该方法用于登录 GTask,首先检查上次登录时间是否超过 5 分钟,如果超过则需要重新登录,将mLoggedin设置为 false。
+ 然后判断当前帐户是否发生切换,如果发生切换也需要重新登录,同样将mLoggedin设置为 false。
+ 如果已经登录,则直接返回 true。否则,记录本次登录时间,然后使用loginGoogleAccount()方法登录 Google 帐户,获取授权令牌。
+ 如果登录失败,则返回 false。接下来,如果当前帐户不是 Gmail 或 Googlemail 帐户,则使用自定义域名登录,更新获取 GTask 数据和提交 GTask 数据的 URL,然后尝试登录 GTask。
+ 如果自定义域名登录失败,则使用 Google 官方 URL 登录。
+ 无论使用哪种方式登录成功,最后将mLoggedin设置为 true,表示已经登录成功。*/
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {
String authToken;
- AccountManager accountManager = AccountManager.get(activity);
- Account[] accounts = accountManager.getAccountsByType("com.google");
+ AccountManager accountManager = AccountManager.get(activity); // 获取 AccountManager 实例
+ Account[] accounts = accountManager.getAccountsByType("com.google"); // 获取所有 Google 帐户
- if (accounts.length == 0) {
+ if (accounts.length == 0) { // 如果没有可用的 Google 帐户,则返回 null
Log.e(TAG, "there is no available google account");
return null;
}
- String accountName = NotesPreferenceActivity.getSyncAccountName(activity);
+ String accountName = NotesPreferenceActivity.getSyncAccountName(activity); // 获取设置中的同步帐户名称
Account account = null;
for (Account a : accounts) {
- if (a.name.equals(accountName)) {
+ if (a.name.equals(accountName)) { // 如果找到同名帐户,则使用该帐户
account = a;
break;
}
}
if (account != null) {
- mAccount = account;
+ mAccount = account; // 更新当前使用的帐户
} else {
Log.e(TAG, "unable to get an account with the same name in the settings");
return null;
@@ -191,39 +198,48 @@ public class GTaskClient {
// get the token now
AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account,
- "goanna_mobile", null, activity, null, null);
+ "goanna_mobile", null, activity, null, null); // 获取 token
try {
Bundle authTokenBundle = accountManagerFuture.getResult();
- authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
- if (invalidateToken) {
- accountManager.invalidateAuthToken("com.google", authToken);
- loginGoogleAccount(activity, false);
+ authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); // 从 Bundle 中获取 token
+ if (invalidateToken) { // 如果需要使 token 失效
+ accountManager.invalidateAuthToken("com.google", authToken); // 使 token 失效
+ loginGoogleAccount(activity, false); // 重新登录
}
- } catch (Exception e) {
+ } catch (Exception e) { // 获取 token 失败
Log.e(TAG, "get auth token failed");
authToken = null;
}
- return authToken;
+ return authToken; // 返回 token
}
+ /*该方法的作用是获取 Google 帐户的 token,以用于访问 Google 服务。
+ 它首先获取所有的 Google 帐户,然后根据设置中的同步帐户名称选择使用哪个帐户。
+ 接着,它使用AccountManager获取该帐户的 token,并返回该 token。
+ 如果invalidateToken参数为true,则该方法会使 token 失效,并重新登录,以获取新的 token。
+ */
private boolean tryToLoginGtask(Activity activity, String authToken) {
- if (!loginGtask(authToken)) {
+ if (!loginGtask(authToken)) { // 如果登录 GTask 失败
// maybe the auth token is out of date, now let's invalidate the
// token and try again
- authToken = loginGoogleAccount(activity, true);
- if (authToken == null) {
+ authToken = loginGoogleAccount(activity, true); // 使 token 失效并重新登录
+ if (authToken == null) { // 如果重新登录失败,则返回 false
Log.e(TAG, "login google account failed");
return false;
}
- if (!loginGtask(authToken)) {
+ if (!loginGtask(authToken)) { // 如果重新登录 GTask 仍然失败,则返回 false
Log.e(TAG, "login gtask failed");
return false;
}
}
- return true;
+ return true; // 登录 GTask 成功,返回 true
}
+ /*该方法的作用是尝试登录 GTask,它接收一个authToken参数,该参数是通过loginGoogleAccount()方法获取的 Google 帐户的 token。
+ 如果登录 GTask 失败,则会使 token 失效并重新登录,再次尝试登录 GTask。
+ 如果重新登录失败,则返回false,否则返回true。
+ */
private boolean loginGtask(String authToken) {
int timeoutConnection = 10000;
@@ -231,6 +247,8 @@ public class GTaskClient {
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);
+
+ // 设置 HttpClient 的参数
mHttpClient = new DefaultHttpClient(httpParameters);
BasicCookieStore localBasicCookieStore = new BasicCookieStore();
mHttpClient.setCookieStore(localBasicCookieStore);
@@ -239,11 +257,10 @@ public class GTaskClient {
// login gtask
try {
String loginUrl = mGetUrl + "?auth=" + authToken;
- HttpGet httpGet = new HttpGet(loginUrl);
- HttpResponse response = null;
- response = mHttpClient.execute(httpGet);
+ HttpGet httpGet = new HttpGet(loginUrl); // 创建 HTTP GET 请求
+ HttpResponse response = mHttpClient.execute(httpGet); // 执行请求
- // get the cookie now
+ // 获取 cookie
List cookies = mHttpClient.getCookieStore().getCookies();
boolean hasAuthCookie = false;
for (Cookie cookie : cookies) {
@@ -255,7 +272,7 @@ public class GTaskClient {
Log.w(TAG, "it seems that there is no auth cookie");
}
- // get the client version
+ // 获取客户端版本
String resString = getResponseContent(response.getEntity());
String jsBegin = "_setup(";
String jsEnd = ")}";
@@ -279,49 +296,63 @@ public class GTaskClient {
return true;
}
+ /*该方法的作用是使用给定的authToken登录 GTask。
+ 它创建了一个 HTTP GET 请求,并将authToken添加到 URL 末尾,然后执行该请求并获取响应。
+ 它还获取了响应中包含的 cookie,并将客户端版本存储在mClientVersion中。
+ 如果登录成功,则返回true,否则返回false。如果发生异常,则返回false。
+ */
private int getActionId() {
- return mActionId++;
+ return mActionId++; // 返回下一个 action ID,并将 mActionId 加 1
}
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;
- }
+ HttpPost httpPost = new HttpPost(mPostUrl); // 创建一个 HTTP POST 请求
+ httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); // 设置请求头的 Content-Type
+ httpPost.setHeader("AT", "1"); // 设置请求头的 AT 字段为 1
+ return httpPost; // 返回创建的 HTTP POST 请求
+ }/*getActionId()的作用是获取下一个 action ID,每次调用它都会将mActionId加 1,并返回加 1 后的值。
+ createHttpPost()的作用是创建一个 HTTP POST 请求,并设置请求头的 Content-Type 为application/x-www-form-urlencoded;charset=utf-8,设置请求头的 AT 字段为 1。
+ 它返回创建的 HTTP POST 请求对象。
+ */
private String getResponseContent(HttpEntity entity) throws IOException {
String contentEncoding = null;
if (entity.getContentEncoding() != null) {
- contentEncoding = entity.getContentEncoding().getValue();
+ contentEncoding = entity.getContentEncoding().getValue(); // 获取响应内容的编码方式
Log.d(TAG, "encoding: " + contentEncoding);
}
- InputStream input = entity.getContent();
+ InputStream input = entity.getContent(); // 获取响应内容的输入流
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
- input = new GZIPInputStream(entity.getContent());
+ input = new GZIPInputStream(entity.getContent()); // 如果响应内容被 gzip 压缩了,则创建一个 GZIPInputStream 解压缩
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
Inflater inflater = new Inflater(true);
- input = new InflaterInputStream(entity.getContent(), inflater);
+ input = new InflaterInputStream(entity.getContent(), inflater); // 如果响应内容被 deflate 压缩了,则创建一个 InflaterInputStream 解压缩
}
try {
- InputStreamReader isr = new InputStreamReader(input);
- BufferedReader br = new BufferedReader(isr);
- StringBuilder sb = new StringBuilder();
+ InputStreamReader isr = new InputStreamReader(input); // 创建一个 InputStreamReader 对象
+ BufferedReader br = new BufferedReader(isr); // 创建一个 BufferedReader 对象
+ StringBuilder sb = new StringBuilder(); // 创建一个 StringBuilder 对象
while (true) {
- String buff = br.readLine();
+ String buff = br.readLine(); // 逐行读取响应内容
if (buff == null) {
- return sb.toString();
+ return sb.toString(); // 如果读到了末尾,则返回读取到的响应内容
}
- sb = sb.append(buff);
+ sb = sb.append(buff); // 将读取到的响应内容追加到 StringBuilder 对象中
}
} finally {
- input.close();
+ input.close(); // 关闭输入流
}
}
+ /*getResponseContent(HttpEntity entity)的作用是从HttpEntity对象中获取响应内容,并将其解压(如果响应内容被压缩了)。它返回解压后的响应内容。
+ 首先获取响应内容的编码方式,然后根据编码方式创建对应的输入流。
+ 如果响应内容被 gzip 压缩了,则创建一个 GZIPInputStream 对象解压缩;如果响应内容被 deflate 压缩了,则创建一个 InflaterInputStream 对象解压缩。
+ 接着使用 InputStreamReader 和 BufferedReader 逐行读取响应内容,并将其追加到 StringBuilder 对象中。
+ 最后返回读取到的响应内容,并关闭输入流。
+ */
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {
if (!mLoggedin) {
@@ -329,17 +360,17 @@ public class GTaskClient {
throw new ActionFailureException("not logged in");
}
- HttpPost httpPost = createHttpPost();
+ HttpPost httpPost = createHttpPost(); // 创建 HTTP POST 请求
try {
LinkedList list = new LinkedList();
- list.add(new BasicNameValuePair("r", js.toString()));
- UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");
- httpPost.setEntity(entity);
+ list.add(new BasicNameValuePair("r", js.toString())); // 将传入的 JSONObject 对象转为字符串,并添加到请求参数中
+ UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); // 创建一个 UrlEncodedFormEntity 对象,用于封装请求参数
+ httpPost.setEntity(entity); // 将 UrlEncodedFormEntity 对象设置为 HTTP POST 请求的实体
// execute the post
- HttpResponse response = mHttpClient.execute(httpPost);
- String jsString = getResponseContent(response.getEntity());
- return new JSONObject(jsString);
+ HttpResponse response = mHttpClient.execute(httpPost); // 执行 HTTP POST 请求
+ String jsString = getResponseContent(response.getEntity()); // 获取响应内容,并将其解压(如果响应内容被压缩了),然后转为字符串
+ return new JSONObject(jsString); // 将响应内容转为 JSONObject 对象
} catch (ClientProtocolException e) {
Log.e(TAG, e.toString());
@@ -359,25 +390,30 @@ public class GTaskClient {
throw new ActionFailureException("error occurs when posting request");
}
}
-
+ /*postRequest(JSONObject js)的作用是向服务器发送 HTTP POST 请求,并将响应内容转为JSONObject对象返回。
+ 首先检查用户是否已经登录,如果没有登录则抛出异常。然后创建一个 HTTP POST 请求,并将传入的 JSONObject 对象转为字符串,并添加到请求参数中。接着,创建一个 UrlEncodedFormEntity 对象,用于封装请求参数,并将其设置为 HTTP POST 请求的实体。
+ 执行 HTTP POST 请求,并获取响应内容。将响应内容解压(如果响应内容被压缩了),然后将其转为字符串,并通过 JSONObject 构造方法将其转为 JSONObject 对象。如果转换失败,则抛出异常。
+ 如果在执行 HTTP POST 请求或转换响应内容为 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
public void createTask(Task task) throws NetworkFailureException {
- commitUpdate();
+ commitUpdate(); // 提交所有未提交的更新操作
+
try {
- JSONObject jsPost = new JSONObject();
- JSONArray actionList = new JSONArray();
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储操作列表
// action_list
- actionList.put(task.getCreateAction(getActionId()));
- jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
+ actionList.put(task.getCreateAction(getActionId())); // 将新增任务的操作添加到操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将操作列表添加到 JSONObject 对象中
// client_version
- jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
// post
- JSONObject jsResponse = postRequest(jsPost);
+ JSONObject jsResponse = postRequest(jsPost); // 向服务器发送 HTTP POST 请求,并获取响应内容
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
- GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
- task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
+ GTaskStringUtils.GTASK_JSON_RESULTS).get(0); // 从响应内容中获取结果列表,并获取第一个结果
+ task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); // 获取新任务的 ID,并将其设置为 Task 对象的 gid 属性
} catch (JSONException e) {
Log.e(TAG, e.toString());
@@ -385,25 +421,30 @@ public class GTaskClient {
throw new ActionFailureException("create task: handing jsonobject failed");
}
}
-
+ /*createTask(Task task)的作用是创建新任务。首先调用commitUpdate()方法提交所有未提交的更新操作。
+ 然后创建一个新的 JSONObject 对象,并创建一个新的 JSONArray 对象,用于存储操作列表。将新增任务的操作添加到操作列表中,并将操作列表添加到 JSONObject 对象中。将客户端版本号也添加到 JSONObject 对象中。
+ 向服务器发送 HTTP POST 请求,并获取响应内容。从响应内容中获取结果列表,并获取第一个结果。从结果中获取新任务的 ID,并将其设置为 Task 对象的 gid 属性。
+ 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
public void createTaskList(TaskList tasklist) throws NetworkFailureException {
- commitUpdate();
+ commitUpdate(); // 提交所有未提交的更新操作
+
try {
- JSONObject jsPost = new JSONObject();
- JSONArray actionList = new JSONArray();
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储操作列表
// action_list
- actionList.put(tasklist.getCreateAction(getActionId()));
- jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
+ actionList.put(tasklist.getCreateAction(getActionId())); // 将新增任务列表的操作添加到操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将操作列表添加到 JSONObject 对象中
- // client version
- jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
+ // client_version
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
// post
- JSONObject jsResponse = postRequest(jsPost);
+ JSONObject jsResponse = postRequest(jsPost); // 向服务器发送 HTTP POST 请求,并获取响应内容
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
- GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
- tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
+ GTaskStringUtils.GTASK_JSON_RESULTS).get(0); // 从响应内容中获取结果列表,并获取第一个结果
+ tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID)); // 获取新任务列表的 ID,并将其设置为 TaskList 对象的 gid 属性
} catch (JSONException e) {
Log.e(TAG, e.toString());
@@ -411,20 +452,25 @@ public class GTaskClient {
throw new ActionFailureException("create tasklist: handing jsonobject failed");
}
}
-
+ /*createTaskList(TaskList tasklist)的作用是创建新任务列表。首先调用commitUpdate()方法提交所有未提交的更新操作。
+ 然后创建一个新的 JSONObject 对象,并创建一个新的 JSONArray 对象,用于存储操作列表。将新增任务列表的操作添加到操作列表中,并将操作列表添加到 JSONObject 对象中。将客户端版本号也添加到 JSONObject 对象中。
+ 向服务器发送 HTTP POST 请求,并获取响应内容。从响应内容中获取结果列表,并获取第一个结果。从结果中获取新任务列表的 ID,并将其设置为 TaskList 对象的 gid 属性。
+ 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
public void commitUpdate() throws NetworkFailureException {
- if (mUpdateArray != null) {
+ if (mUpdateArray != null) { // 判断更新操作列表是否为空
try {
- JSONObject jsPost = new JSONObject();
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
// action_list
- jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray); // 将更新操作列表添加到 JSONObject 对象中
// client_version
- jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作
+ mUpdateArray = null; // 更新操作提交成功后,清空更新操作列表
- postRequest(jsPost);
- mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
@@ -432,52 +478,63 @@ public class GTaskClient {
}
}
}
-
+ /*commitUpdate()的作用是提交所有未提交的更新操作。如果更新操作列表不为空,则创建一个新的 JSONObject 对象,将更新操作列表添加到 JSONObject 对象中,并将客户端版本号也添加到 JSONObject 对象中。
+ 向服务器发送 HTTP POST 请求,提交更新操作。提交成功后,清空更新操作列表。
+ 如果在处理 JSONObject 对象时出现异常,则抛出相应的异常。
+ */
public void addUpdateNode(Node node) throws NetworkFailureException {
- if (node != null) {
+ if (node != null) { // 判断 Node 对象是否为空
// too many update items may result in an error
// set max to 10 items
- if (mUpdateArray != null && mUpdateArray.length() > 10) {
- commitUpdate();
+ if (mUpdateArray != null && mUpdateArray.length() > 10) { // 判断更新操作列表是否已满
+ commitUpdate(); // 如果已满,则提交所有未提交的更新操作
}
if (mUpdateArray == null)
- mUpdateArray = new JSONArray();
- mUpdateArray.put(node.getUpdateAction(getActionId()));
+ mUpdateArray = new JSONArray(); // 如果更新操作列表还未创建,则创建一个新的 JSONArray 对象
+ mUpdateArray.put(node.getUpdateAction(getActionId())); // 将 Node 对象的更新操作添加到更新操作列表中
}
}
-
+ /*addUpdateNode(Node node)的作用是向更新操作列表中添加一个新的更新操作。首先判断 Node 对象是否为空。
+ 如果更新操作列表已满(长度大于 10),则调用commitUpdate()方法提交所有未提交的更新操作。
+ 如果更新操作列表还未创建,则创建一个新的 JSONArray 对象。将 节点
+ 如果 Node 对象为空,则不执行任何操作。
+ */
public void moveTask(Task task, TaskList preParent, TaskList curParent)
throws NetworkFailureException {
- commitUpdate();
+ commitUpdate(); // 先提交所有未提交的更新操作
try {
- JSONObject jsPost = new JSONObject();
- JSONArray actionList = new JSONArray();
- JSONObject action = new JSONObject();
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储更新操作
+ JSONObject action = new JSONObject(); // 创建一个新的 JSONObject 对象,用于存储移动任务的操作
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
- GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE);
- action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
- action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid());
+ GTaskStringUtils.GTASK_JSON_ACTION_TYPE_MOVE); // 设置操作类型为移动任务
+ action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置操作 ID
+ action.put(GTaskStringUtils.GTASK_JSON_ID, task.getGid()); // 设置任务的 GID
+
if (preParent == curParent && task.getPriorSibling() != null) {
// put prioring_sibing_id only if moving within the tasklist and
// it is not the first one
- action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling());
+ action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); // 如果是在同一任务列表中移动任务,则设置前一个任务的 GID
}
- action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid());
- action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());
+
+ action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); // 设置任务的原始任务列表的 GID
+ action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); // 设置任务的目标任务列表的 GID
+
if (preParent != curParent) {
// put the dest_list only if moving between tasklists
- action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());
+ action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); // 如果是在不同的任务列表之间移动任务,则设置任务的目标任务列表的 GID
}
- actionList.put(action);
- jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
+
+ actionList.put(action); // 将移动任务的操作添加到更新操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将更新操作列表添加到 JSONObject 对象中
// client_version
- jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
- postRequest(jsPost);
+ postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作
} catch (JSONException e) {
Log.e(TAG, e.toString());
@@ -485,101 +542,127 @@ public class GTaskClient {
throw new ActionFailureException("move task: handing jsonobject failed");
}
}
-
+ /*moveTask(Task task, TaskList preParent, TaskList curParent)的作用是移动一个任务到另一个任务列表中。
+ 首先调用commitUpdate()方法提交所有未提交的更新操作。然后,创建一个新的 JSONObject 对象,用于存储移动任务的操作。
+ 在移动任务的操作中,设置操作类型为移动任务。设置操作 ID 和任务的 GID。如果是在同一任务列表中移动任务,则设置前一个任务的 GID。设置任务的原始任务列表的 GID 和任务的目标任务列表的 GID。如果是在不同的任务列表之间移动任务,则设置任务的目标任务列表的 GID。
+ 将移动任务的操作添加到更新操作列表中,然后将更新操作列表添加到 JSONObject 对象中。最后,添加客户端版本号到 JSONObject 对象中,向服务器发送 HTTP POST 请求,提交更新操作。
+ 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常。
+ */
public void deleteNode(Node node) throws NetworkFailureException {
- commitUpdate();
+ commitUpdate(); // 先提交所有未提交的更新操作
try {
- JSONObject jsPost = new JSONObject();
- JSONArray actionList = new JSONArray();
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象,用于存储更新操作
// action_list
- node.setDeleted(true);
- actionList.put(node.getUpdateAction(getActionId()));
- jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
+ node.setDeleted(true); // 将节点标记为已删除
+ actionList.put(node.getUpdateAction(getActionId())); // 将节点的更新操作添加到更新操作列表中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将更新操作列表添加到 JSONObject 对象中
// client_version
- jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 添加客户端版本号到 JSONObject 对象中
+
+ postRequest(jsPost); // 向服务器发送 HTTP POST 请求,提交更新操作
+ mUpdateArray = null; // 将更新操作数组置为空
- postRequest(jsPost);
- mUpdateArray = null;
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
- throw new ActionFailureException("delete node: handing jsonobject failed");
+ throw new ActionFailureException("delete node: handing jsonobject failed"); // 处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常
}
}
+ /*此方法的主要目的是删除一个节点,并将删除操作提交到服务器。
+ 方法首先提交所有未提交的更新操作,然后创建一个新的 JSONObject 对象,将节点的删除操作添加到该对象中,同时添加客户端版本号。
+ 最后,方法通过向服务器发送 HTTP POST 请求来提交更新操作,如果在处理 JSONObject 对象时出现异常,则会抛出 ActionFailureException 异常。
+ */
public JSONArray getTaskLists() throws NetworkFailureException {
- if (!mLoggedin) {
+ if (!mLoggedin) { // 如果用户没有登录,则抛出 ActionFailureException 异常
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
try {
- HttpGet httpGet = new HttpGet(mGetUrl);
+ HttpGet httpGet = new HttpGet(mGetUrl); // 创建一个新的 HttpGet 请求对象
HttpResponse response = null;
- response = mHttpClient.execute(httpGet);
+ response = mHttpClient.execute(httpGet); // 执行 HttpGet 请求
// get the task list
- String resString = getResponseContent(response.getEntity());
+ String resString = getResponseContent(response.getEntity()); // 获取响应内容
String jsBegin = "_setup(";
String jsEnd = ")}";
int begin = resString.indexOf(jsBegin);
int end = resString.lastIndexOf(jsEnd);
String jsString = null;
- if (begin != -1 && end != -1 && begin < end) {
+ if (begin != -1 && end != -1 && begin < end) { // 如果响应内容中包含任务列表,那么提取出来
jsString = resString.substring(begin + jsBegin.length(), end);
}
- JSONObject js = new JSONObject(jsString);
- return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);
- } catch (ClientProtocolException e) {
+ JSONObject js = new JSONObject(jsString); // 将任务列表转换成 JSONObject 对象
+ return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); // 返回任务列表数组
+
+ } catch (ClientProtocolException e) { // 如果发生协议错误,则抛出 NetworkFailureException 异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
- } catch (IOException e) {
+ } catch (IOException e) { // 如果发生 I/O 错误,则抛出 NetworkFailureException 异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
- } catch (JSONException e) {
+ } catch (JSONException e) { // 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task lists: handing jasonobject failed");
}
}
+ /*此方法的主要目的是从服务器获取用户的任务列表,并将其作为 JSONArray 对象返回。
+ 方法首先检查用户是否已登录,然后创建一个新的 HttpGet 请求对象,并通过执行该请求来获取响应内容。
+ 接下来,方法从响应内容中提取出任务列表,并将其转换为 JSONObject 对象,最后返回任务列表数组。
+ 如果在执行 HttpGet 请求或处理 JSONObject 对象时发生错误,则会抛出 NetworkFailureException 或 ActionFailureException 异常。
+ */
public JSONArray getTaskList(String listGid) throws NetworkFailureException {
- commitUpdate();
+ commitUpdate(); // 提交所有未提交的更改
try {
- JSONObject jsPost = new JSONObject();
- JSONArray actionList = new JSONArray();
- JSONObject action = new JSONObject();
+ JSONObject jsPost = new JSONObject(); // 创建一个新的 JSONObject 对象
+ JSONArray actionList = new JSONArray(); // 创建一个新的 JSONArray 对象
+ JSONObject action = new JSONObject(); // 创建一个新的 JSONObject 对象
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
- GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
- action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
- action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);
- action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
- actionList.put(action);
- jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
+ GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); // 设置 action 的类型为 "getall"
+ action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); // 设置 action 的 ID
+ action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); // 设置 action 操作的任务列表 ID
+ action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); // 设置是否获取已删除的任务
+ actionList.put(action); // 将 action 添加到 action_list 中
+ jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // 将 action_list 添加到 jsPost 中
// client_version
- jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
+ jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion); // 设置客户端版本号
- JSONObject jsResponse = postRequest(jsPost);
- return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
- } catch (JSONException e) {
+ JSONObject jsResponse = postRequest(jsPost); // 发送请求并获取响应
+ return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS); // 从响应中获取任务列表并返回
+
+ } catch (JSONException e) { // 如果处理 JSONObject 对象时出现异常,则抛出 ActionFailureException 异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task list: handing jsonobject failed");
}
}
+ /*此方法的主要目的是从服务器获取特定任务列表的任务,并将其作为 JSONArray 对象返回。
+ 方法首先提交所有未提交的更改,然后构造一个包含获取任务列表的请求并发送它。
+ 接下来,方法从响应中提取出任务列表,并将其作为 JSONArray 对象返回。
+ 如果在处理 JSONObject 对象时发生错误,则会抛出 ActionFailureException 异常。
+ */
public Account getSyncAccount() {
return mAccount;
}
+ //这个方法返回GTaskClient的同步账户(即当前使用的 Google 帐户)。
public void resetUpdateArray() {
mUpdateArray = null;
}
}
+ /*这个方法将GTaskClient的更新数组mUpdateArray设置为null,以清除未提交的更改。
+ 在更新任务列表之前,需要调用commitUpdate()方法提交所有未提交的更改,如果您想丢弃这些更改,可以调用resetUpdateArray()方法以清除它们。
+ */
\ No newline at end of file