四月十三,唐志发精读报告提交

Git-tzf
唐志发 3 years ago
parent cfa35a3d0f
commit 2f60bdcb61

@ -0,0 +1,33 @@
/*
* 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 {//从RuntimeException类派生出ActionFailureException类用来处理行为异常
private static final long serialVersionUID = 4425249765923293627L;//定义serialVersionUID相当于java类的身份证主要用于版本控制。
public ActionFailureException() {// 函数:交给父类的构造函数(包括下面的两个构造函数)
super();//super是指向父类的一个指针与其相对的还有this指向当前类。
}
public ActionFailureException(String paramString) {
super(paramString);
}
public ActionFailureException(String paramString, Throwable paramThrowable) {//调用父类具有相同形参paramString和paramThrowable的构造方法
super(paramString, paramThrowable);
}
}

@ -0,0 +1,33 @@
/*
* 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 NetworkFailureException extends Exception {//应该是处理网络异常的类直接继承于Exception
private static final long serialVersionUID = 2107610287180234136L;//定义serialVersionUID相当于java类的身份证主要用于版本控制。作用验证版本一致性如果不一致会导致反序列化的时候版本不一致的异常。
public NetworkFailureException() {
super();
}//构造函数(以下三个都是)
public NetworkFailureException(String paramString) {
super(paramString);//调用父类具有相同形参paramString的构造方法相当于Exception(paramString)
}
public NetworkFailureException(String paramString, Throwable paramThrowable) {
super(paramString, paramThrowable);//调用父类具有相同形参paramString和paramThrowable的构造方法
}
}

@ -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<Void, String, Integer> {//异步任务类:任务同步和取消,显示同步任务的进程、通知和结果
private static int GTASK_SYNC_NOTIFICATION_ID = 5234235;//定义一个int变量作用是存储GTASK同步通知ID
public interface OnCompleteListener {//方法声明了一个名为OnCompleteListener的接口其内部的OnComplete方法在GTaskSyncService里面实现用来初始化异步的功能
void onComplete();//初始化
}
private Context mContext;//定义成员:文本内容
private NotificationManager mNotifiManager;//对象: 通知管理器类的实例化
private GTaskManager mTaskManager;//实例化任务管理器
private OnCompleteListener mOnCompleteListener;//实例化是否完成的监听器
public GTaskASyncTask(Context context, OnCompleteListener listener) {//传入两个变量构造形成GtaskASyncTask类
mContext = context;// 引入两个变量构造形成GtaskASyncTask类
mOnCompleteListener = listener;
mNotifiManager = (NotificationManager) mContext//getSystemService是Activity的一个方法可根据传入的参数获得应服务的对象。这里以Context的NOTIFICATION_SERVICE为对象。
.getSystemService(Context.NOTIFICATION_SERVICE);//getSystemService是一种可根据传入的参数获得应服务的对象的端口函数。
mTaskManager = GTaskManager.getInstance();//getInstance ()函数用于使用单例模式创建类的实例。
}
public void cancelSync() {//取消同步
mTaskManager.cancelSync();//调用类中的同名方法来取消同步
}
public void publishProgess(String message) {//显示消息string message
publishProgress(new String[] {//String[]创建java数组
message
});
}
private void showNotification(int tickerId, String content) {//显示通知
Notification notification = new Notification(R.drawable.notification, mContext//新建一个通知
.getString(tickerId), System.currentTimeMillis());//新建一个通知并显示通知
notification.defaults = Notification.DEFAULT_LIGHTS;// 默认调用系统自带灯光
notification.flags = Notification.FLAG_AUTO_CANCEL;
PendingIntent pendingIntent;//描述了想要启动一个Activity、Broadcast或是Service的意图
if (tickerId != R.string.ticker_success) {// 点击清除按钮或点击通知后会自动消失
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,//若同步不成功就从系统取得一个来启动NotesPreferenceActivity的对象
NotesPreferenceActivity.class), 0);//获取首选项设置页
} else {
pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext,//若同步成功就从系统取得一个来启动一个NotesListActivity的对象
NotesListActivity.class), 0);
}
notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content,
pendingIntent);//设置最新事件信息
mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification);//通过NotificationManager对象的notify方法来执行一个notification的消息
}
@Override//这是Java5的元数据自动加上去的一个标志目的是告诉你下面这个方法是从父类/接口继承过来的,需要重写一次
protected Integer doInBackground(Void... unused) {//执行后台操作
publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity//利用getString,将把 字符串内容传进sync_progress_login中
.getSyncAccountName(mContext)));
return mTaskManager.sync(mContext, this);//在后台进行同步
}
@Override//这是Java5的元数据自动加上去的一个标志目的是告诉你下面这个方法是从父类/接口继承过来的,需要重写一次
protected void onProgressUpdate(String... progress) {//显示进度的更新
showNotification(R.string.ticker_syncing, progress[0]);//显示进度的更新
if (mContext instanceof GTaskSyncService) {//判断mContext是否是GTaskSyncService的实例
((GTaskSyncService) mContext).sendBroadcast(progress[0]);// 如果mContext是GTaskSyncService实例化的对象则发送一个广播
}
}
@Override//这是Java5的元数据自动加上去的一个标志目的是告诉你下面这个方同步失败取消法是从父类/接口继承过来的,需要重写一次
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) {//若监听器为空,则创建新进程
new Thread(new Runnable() {
public void run() {
mOnCompleteListener.onComplete();
}//执行完后调用然后返回主线程中
}).start();
}
}
}

@ -0,0 +1,584 @@
/*
* 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 {//GTaskClient类实现GTask的登录以及创建GTask任务和任务列表从网络上获取任务内容
private static final String TAG = GTaskClient.class.getSimpleName();//Google邮箱指定URL
private static final String GTASK_URL = "https://mail.google.com/tasks/";//这个是获得URL
private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig";//这个是传递URL
private static final String GTASK_POST_URL = "https://mail.google.com/tasks/r/ig";//发布的uri
private static GTaskClient mInstance = null;//后续使用的参数以及变量
private DefaultHttpClient mHttpClient;//网络地址客户端
private String mGetUrl;//构造函数:初始化各属性
private String mPostUrl;
private long mClientVersion;
private boolean mLoggedin;
private long mLastLoginTime;
private int mActionId;
private Account mAccount;
private JSONArray mUpdateArray;
private GTaskClient() {//getInstance获取实例化对象并返回
mHttpClient = null;//初始化客户端,使用 getInstance()返回mInstance这个实例化对象从而获取实例化对象
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
mClientVersion = -1;
mLoggedin = false;
mLastLoginTime = 0;
mActionId = 1;
mAccount = null;
mUpdateArray = null;
}
public static synchronized GTaskClient getInstance() {//获取实例如果当前没有示例则新建一个登陆的gtask如果有直接返回
if (mInstance == null) {// 若无实例,则新建一个
mInstance = new GTaskClient();
}
return mInstance;
}
public boolean login(Activity activity) {//login用于实现登录的方法以activity作为参数
// we suppose that the cookie would expire after 5 minutes//设置登录时间一旦超过5分钟即需要重新登录
// then we need to re-login//实现登录使用下面定义的loginGoogleAccount( )方法登录Google账户 使用下面定义的loginGtask( )方法登录gtask登录成功返回true登录失败返回false
final long interval = 1000 * 60 * 5;//interval时间间隔为1000ns * 60 * 5 = 5min 即间隔5分钟时间
if (mLastLoginTime + interval < System.currentTimeMillis()) {//判断距离上次登录的时间间隔若超过5分钟则重置登录状态
mLoggedin = false;//取消登录
}
// need to re-login after account switch//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) {//登录失败的情况
Log.e(TAG, "login google account failed");//登录失败
return false;
}
// login with custom domain if necessary//利用自己的用户域名登陆
if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase()//使用用户域名进行登录
.endsWith("googlemail.com"))) {// 判断是不是一个谷歌账户
StringBuilder url = new StringBuilder(GTASK_URL).append("a/");//变为小写
int index = mAccount.name.indexOf('@') + 1;//语句:返回@第一次出现的位置并把位置+1后记录在index里
String suffix = mAccount.name.substring(index);//语句substring() 方法用于提取字符串中介于两个指定下标之间的字符此语句中index为start没有设置stop所以提取了index开始到后面的字符也就是账户名的后缀例如qq.com 163.com之类的后缀
url.append(suffix + "/");//均为字符串操作来构建url链接
mGetUrl = url.toString() + "ig";//设置用户的getUrl
mPostUrl = url.toString() + "r/ig";//设置用户postURL
if (tryToLoginGtask(activity, authToken)) {成功登入
mLoggedin = true;//若不能使用用户域名登录使用google官方url登录
}
}
// try to login with google official url//尝试使用谷歌的官方URL登录
if (!mLoggedin) {//代码块: 若前面的尝试失败,则尝试使用官方的域名登陆
mGetUrl = GTASK_GET_URL;
mPostUrl = GTASK_POST_URL;
if (!tryToLoginGtask(activity, authToken)) {//第二次登录失败返回false
return false;
}
}
mLoggedin = true;//如果没有报错就说明登陆成功
return true;
}
private String loginGoogleAccount(Activity activity, boolean invalidateToken) {//登陆Google的主函数主要用于登陆成功后获取认证令牌
String authToken;
AccountManager accountManager = AccountManager.get(activity);//在这里,账户管理器帮助我们集中管理注册账号
Account[] accounts = accountManager.getAccountsByType("com.google");//获取谷歌账户
if (accounts.length == 0) {//如果没有这样的账号输出日志信息“无有效的google账户”
Log.e(TAG, "there is no available google account");//显示没有该谷歌账户
return null;
}
String accountName = NotesPreferenceActivity.getSyncAccountName(activity);//代码块匹配活动的账户里是否存在账户存在的话把这个账户记在mAccount中没有的话显示不能在设置中获取相同名字的账户
Account account = null;//遍历account数组寻找已登录过的信息
for (Account a : accounts) {//找到后,为属性赋值
if (a.name.equals(accountName)) {//没找到,输出例外信息
account = a;
break;
}
}
if (account != null) {//若存在把这个账户记在mAccount中否则显示“不能在设置中获取相同名字的账户”字样并返回值为null的令牌
mAccount = account;//若invalidateToken则需调用invalidateAuthToken废除这个无效的token
} else {
Log.e(TAG, "unable to get an account with the same name in the settings");//语句: 若遍历完之后仍没有用户名匹配的账号,则直接返回
return null;
}
// get the token now//获取token
AccountManagerFuture<Bundle> accountManagerFuture = accountManager.getAuthToken(account,//getAuthToken方法 获取令牌
"goanna_mobile", null, activity, null, null);
try {
Bundle authTokenBundle = accountManagerFuture.getResult();//语句bundle是一个key-value对这里获取目标账户的最终结果集
authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);//语句这里获取bundle类的对象的String串并赋值给令牌对象
if (invalidateToken) {//如果是非法的令牌,那么废除这个账号,取消登录状态
accountManager.invalidateAuthToken("com.google", authToken);//删除存储AccountManager中此账号类型对应的authToken缓存应用必须调用这个方法将缓存的authToken置为过期否则getAuthToken获取到的一直是缓存的token
loginGoogleAccount(activity, false);
}
} catch (Exception e) {//捕捉令牌获取失败的异常
Log.e(TAG, "get auth token failed");//错误,获取授权标记失败
authToken = null;//tryToLoginGtask尝试登录Gtask方法这是一个试探方法作为登录的预判
}
return authToken;//再次验证令牌。令牌可能是过期的,因此我们需要废除过期令牌
}
private boolean tryToLoginGtask(Activity activity, String authToken) {//方法用于判断令牌对于登陆gtask账号是否有效
if (!loginGtask(authToken)) {//代码块: 如果令牌不可用于登陆gtask账号则需要重新登陆google账号获取令牌
// maybe the auth token is out of date, now let's invalidate the//判断令牌对于登陆gtask账号是否有效
// token and try again
authToken = loginGoogleAccount(activity, true);//删除过一个无效的authToken申请一个新的后再次尝试登陆
if (authToken == null) {//代码块对再次登陆google账号失败的处理
Log.e(TAG, "login google account failed");//错误,登录 google 帐户失败
return false;//对再次登陆google账号失败的处理
}
if (!loginGtask(authToken)) {//代码块: 重新获取的令牌再次失效
Log.e(TAG, "login gtask failed");//错误,登录 gtask 失败
return false;
}
}
return true;
}
private boolean loginGtask(String authToken) {//loginGtask实现登录Gtask的方法
int timeoutConnection = 10000;//连接超时为10000毫秒即10秒
int timeoutSocket = 15000;//socketandroid与服务器的通信工具与http的主要区别是能够主动推送信息而不需要每次发送请求
HttpParams httpParameters = new BasicHttpParams();//申请一个httpParameters参数类的对象
HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//通过该方法设置连接超时的时间
HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置端口超时的时间
mHttpClient = new DefaultHttpClient(httpParameters);
BasicCookieStore localBasicCookieStore = new BasicCookieStore();//为cookie申请存储对象
mHttpClient.setCookieStore(localBasicCookieStore);//设置本地cookie
HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false);//setUseExpectContinu方法设置http协议1.1中的一个header属性Expect 100 Continue
// login gtask//登录的实现
try {//登录Gtask
String loginUrl = mGetUrl + "?auth=" + authToken;//设置登录的url以及令牌信息
HttpGet httpGet = new HttpGet(loginUrl);//通过HttpGet向服务器申请
HttpResponse response = null;//通过HttpGet向服务器申请
response = mHttpClient.execute(httpGet);//从cookiestore中获取cookie
// get the cookie now
List<Cookie> cookies = mHttpClient.getCookieStore().getCookies();//语句获取cookie值
boolean hasAuthCookie = false;//获取cookie值
for (Cookie cookie : cookies) {//功能遍历cookies集合中的每个Cookie对象如果有一个Cookie对象的名中含有GTLhasAuthCookie被赋给True
if (cookie.getName().contains("GTL")) {//验证cookie信息这里通过GTL标志来验证
hasAuthCookie = true;//验证cookie信息
}
}
if (!hasAuthCookie) {//代码块显示这是没有授权的cookie
Log.w(TAG, "it seems that there is no auth cookie");//显示没有授权的cookie
}
// get the client version//获取client的版本号
String resString = getResponseContent(response.getEntity());//获取客户端版本
String jsBegin = "_setup(";//在取得的内容中截取从_setup(到)}</script>中间的部分这是html语言格式获取的是gtask_url
String jsEnd = ")}</script>";
int begin = resString.indexOf(jsBegin);//获取jsbegin中begin的序号
int end = resString.lastIndexOf(jsEnd);//获取jsend中end的序号
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) {//catch例外GET失败
// simply catch all exceptions
Log.e(TAG, "httpget gtask_url failed");//获取异常类型和异常详细消息
return false;
}
return true;
}
private int getActionId() {
return mActionId++;
}//获取动作的id号码
private HttpPost createHttpPost() {//创建一个用来保存URL的httppost对象
HttpPost httpPost = new HttpPost(mPostUrl);//创建一个httppost对象用来保存URL
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");//创建一个httppost对象保存URL
httpPost.setHeader("AT", "1");
return httpPost;
}
private String getResponseContent(HttpEntity entity) throws IOException {//getResponseContent获取服务器响应的数据主要通过方法getContentEncoding来获取网上资源返回这些资源
String contentEncoding = null;//通过URL得到HttpEntity对象如果不为空则使用getContent方法创建一个流将数据从网络都过来
if (entity.getContentEncoding() != null) {//代码块如果获取的内容编码不为空给内容编码赋值显示encoding内容编码
contentEncoding = entity.getContentEncoding().getValue();
Log.d(TAG, "encoding: " + contentEncoding);//gzip是使用deflate进行压缩数据的一个压缩库
}
InputStream input = entity.getContent();
if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//deflate是一种压缩算法,是huffman编码的一种加强
input = new GZIPInputStream(entity.getContent());
} else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//语句deflate是一种压缩算法
Inflater inflater = new Inflater(true);
input = new InflaterInputStream(entity.getContent(), inflater);//InflaterInputStream类实现了一个流过滤器用于以“deflate”压缩格式解压缩数据
}
try {//完成将字节流数据内容进行存储的功能
InputStreamReader isr = new InputStreamReader(input);//InputStreamReader类是从字节流到字符流的桥接器它使用指定的字符集读取字节并将它们解码为字符
BufferedReader br = new BufferedReader(isr);//缓存读取类,用于快速的读缓存操作
StringBuilder sb = new StringBuilder();
while (true) {//将BufferedReader类br的内容逐行读取并存储StringBuilder类的sb中。然后返回sb的string格式。
String buff = br.readLine();
if (buff == null) {
return sb.toString();
}
sb = sb.append(buff);
}
} finally {
input.close();
}
}
private JSONObject postRequest(JSONObject js) throws NetworkFailureException {//postRequest利用JSON发送请求返回获取的内容
if (!mLoggedin) {//未登录,输出提示信息
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
HttpPost httpPost = createHttpPost();//实例化一个httpPost的对象用来向服务器传输数据发送在js里请求的内容
try {//实例化一个对象,用于与服务器交互和发送请求
LinkedList<BasicNameValuePair> list = new LinkedList<BasicNameValuePair>();//LinkedList 类是一个继承于AbstractSequentialList的双向链表
list.add(new BasicNameValuePair("r", js.toString()));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8");//形式比较单一,是普通的键值对"UTF-8"
httpPost.setEntity(entity);//语句向httpPost对象中添加参数
// execute the post//响应请求
HttpResponse response = mHttpClient.execute(httpPost);//执行请求
String jsString = getResponseContent(response.getEntity());
return new JSONObject(jsString);
} catch (ClientProtocolException e) {//下面是几个异常
Log.e(TAG, e.toString());//下面是对四种不同的异常出现时的处理
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");//post请求失败
} catch (IOException e) {//post执行时发生异常
Log.e(TAG, e.toString());//post执行时发生异常
e.printStackTrace();
throw new NetworkFailureException("postRequest failed");//createTask创建一个任务对象
} 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");
}
}
public void createTask(Task task) throws NetworkFailureException {//方法创建Task,设置好action的链表、client_version、post
commitUpdate();//语句:提交更新
try {
JSONObject jsPost = new JSONObject();//利用JSON获取Task中的内容并创建相应的jspost
JSONArray actionList = new JSONArray();
// action_list//操作列表
actionList.put(task.getCreateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);//用户版本
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);//client的版本号
// post//通过postRequest获取任务的返回信息
JSONObject jsResponse = postRequest(jsPost);//postRequest方法获取任务的返回信息
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
task.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {//代码块:对异常情况的处理
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create task: handing jsonobject failed");
}
}
public void createTaskList(TaskList tasklist) throws NetworkFailureException {//createTaskList创建任务列表与createTask类似
commitUpdate();//提交后更新
try {//动作列表
JSONObject jsPost = new JSONObject();//操作列表
JSONArray actionList = new JSONArray();
// action_list
actionList.put(tasklist.getCreateAction(getActionId()));
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);//客户端版本
// client version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
// post//post操作
JSONObject jsResponse = postRequest(jsPost);
JSONObject jsResult = (JSONObject) jsResponse.getJSONArray(
GTaskStringUtils.GTASK_JSON_RESULTS).get(0);
tasklist.setGid(jsResult.getString(GTaskStringUtils.GTASK_JSON_NEW_ID));
} catch (JSONException e) {//创建失败
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("create tasklist: handing jsonobject failed");
}
}
public void commitUpdate() throws NetworkFailureException {//提交更新数据还是利用JSON
if (mUpdateArray != null) {
try {//新建JSONObject对象使用jsPost.put( )添加对应关系使用postRequest( )方法发送jspost最后给mUpdateArray赋值NULL表示现在没有内容要更新
JSONObject jsPost = new JSONObject();//更新数据
// action_list
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, mUpdateArray);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);//post操作
mUpdateArray = null;//语句:更新处理完毕,列表置空
} catch (JSONException e) {//代码块:对异常的处理
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("commit update: handing jsonobject failed");
}
}
}
public void addUpdateNode(Node node) throws NetworkFailureException {//添加更新节点主要利用commitUpdate
if (node != null) {//更新太多内容可能导致出现异常
// too many update items may result in an error
// set max to 10 items
if (mUpdateArray != null && mUpdateArray.length() > 10) {//提交后更新
commitUpdate();//更新的阵列为空的话就使用JSONArray
}
if (mUpdateArray == null)
mUpdateArray = new JSONArray();
mUpdateArray.put(node.getUpdateAction(getActionId()));//语句:将更新节点加入列表
}
}
public void moveTask(Task task, TaskList preParent, TaskList curParent)//移动一个任务通过getGid获取task所属的Id还是通过JSONObject和postRequest实现
throws NetworkFailureException {//把任务移动到指定的列表中
commitUpdate();//方法:提交更新数据
try {
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
JSONObject action = new 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());
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_SOURCE_LIST, preParent.getGid());//设置当前列表
action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid());//在不同列表间移动时,放入目标列表中去
if (preParent != curParent) {//语句当移动发生在不同的任务列表之间设置为dest_list
// put the dest_list only if moving between tasklists
action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid());//将动作列表放入jsPost中
}
actionList.put(action);
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);//用户版本
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);//postRequst()进行更新后的发送
} catch (JSONException e) {//代码块:异常处理
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("move task: handing jsonobject failed");
}
}
public void deleteNode(Node node) throws NetworkFailureException {//删除节点,过程类似移动
commitUpdate();
try {//代码块新建jsPost把除了node的其他节点都放入jsPost并提交
JSONObject jsPost = new JSONObject();
JSONArray actionList = new JSONArray();
// action_list
node.setDeleted(true);
actionList.put(node.getUpdateAction(getActionId()));// 语句将该节点要更新的操作的id加入操作列表
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
postRequest(jsPost);
mUpdateArray = null;
} catch (JSONException e) {//代码块:异常处理
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("delete node: handing jsonobject failed");
}
}
public JSONArray getTaskLists() throws NetworkFailureException {//获取任务列表首先通过getURI在网上获取数据在截取所需部分内容返回
if (!mLoggedin) {//检查是否在登录状态
Log.e(TAG, "please login first");
throw new ActionFailureException("not logged in");
}
try {//使用url实例化一个获取对象
HttpGet httpGet = new HttpGet(mGetUrl);//通过发送HttpPost请求访问HTTP资源
HttpResponse response = null;//语句初始化Httpresponse (回复)为空
response = mHttpClient.execute(httpGet);//语句使用httpget发送一个请求返回一个response对象
// get the task list//代码块获取任务链表判断resString的开头结尾格式对不对正确的话则重建一个字符串赋值给jsString然后用jsString新建一个JSONObject对象js,并通过js调用一系列方法把任务列表返回
String resString = getResponseContent(response.getEntity());//获取任务列表
String jsBegin = "_setup(";//截取字符串并放入到jsString里
String jsEnd = ")}</script>";
int begin = resString.indexOf(jsBegin);
int end = resString.lastIndexOf(jsEnd);
String jsString = null;
if (begin != -1 && end != -1 && begin < end) {
jsString = resString.substring(begin + jsBegin.length(), end);
}
JSONObject js = new JSONObject(jsString);
return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS);//获取GTASK_JSON_LISTS
} catch (ClientProtocolException e) {//捕捉httpget失败异常
Log.e(TAG, e.toString());//处理异常
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (IOException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new NetworkFailureException("gettasklists: httpget failed");
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task lists: handing jasonobject failed");
}
}
public JSONArray getTaskList(String listGid) throws NetworkFailureException {//方法对于已经获取的任务列表可以通过其id来获取到
commitUpdate();
try {//设置为传入的listGid
JSONObject jsPost = new JSONObject();//设置为传入的listGid
JSONArray actionList = new JSONArray();
JSONObject action = new JSONObject();
// action_list
action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,//通过action.pu()t对JSONObject对象action添加元素通过jsPost.put()对jsPost添加相关元素然后通过postRequest()提交更新后的请求并返回一个JSONObject的对象最后使用jsResponse.getJSONArray( )获取jsResponse中的JSONArray值并作为函数返回值
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL);
action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId());
action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid);//这里设置为传入的listGid
action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false);
actionList.put(action);
jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList);
// client_version
jsPost.put(GTaskStringUtils.GTASK_JSON_CLIENT_VERSION, mClientVersion);
JSONObject jsResponse = postRequest(jsPost);
return jsResponse.getJSONArray(GTaskStringUtils.GTASK_JSON_TASKS);
} catch (JSONException e) {//代码块:处理异常
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("get task list: handing jsonobject failed");
}
}
public Account getSyncAccount() {
return mAccount;
}//获得同步账户。
public void resetUpdateArray() {
mUpdateArray = null;
}//重置更新内容
}

@ -0,0 +1,800 @@
/*
* 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.Activity;//在包里引用各种类
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import net.micode.notes.R;//引用小米便签中的类
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.gtask.data.MetaData;
import net.micode.notes.gtask.data.Node;
import net.micode.notes.gtask.data.SqlNote;
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.DataUtils;
import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
public class GTaskManager {//声明一个类,类名称的命名规范:所有单词的首字母大写
private static final String TAG = GTaskManager.class.getSimpleName();//定义了一系列静态变量来显示GTask当前的状态1设置GTask的TAG
public static final int STATE_SUCCESS = 0;//成功
public static final int STATE_NETWORK_ERROR = 1;//网络错误
public static final int STATE_INTERNAL_ERROR = 2;//内部错误
public static final int STATE_SYNC_IN_PROGRESS = 3;//进程同步中
public static final int STATE_SYNC_CANCELLED = 4;//取消同步
private static GTaskManager mInstance = null;//private 定义一系列不可被外部的类访问的量
private Activity mActivity;//构造函数
private Context mContext;
private ContentResolver mContentResolver;
private boolean mSyncing;
private boolean mCancelled;
private HashMap<String, TaskList> mGTaskListHashMap;
private HashMap<String, Node> mGTaskHashMap;
private HashMap<String, MetaData> mMetaHashMap;
private TaskList mMetaList;
private HashSet<Long> mLocalDeleteIdMap;
private HashMap<String, Long> mGidToNid;
private HashMap<Long, String> mNidToGid;
private GTaskManager() {//方法:类的构造函数,对其内部变量进行初始化
mSyncing = false;//正在同步标识false代表未同步
mCancelled = false;
mGTaskListHashMap = new HashMap<String, TaskList>();//全局标识flase代表可以执行
mGTaskHashMap = new HashMap<String, Node>();//<>代表Java的泛型,就是创建一个用类型作为参数的类。
mMetaHashMap = new HashMap<String, MetaData>();//创建一个删除本地ID的map
mMetaList = null;//创建一个删除本地ID的map
mLocalDeleteIdMap = new HashSet<Long>();
mGidToNid = new HashMap<String, Long>();//建立一个google id到节点id的映射
mNidToGid = new HashMap<Long, String>();//创建一个节点id到google id的映射
}
public static synchronized GTaskManager getInstance() {//synchronized指明该函数可以运行在多线程下
if (mInstance == null) {//初始化mInstance
mInstance = new GTaskManager();//初始化
}
return mInstance;
}
public synchronized void setActivityContext(Activity activity) {//对类的当前实例进行加锁防止其他线程同时访问该类的该实例的所有synchronized块
// used for getting authtoken//获得操作指令
mActivity = activity;
}
public int sync(Context context, GTaskASyncTask asyncTask) {//实现本地和远程同步的操作
if (mSyncing) {//正在同步时,日志中写入正在同步
Log.d(TAG, "Sync is in progress");//debug进程已在同步中
return STATE_SYNC_IN_PROGRESS;//返回同步状态
}
mContext = context;//代码块对同步时GTaskManager的属性进行更新
mContentResolver = mContext.getContentResolver();//对GTaskManager的属性进行更新
mSyncing = true;//初始化各种标志变量
mCancelled = false;
mGTaskListHashMap.clear();//各种环境清空
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
try {//异常处理程序
GTaskClient client = GTaskClient.getInstance();//创建一个用户的实例
client.resetUpdateArray();//getInstance即为创建一个实例
// login google task //更新数组操作
if (!mCancelled) {//登陆用户端
if (!client.login(mActivity)) {//执行登录程序登录到google task
throw new NetworkFailureException("login google task failed");//抛出异常,登录 google 任务失败
}
}
// get the task list from google
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list));
initGTaskList();//调用下面自定义的方法初始化GTaskList
// do content sync work
asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing));
syncContent();//同步便签内容
} catch (NetworkFailureException e) {//网络连接中断
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
return STATE_NETWORK_ERROR;
} catch (ActionFailureException e) {//操作未完成
Log.e(TAG, e.toString());
return STATE_INTERNAL_ERROR;
} catch (Exception e) {//处理各种异常
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();
return STATE_INTERNAL_ERROR;
} finally {//代码块在同步操作结束之后更新GTaskManager的属性
mGTaskListHashMap.clear();//同步结束后清空环境
mGTaskHashMap.clear();
mMetaHashMap.clear();
mLocalDeleteIdMap.clear();
mGidToNid.clear();
mNidToGid.clear();
mSyncing = false;
}
return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS;//语句:若在同步时操作未取消,则说明同步成功,否则返回同步操作取消
}
private void initGTaskList() throws NetworkFailureException {//初始化GTask列表将google上的JSONTaskList转为本地任务列表
if (mCancelled)//是否中途取消
return;
GTaskClient client = GTaskClient.getInstance();//创建一个用户的实例
try {//客户端获取任务列表
JSONArray jsTaskLists = client.getTaskLists();//客户端获取任务列表jsTaskLists
// init meta list first
mMetaList = null;//初始化元数据列表
for (int i = 0; i < jsTaskLists.length(); i++) {//代码块:对获取到任务列表中的每一个元素进行操作
JSONObject object = jsTaskLists.getJSONObject(i);//取出单个JSON对象
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);//获取它的id
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);//获取它的名字
if (name
.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) {//如果 name 等于 字符串 "[MIUI_Notes]" + "METADATA"执行if语句块
mMetaList = new TaskList();//新建数组,并为新建的数组设定内容
mMetaList.setContentByRemoteJSON(object);//新建一个元数据列表
// load meta data
JSONArray jsMetas = client.getTaskList(gid);//将JSON中部分数据复制到自己定义的对象中相对应的数据name->mname...
for (int j = 0; j < jsMetas.length(); j++) {//代码块把jsMetas里的每一个有识别码的metaData都放到哈希表中
object = (JSONObject) jsMetas.getJSONObject(j);//获取一个JSON类型的对象
MetaData metaData = new MetaData();//新建一个Metadata
metaData.setContentByRemoteJSON(object);//新建MetaData
if (metaData.isWorthSaving()) {//需要保存时,将子任务加入到主任务中
mMetaList.addChildTask(metaData);//新建一个元数据列表。
if (metaData.getGid() != null) {//操作getGid取得组识别码函数
mMetaHashMap.put(metaData.getRelatedGid(), metaData);//语句:把元数据放到哈希表中
}
}
}
}
}
// create meta list if not existed
if (mMetaList == null) {//代码块:若元数据列表不存在则创建一个
mMetaList = new TaskList();//元数据列表不存在,则在客户端创建一个
mMetaList.setName(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_META);
GTaskClient.getInstance().createTaskList(mMetaList);
}
// init task list
for (int i = 0; i < jsTaskLists.length(); i++) {//以下循环用于初始化任务列表
JSONObject object = jsTaskLists.getJSONObject(i);//代码块:先获取列表中每一个节点的属性
String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);//通过getString函数传入本地某个标志数据的名称获取其在远端的名称
String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME);//获取JSON名字
if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX)
&& !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX
+ GTaskStringUtils.FOLDER_META)) {
TaskList tasklist = new TaskList();//语句: 创建一个新的任务列表
tasklist.setContentByRemoteJSON(object);//语句:对任务列表的内容进行设置
mGTaskListHashMap.put(gid, tasklist);//对任务列表的内容进行设置
mGTaskHashMap.put(gid, tasklist);
// load tasks
JSONArray jsTasks = client.getTaskList(gid);//获取任务id号
for (int j = 0; j < jsTasks.length(); j++) {//任务id号
object = (JSONObject) jsTasks.getJSONObject(j);
gid = object.getString(GTaskStringUtils.GTASK_JSON_ID);//语句获取当前任务的gid
Task task = new Task();
task.setContentByRemoteJSON(object);//语句:设置任务内容
if (task.isWorthSaving()) {//语句:判断该任务有无价值保存
task.setMetaInfo(mMetaHashMap.get(gid));//判断该任务是否有价值
tasklist.addChildTask(task);
mGTaskHashMap.put(gid, task);
}
}
}
}
} catch (JSONException e) {//初始化时捕捉异常
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();
throw new ActionFailureException("initGTaskList: handing JSONObject failed");//抛出异常,提交 JSONObject 失败
}
}
private void syncContent() throws NetworkFailureException {//实现内容同步
int syncType;//本地内容同步操作
Cursor c = null;//同步操作类
String gid;
Node node;//Node包含Sync_Action的不同类型
mLocalDeleteIdMap.clear();//初始化本地删除列表
if (mCancelled) {//对于本地已删除的便签采取的动作
return;
}
// for local deleted note
try {//代码块:对于删除本地便签的操作的同步
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,//语句:指针指向待删除的便签位置
"(type<>? AND parent_id=?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
}, null);
if (c != null) {//代码块:若获取到的待删除便签不为空,则进行同步操作
while (c.moveToNext()) {//通过while用指针遍历所有结点
gid = c.getString(SqlNote.GTASK_ID_COLUMN);//语句获取待删除便签的gid
node = mGTaskHashMap.get(gid);//语句:获取待删除便签的节点
if (node != null) {//节点非空则从哈希表里删除,并进行同步操作
mGTaskHashMap.remove(gid);//语句将待删除的节点对应的google id从映射表中移除
doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c);//语句:在远程删除对应节点
}
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));//查找不到时,在日志中记录信息
}
} else {//若c结点为空即寻找错误的时候报错
Log.w(TAG, "failed to query trash folder");//警告,询问垃圾文件夹失败
}
} finally {//代码块最后把c关闭并重置代码块
if (c != null) {//结束操作之后,将指针指向内容关闭并将指针置空
c.close();//记得关闭 cursor 所指文件
c = null;//cursor 置空
}
}
// sync folder first
syncFolder();//语句:对文件夹进行同步
// for note existing in database
try {//对于数据库中已经存在的便签,采取以下操作
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,//语句使c指针指向待操作的便签位置
"(type=? AND parent_id<>?)", new String[] {//c指针指向待操作的位置
String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");
if (c != null) {//query语句的用法
while (c.moveToNext()) {//语句:指针向后移动
gid = c.getString(SqlNote.GTASK_ID_COLUMN);//语句获取待操作的便签的gid
node = mGTaskHashMap.get(gid);//语句:获取待操作的便签的节点
if (node != null) {//若结点不为空将其对应的google id从映射表中移除然后建立google id到节点id的映射通过hashmap、gid和nid之间的映射表
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));//建立google id到节点id的映射
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);//通过hashmap建立联系
syncType = node.getSyncAction(c);//语句:更新此时的同步类型
} else {//代码块如果note是空的则判断c的trim的长度是否为0如果是则设置同步类型为ADD REMOTE,否则设置为DEL LOCAL
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {//语句:若本地增加了内容,则远程也要增加内容
// local add
syncType = Node.SYNC_ACTION_ADD_REMOTE;//远程增加内容
} else {//语句若本地删除了内容则远程也要删除内容应的gid
// remote delete
syncType = Node.SYNC_ACTION_DEL_LOCAL;//本地删除
}
}
doContentSync(syncType, node, c);//进行同步操作
}
} else {
Log.w(TAG, "failed to query existing note in database");//查询失败时在日志中写回错误信息
}
} finally {//代码块在最后关闭c并重置
if (c != null) {//代码块:结束操作之后,将指针指向内容关闭并将指针置空
c.close();//关闭 cursor 所指文件
c = null;//cursor 置空
}
}
// go through remaining items
Iterator<Map.Entry<String, Node>> iter = mGTaskHashMap.entrySet().iterator();//扫描剩下的项目,逐个进行同步
while (iter.hasNext()) {//迭代
Map.Entry<String, Node> entry = iter.next();
node = entry.getValue();//getValue()可以获取指定对象的属性值
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);//语句:在本地增加这些节点
}
// mCancelled can be set by another thread, so we neet to check one by
// one
// clear local delete table
if (!mCancelled) {
if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) {//语句:终止标识有可能被其他进程改变,因此需要一个个进行检查
throw new ActionFailureException("failed to batch-delete local deleted notes");//终止标识有可能被其他线程改变
}
}
// refresh local sync id
if (!mCancelled) {//更新同步表
GTaskClient.getInstance().commitUpdate();//更新同步表
refreshLocalSyncId();//更新同步的id
}
}
private void syncFolder() throws NetworkFailureException {//同步文件夹
Cursor c = null;//同步文件夹
String gid;
Node node;
int syncType;
if (mCancelled) {//语句:判断是否取消该操作
return;
}
// for root folder
try {//对于根文件夹
c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,//语句:使指针指向根文件夹的位置
Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null);//使指针指向根文件夹的位置
if (c != null) {
c.moveToNext();
gid = c.getString(SqlNote.GTASK_ID_COLUMN);//语句获取指针指向内容对应的gid
node = mGTaskHashMap.get(gid);//语句获取该gid所代表的节点
if (node != null) {//获取gid所代表的节点
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER);//语句将该节点的gid到nid的映射加入映射表
mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid);
// for system folder, only update remote name if necessary
if (!node.getName().equals(//添加MIUI文件前缀
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT))
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);//语句:若非系统文件夹则在远程进行增加节点操作
}
} else {
Log.w(TAG, "failed to query root folder");//出现异常时,在日志中写回出错信息
}
} finally {//结束操作之后,最后将指针关闭,并将指针置空。方法与之前相同
if (c != null) {//代码块:结束操作之后,将指针指向内容关闭并将指针置空
c.close();//关闭 cursor 所指文件
c = null;//cursor 置空
}
}
// for call-note folder
try {//对于电话号码数据文件
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)",//语句:使指针指向文件夹的位置
new String[] {//添加MIUI文件前缀
String.valueOf(Notes.ID_CALL_RECORD_FOLDER)//添加MIUI文件前缀
}, null);
if (c != null) {
if (c.moveToNext()) {
gid = c.getString(SqlNote.GTASK_ID_COLUMN);//语句获取指针指向内容对应的gid
node = mGTaskHashMap.get(gid);//语句获取指针指向内容对应的gid
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER);//语句将该节点的gid到nid的映射加入映射表
mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid);
// for system folder, only update remote name if
// necessary
if (!node.getName().equals(//语句:若当前访问的文件夹是系统文件夹则只需要更新
GTaskStringUtils.MIUI_FOLDER_PREFFIX//若当前访问的文件夹是系统文件夹则只需更新
+ GTaskStringUtils.FOLDER_CALL_NOTE))
doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c);
} else {
doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c);//语句:若非系统文件夹则在远程进行增加节点操作
}
}
} else {
Log.w(TAG, "failed to query call note folder");//警告,询问通讯便签文件夹失败
}
} finally {
if (c != null) {//代码块:结束操作之后,将指针指向内容关闭并将指针置空
c.close();//关闭 cursor 所指文件
c = null;//cursor 置空
}
}
// for local existing folders
try {//对于本地已存在的文件的操作
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,// 语句:使指针指向第一个文件夹的位置
"(type=? AND parent_id<>?)", new String[] {//使指针指向第一个文件夹的位置
String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");
if (c != null) {
while (c.moveToNext()) {//语句:使指针遍历所有的文件夹
gid = c.getString(SqlNote.GTASK_ID_COLUMN);
node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN));//语句获取指针指向内容对应的gid
mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid);//语句获取指针指向内容对应的gid
syncType = node.getSyncAction(c);//语句:更新同步类型
} else {//更新同步类型
if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) {//语句:若本地增加了内容,则远程也要增加内容
// local add
syncType = Node.SYNC_ACTION_ADD_REMOTE;//远程添加
} else {//语句:若远程删除了内容,则本地也要删除内容
// remote delete
syncType = Node.SYNC_ACTION_DEL_LOCAL;//本地删除
}
}
doContentSync(syncType, node, c);//语句:进行同步操作
}
} else {//进行同步操作
Log.w(TAG, "failed to query existing folder");//警告,询问已创建的文件夹失败
}
} finally {
if (c != null) {//代码块:结束操作之后,将指针指向内容关闭并将指针置空
c.close();//关闭 cursor 所指文件
c = null;//cursor 置空
}
}
// for remote add folders
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();//远程添加文件需要执行的操作
while (iter.hasNext()) {//语句:使用迭代器对远程增添的内容进行遍
Map.Entry<String, TaskList> entry = iter.next();
gid = entry.getKey();//语句获取对应的gid
node = entry.getValue();//语句获取gid对应的节点
if (mGTaskHashMap.containsKey(gid)) {
mGTaskHashMap.remove(gid);
doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null);//语句:进行本地增添操作
}
}
if (!mCancelled)
GTaskClient.getInstance().commitUpdate();//语句如果没有取消在GTsk的客户端进行实例的提交更新
}
private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException {//功能syncType分类
if (mCancelled) {//进行本地增添操作
return;
}
MetaData meta;
switch (syncType) {//根据同步类型选择操作
case Node.SYNC_ACTION_ADD_LOCAL://远程添加
addLocalNode(node);//本地添加
break;
case Node.SYNC_ACTION_ADD_REMOTE://本地删除
addRemoteNode(node, c);//本地删除
break;
case Node.SYNC_ACTION_DEL_LOCAL://远程删除
meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN));
if (meta != null) {
GTaskClient.getInstance().deleteNode(meta);
}
mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN));
break;
case Node.SYNC_ACTION_DEL_REMOTE://更新本地数据
meta = mMetaHashMap.get(node.getGid());//更新本地数据
if (meta != null) {
GTaskClient.getInstance().deleteNode(meta);
}
GTaskClient.getInstance().deleteNode(node);
break;
case Node.SYNC_ACTION_UPDATE_LOCAL://更新远程数据
updateLocalNode(node, c);
break;
case Node.SYNC_ACTION_UPDATE_REMOTE:
updateRemoteNode(node, c);
break;
case Node.SYNC_ACTION_UPDATE_CONFLICT://同步出错
// merging both modifications maybe a good idea
// right now just use local update simply
updateRemoteNode(node, c);
break;
case Node.SYNC_ACTION_NONE://代码块:空操作
break;//空操作
case Node.SYNC_ACTION_ERROR://代码块:操作错误
default://代码块default:同步类型不在规定的类型范围内
throw new ActionFailureException("unkown sync action type");//抛出异常,未知的同步行为类型
}
}
private void addLocalNode(Node node) throws NetworkFailureException {//功能本地增加Node
if (mCancelled) {//这个函数是添加本地结点参数node即为要添加的本地结点
return;
}
SqlNote sqlNote;
if (node instanceof TaskList) {//节点是任务列表中的一个节点
if (node.getName().equals(//代码块:在根目录中增加节点
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) {
sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER);
} else if (node.getName().equals(//代码块:在存放电话号码便签的文件夹中增加节点
GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) {
sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER);
} else {//代码块如果在其他文件夹里则用一般操作设置sqlNote的参数
sqlNote = new SqlNote(mContext);//代码块:若没有存放的文件夹,则将其放在根文件夹中
sqlNote.setContent(node.getLocalJSONFromContent());//从本地任务列表中获取内容
sqlNote.setParentId(Notes.ID_ROOT_FOLDER);
}
} else {//代码块:若待增添节点不是任务列表中的节点,进一步操作
sqlNote = new SqlNote(mContext);
JSONObject js = node.getLocalJSONFromContent();//语句从待增添节点中获取jsonobject对象
try {//异常判断
if (js.has(GTaskStringUtils.META_HEAD_NOTE)) {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);//语句获取对应便签的jsonobject对象
if (note.has(NoteColumns.ID)) {//语句:判断便签中是否有条目
long id = note.getLong(NoteColumns.ID);
if (DataUtils.existInNoteDatabase(mContentResolver, id)) {//id存在时删除id
// the id is not available, have to create a new one
note.remove(NoteColumns.ID);
}
}
}
if (js.has(GTaskStringUtils.META_HEAD_DATA)) {//以下为判断便签中的数据条目
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
for (int i = 0; i < dataArray.length(); i++) {//依次删除存在的data的ID
JSONObject data = dataArray.getJSONObject(i);//语句获取对应数据的jsonobject对象
if (data.has(DataColumns.ID)) {//语句:判断数据中是否有条目
long dataId = data.getLong(DataColumns.ID);
if (DataUtils.existInDataDatabase(mContentResolver, dataId)) {//data id存在时删除已建立的对应ID
// the data id is not available, have to create
// a new one
data.remove(DataColumns.ID);
}
}
}
}
} catch (JSONException e) {//出现异常时,打印异常信息
Log.w(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();
}
sqlNote.setContent(js);//语句将之前的操作获取到的js更新至该节点中
Long parentId = mGidToNid.get(((Task) node).getParent().getGid());//代码块找到父任务的ID号并作为sqlNote的父任务的ID没有父任务则报错
if (parentId == null) {//语句当不能找到该任务上一级的id时报错
Log.e(TAG, "cannot find task's parent id locally");//本地无法找到父进程id
throw new ActionFailureException("cannot add local node");//报告无法添加本地节点
}
sqlNote.setParentId(parentId.longValue());
}
// create the local node
sqlNote.setGtaskId(node.getGid());//设置google task id
sqlNote.commit(false);//更新本地便签
// update gid-nid mapping
mGidToNid.put(node.getGid(), sqlNote.getId());//语句更新gid与nid的映射表
mNidToGid.put(sqlNote.getId(), node.getGid());
// update meta
updateRemoteMeta(node.getGid(), sqlNote);//语句:更新远程的数据
}
private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException {//函数:更新本地节点,两个传入参数,一个是待更新的节点,一个是指向待增加位置的指针
if (mCancelled) {//如果正在取消同步,直接返回
return;
}
SqlNote sqlNote;//新建一个sql节点并将内容存储进Node中
// update the note locally
sqlNote = new SqlNote(mContext, c);//语句:在指针指向处创建一个新的节点
sqlNote.setContent(node.getLocalJSONFromContent());//语句:利用待更新节点中的内容对数据库节点进行设置
Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid())//语句: 设置父任务的ID通过判断node是不是Task的实例
: new Long(Notes.ID_ROOT_FOLDER);
if (parentId == null) {//语句当不能找到该任务上一级的id时报错
Log.e(TAG, "cannot find task's parent id locally");//错误,不能在本地找到任务的父 id
throw new ActionFailureException("cannot update local node");//抛出异常,不能更新本地节点
}
sqlNote.setParentId(parentId.longValue());//设置该任务节点上一级的id
sqlNote.commit(true);//抛出异常,不能更新本地节点
// update meta info
updateRemoteMeta(node.getGid(), sqlNote);//升级meta
}
private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException {//添加远程节点
if (mCancelled) {//如果正在取消同步,直接返回
return;
}
SqlNote sqlNote = new SqlNote(mContext, c);//新建一个sql节点并将内容存储进Node中
Node n;
// update remotely
if (sqlNote.isNoteType()) {//语句:若待增添的节点为任务节点,进一步操作
Task task = new Task();
task.setContentByLocalJSON(sqlNote.getContent());
String parentGid = mNidToGid.get(sqlNote.getParentId());//找不到parentID时报错
if (parentGid == null) {
Log.e(TAG, "cannot find task's parent tasklist");//错误,无法找到任务的父列表
throw new ActionFailureException("cannot add remote task");//抛出异常,无法添加云端任务
}
mGTaskListHashMap.get(parentGid).addChildTask(task);//在本地生成的GTaskList中增加子结点
GTaskClient.getInstance().createTask(task);//在本地生成的GTaskList中增加子结点
n = (Node) task;
// add meta//添加元数据
updateRemoteMeta(task.getGid(), sqlNote);
} else {
TaskList tasklist = null;
// we need to skip folder if it has already existed//当文件夹存在则跳过,若不存在则创建新的文件夹
String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX;//代码块:当文件夹已经存在则跳过处理,若不存在则创建新的文件夹
if (sqlNote.getId() == Notes.ID_ROOT_FOLDER)//按照文件夹的形式进行命名
folderName += GTaskStringUtils.FOLDER_DEFAULT;//语句:若为根文件夹则按根文件夹命名
else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER)
folderName += GTaskStringUtils.FOLDER_CALL_NOTE;//语句:若为电话号码便签文件夹则按电话号码便签命名
else
folderName += sqlNote.getSnippet();
Iterator<Map.Entry<String, TaskList>> iter = mGTaskListHashMap.entrySet().iterator();//使用iterator作为map接口对map进行遍历
while (iter.hasNext()) {//iterator迭代器通过统一的接口迭代所有的map元素
Map.Entry<String, TaskList> entry = iter.next();
String gid = entry.getKey();
TaskList list = entry.getValue();
if (list.getName().equals(folderName)) {//代码块:若寻找到的任务列表已存在,则直接在里面更新
tasklist = list;//找不到可以匹配的任务链
if (mGTaskHashMap.containsKey(gid)) {
mGTaskHashMap.remove(gid);
}
break;
}
}
// no match we can add now
if (tasklist == null) {//若没有匹配的任务列表,则创建一个新的任务列表
tasklist = new TaskList();//直接新建一个任务链
tasklist.setContentByLocalJSON(sqlNote.getContent());
GTaskClient.getInstance().createTaskList(tasklist);
mGTaskListHashMap.put(tasklist.getGid(), tasklist);
}
n = (Node) tasklist;
}
// update local note//进行本地节点的更新
sqlNote.setGtaskId(n.getGid());//创建id间的映射
sqlNote.commit(false);
sqlNote.resetLocalModified();
sqlNote.commit(true);
// gid-id mapping//进行gid与nid映射关系的更新
mGidToNid.put(n.getGid(), sqlNote.getId());//代码块更新gid-nid映射表
mNidToGid.put(sqlNote.getId(), n.getGid());
}
private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException {//更新远程节点
if (mCancelled) {//如果正在取消同步,直接返回
return;
}
SqlNote sqlNote = new SqlNote(mContext, c);//语句:在指针指向处创建一个新的节点
// update remotely
node.setContentByLocalJSON(sqlNote.getContent());//代码块:远程更新
GTaskClient.getInstance().addUpdateNode(node);//GTaskClient用途为从本地登陆远端服务器
// update meta
updateRemoteMeta(node.getGid(), sqlNote);//语句:更新数据
// move task if necessary
if (sqlNote.isNoteType()) {//判断节点类型是否符合要求
Task task = (Task) node;//新建一个task节点
TaskList preParentList = task.getParent();//找到当前任务列表的父节点google id和之前父任务链
String curParentGid = mNidToGid.get(sqlNote.getParentId());//curParentGid为通过光标在数据库中找到sqlNote的mParentId再通过mNidToGid由long类型转为String类型的Gid
if (curParentGid == null) {//代码块:找不到当前任务的上一级任务列表,报错
Log.e(TAG, "cannot find task's parent tasklist");//错误,无法找到任务的父列表
throw new ActionFailureException("cannot update remote task");//抛出异常,无法添加云端任务
}
TaskList curParentList = mGTaskListHashMap.get(curParentGid);//通过HashMap找到对应Gid的TaskList
if (preParentList != curParentList) {//语句:若两个上一级任务列表不一致,进行任务的移动,从之前的任务列表中移动到该列表中
preParentList.removeChildTask(task);
curParentList.addChildTask(task);
GTaskClient.getInstance().moveTask(task, preParentList, curParentList);
}
}
// clear local modified flag
sqlNote.resetLocalModified();//清除本地的modified flag
sqlNote.commit(true);
}
private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException {//更新远程元数组的google id和数据库节点
if (sqlNote != null && sqlNote.isNoteType()) {//判断节点类型是否符合,类型符合时才进行更新操作
MetaData metaData = mMetaHashMap.get(gid);//从google id获取任务列表
if (metaData != null) {//语句:若元数据组为空,则创建一个新的元数据组
metaData.setMeta(gid, sqlNote.getContent());//任务列表不存在时 新建一个空的任务列表并将其放入google id中
GTaskClient.getInstance().addUpdateNode(metaData);
} else {//语句:若元数据组不为空,则进行更新
metaData = new MetaData();
metaData.setMeta(gid, sqlNote.getContent());
mMetaList.addChildTask(metaData);
mMetaHashMap.put(gid, metaData);
GTaskClient.getInstance().createTask(metaData);
}
}
}
private void refreshLocalSyncId() throws NetworkFailureException {//刷新本地便签id从远程同步
if (mCancelled) {
return;
}//获取最近的gtask list
// get the latest gtask list//获取最新的gtask列表
mGTaskHashMap.clear();//否则初始化hash表
mGTaskListHashMap.clear();
mMetaHashMap.clear();
initGTaskList();
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE,
"(type<>? AND parent_id<>?)", new String[] {
String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)
}, NoteColumns.TYPE + " DESC");//query语句五个参数NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。newString[{String.valueOf(Notes.TYPE_SYSTEM),String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uri
if (c != null) {
while (c.moveToNext()) {//获取最新的GTask列表
String gid = c.getString(SqlNote.GTASK_ID_COLUMN);
Node node = mGTaskHashMap.get(gid);
if (node != null) {
mGTaskHashMap.remove(gid);
ContentValues values = new ContentValues();
values.put(NoteColumns.SYNC_ID, node.getLastModified());//在ContentValues中创建键值对。准备通过contentResolver写入数据
mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI,
c.getLong(SqlNote.ID_COLUMN)), values, null, null);
} else {
Log.e(TAG, "something is missed");//错误,部分内容丢失
throw new ActionFailureException(
"some local items don't have gid after sync");
}
}
} else {//进行批量更改选择参数为NULL应该可以用insert替换参数分别为表名和需要更新的value对象。
Log.w(TAG, "failed to query local note to refresh sync id");//警告,询问本地待同步更新的便签 id 失败
}
} finally {
if (c != null) {
c.close();
c = null;
}
}
}
public String getSyncAccount() {
return GTaskClient.getInstance().getSyncAccount().name;//返回待同步帐户的名称
}//获取同步账号
public void cancelSync() {
mCancelled = true;
}//取消同步置mCancelled为true
}

@ -0,0 +1,128 @@
/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)//GTask同步服务用于提供同步服务开始、取消同步发送广播
*
* 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;//Service是Android四大组件之一通常用作在后台处理耗时的逻辑不用与用户进行交互即使应用被销毁依然可以继续工作。
import android.app.Activity;//引用包
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
public class GTaskSyncService extends Service {//Service是在一段不定的时间运行在后台不和用户交互的应用组件
public final static String ACTION_STRING_NAME = "sync_action_type";//定义一系列静态变量
public final static int ACTION_START_SYNC = 0;//开始同步
public final static int ACTION_CANCEL_SYNC = 1;//取消同步
public final static int ACTION_INVALID = 2;//活动非法为2
public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service";//服务广播的名称
public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing";//正在同步中
public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg";//进程消息
private static GTaskASyncTask mSyncTask = null;
private static String mSyncProgress = "";
private void startSync() {//开始同步
if (mSyncTask == null) {//若当前没有同步工作申请一个task并把指针指向新任务广播后执行
mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() {
public void onComplete() {//实现了在GTaskASyncTask类中定义的接口onComplete( )
mSyncTask = null;
sendBroadcast("");//广播同步消息
stopSelf();//当完成所有功能之后将service停掉
}
});
sendBroadcast("");
mSyncTask.execute();//语句:调用同步执行的函数
}
}
private void cancelSync() {//取消同步
if (mSyncTask != null) {//同步的任务非空
mSyncTask.cancelSync();//如果正在同步,结束当前同步
}
}
@Override
public void onCreate() {
mSyncTask = null;
}//初始化一个service
@Override
public int onStartCommand(Intent intent, int flags, int startId) {//充当重启便签指令
Bundle bundle = intent.getExtras();//Bundle类用作携带数据用于存放key-value明值对应形式的值。
if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) {//判断当前的同步状态,根据开始或取消,执行对应操作
switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) {//判断当前同步状态,启动或取消
case ACTION_START_SYNC://启动同步
startSync();
break;
case ACTION_CANCEL_SYNC://取消同步
cancelSync();
break;
default:
break;
}
return START_STICKY;//等待新的intent来是这个service继续运行
}
return super.onStartCommand(intent, flags, startId);//调用父类的函数
}
@Override//处理内存不足的情况,即取消同步
public void onLowMemory() {//广播信息msg
if (mSyncTask != null) {
mSyncTask.cancelSync();
}
}
public IBinder onBind(Intent intent) {
return null;
}//函数:用于绑定操作的函数
public void sendBroadcast(String msg) {//发送广播内容
mSyncProgress = msg;
Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME);//创建一个新的Intent
intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null);//附加INTENT中的相应参数的值
intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg);
sendBroadcast(intent);//发送这个通知
}
public static void startSync(Activity activity) {//启动同步
GTaskManager.getInstance().setActivityContext(activity);//任务管理器获取活动的内容
Intent intent = new Intent(activity, GTaskSyncService.class);//创建新intent
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC);//将之前初始化的各种字符串加入intent
activity.startService(intent);//开始同步服务
}
public static void cancelSync(Context context) {//取消同步
Intent intent = new Intent(context, GTaskSyncService.class);//显式构建intent以函数参数context作为第一个参数以自己GTaskSyncService.class作为目标活动
intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC);//把想要传递的数据暂存到intent中传递数据以“键值对”形式传入。键为"sync_action_type"值为1
context.startService(intent);//使用startService执行intent在本活动基础上打开GTaskSyncService活动
}
public static boolean isSyncing() {
return mSyncTask != null;
}//判断当前是否处于同步状态
public static String getProgressString() {
return mSyncProgress;
}//返回当前同步状态
}
Loading…
Cancel
Save