You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
GPL_Project/doc/标注/210340061_林亭旭/SqlNote.java

555 lines
23 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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.data;
import android.appwidget.AppWidgetManager;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
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.exception.ActionFailureException;
import net.micode.notes.tool.GTaskStringUtils;
import net.micode.notes.tool.ResourceParser;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class SqlNote {
private static final String TAG/*私有静态常量*/ = SqlNote.class.getSimpleName();
private static final int INVALID_ID = -99999;//无效的 ID
public static final String[] PROJECTION_NOTE = new String[]
//需要在查询中选择的笔记属性
{
NoteColumns.ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID,
NoteColumns.CREATED_DATE, NoteColumns.HAS_ATTACHMENT, NoteColumns.MODIFIED_DATE,
NoteColumns.NOTES_COUNT, NoteColumns.PARENT_ID, NoteColumns.SNIPPET, NoteColumns.TYPE,
NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE, NoteColumns.SYNC_ID,
NoteColumns.LOCAL_MODIFIED, NoteColumns.ORIGIN_PARENT_ID, NoteColumns.GTASK_ID,
NoteColumns.VERSION
};
public static final int ID_COLUMN = 0;//ID 属性在 PROJECTION_NOTE 数组中的下标为 0
public static final int ALERTED_DATE_COLUMN = 1;
public static final int BG_COLOR_ID_COLUMN = 2;
public static final int CREATED_DATE_COLUMN = 3;
public static final int HAS_ATTACHMENT_COLUMN = 4;
public static final int MODIFIED_DATE_COLUMN = 5;
public static final int NOTES_COUNT_COLUMN = 6;
public static final int PARENT_ID_COLUMN = 7;
public static final int SNIPPET_COLUMN = 8;
public static final int TYPE_COLUMN = 9;
public static final int WIDGET_ID_COLUMN = 10;
public static final int WIDGET_TYPE_COLUMN = 11;
public static final int SYNC_ID_COLUMN = 12;
public static final int LOCAL_MODIFIED_COLUMN = 13;
public static final int ORIGIN_PARENT_ID_COLUMN = 14;
public static final int GTASK_ID_COLUMN = 15;
public static final int VERSION_COLUMN = 16;
private Context mContext;//上下文
private ContentResolver mContentResolver;//ContentResolver 对象
private boolean mIsCreate;//表示是否在数据库中创建新笔记
private long mId;//笔记的 ID
private long mAlertDate;//提醒日期
private int mBgColorId;//背景颜色 ID
private long mCreatedDate;//创建日期
private int mHasAttachment;//是否有附件
private long mModifiedDate;//修改日期
private long mParentId;//父笔记 ID
private String mSnippet;//笔记的摘要
private int mType;//笔记类型
private int mWidgetId;//小部件 ID
private int mWidgetType;//小部件类型
private long mOriginParent;//原始父笔记 ID
private long mVersion;//版本号
private ContentValues mDiffNoteValues;// ContentValues 类型的 mDiffNoteValues
private ArrayList<SqlData> mDataList;//SqlData 对象的列表
public SqlNote(Context context) {
mContext = context;
mContentResolver = context.getContentResolver();
//将传入的上下文对象赋值给成员变量 mContext 和 mContentResolver
mIsCreate = true;
//将 mIsCreate 置为 true表示该笔记是要被创建的
mId = INVALID_ID;
//mId 赋值为常量 INVALID_ID表示该笔记的 ID 是无效的
mAlertDate = 0;
mBgColorId = ResourceParser.getDefaultBgId(context);//
// 将 mBgColorId 设为默认背景颜色 ID
mCreatedDate = System.currentTimeMillis();
// 将 mCreatedDate 和 mModifiedDate 设为当前时间戳。
mHasAttachment = 0;
//mHasAttachment 设为 0表示该笔记没有附件
mModifiedDate = System.currentTimeMillis();
mParentId = 0;
//mParentId 设为 0表示该笔记的父 ID 是无效的
mSnippet = "";//mSnippet 设为空字符串,表示该笔记没有摘要
mType = Notes.TYPE_NOTE;
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;//该笔记没有小部件 ID
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;//该笔记不是小部件
mOriginParent = 0;//该笔记没有原始父笔记
mVersion = 0;//笔记的版本号是 0
mDiffNoteValues = new ContentValues();
//建一个空的 ContentValues 对象赋值给 mDiffNoteValues
mDataList = new ArrayList<SqlData>();
//创建一个空的 SqlData 对象列表 mDataList
}
public SqlNote(Context context, Cursor c)
//将传入的 Cursor 对象中的数据加载到 SqlNote 对象中
{
mContext = context;
mContentResolver = context.getContentResolver();
//分别赋值为传入的上下文
mIsCreate = false;//这是一个已经存在的笔记
loadFromCursor(c);//从 Cursor 对象中读取数据并加载到 SqlNote 对象中
mDataList = new ArrayList<SqlData>();//创建一个空的 SqlData 对象列表 mDataList
if (mType == Notes.TYPE_NOTE)
//如果该笔记是普通笔记,则调用 loadDataContent() 方法从数据库读取笔记内容和附件信息
loadDataContent();
mDiffNoteValues = new ContentValues();
//创建一个空的 ContentValues 对象赋值给 mDiffNoteValues
}
public SqlNote(Context context, long id)
//根据笔记 ID 加载笔记数据
{
mContext = context;
mContentResolver = context.getContentResolver();//初始化
mIsCreate = false;//已经存在的笔记
loadFromCursor(id);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
//创建一个空的 ContentValues 对象赋值给 mDiffNoteValues
}
private void loadFromCursor(long id)
//根据给定的笔记 ID 从数据库中加载笔记信息
{
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
//查询指定 ID 的笔记数据
new String[] {
String.valueOf(id)
}, null);//对获取数据进行判空
if (c != null) {
c.moveToNext();
loadFromCursor(c);
// 不为空,将游标移动到第一行,
// 并调用 loadFromCursor(Cursor c) 方法将数据加载到 SqlNote 对象中
} else {
Log.w(TAG, "loadFromCursor: cursor = null");//为空,则打印一条警告日志
}
} finally {
if (c != null)
c.close();
}
}
private void loadFromCursor(Cursor c)
//从 Cursor 对象中加载笔记数据
{
mId = c.getLong(ID_COLUMN);//笔记的 ID
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);//提醒时间
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);//背景颜色 ID
mCreatedDate = c.getLong(CREATED_DATE_COLUMN);//创建时间
mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);//是否有附件
mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);//修改时间
mParentId = c.getLong(PARENT_ID_COLUMN);//父亲笔记的 ID
mSnippet = c.getString(SNIPPET_COLUMN);//笔记片段
mType = c.getInt(TYPE_COLUMN);//笔记类型
mWidgetId = c.getInt(WIDGET_ID_COLUMN);//挂件 ID
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);//挂件类型
mVersion = c.getLong(VERSION_COLUMN);//版本号
}
private void loadDataContent()
//从数据库中读取笔记的内容和附件信息,并将其存储在 mDataList
{
Cursor c = null;
mDataList.clear();
//清空 mDataList 列表
try {
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,
"(note_id=?)", new String[] {
String.valueOf(mId)
}, null);//判断获取到的 Cursor 对象是否为空
if (c != null) {// 不为空,则判断游标中是否有数据
if (c.getCount() == 0) {
Log.w(TAG, "it seems that the note has not data");
//无数据,则打印一条警告日志并返回
return;
}
while (c.moveToNext()) {
SqlData data = new SqlData(mContext, c);
mDataList.add(data);
}//遍历游标中的每一行数据,创建 SqlData 对象并添加到 mDataList 列表
} else {
Log.w(TAG, "loadDataContent: cursor = null");
}
} finally {
if (c != null)
c.close();
}
}
public boolean setContent(JSONObject js)
//据传入的 JSONObject 对象设置笔记的内容
{
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_SYSTEM) {
Log.w(TAG, "cannot set system folder");
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_FOLDER) {
// for folder we can only update the snnipet and type
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;
if (mIsCreate || mId != id) {
mDiffNoteValues.put(NoteColumns.ID, id);
}
mId = id;
long alertDate = note.has(NoteColumns.ALERTED_DATE) ? note
.getLong(NoteColumns.ALERTED_DATE) : 0;
if (mIsCreate || mAlertDate != alertDate) {
mDiffNoteValues.put(NoteColumns.ALERTED_DATE, alertDate);
}
mAlertDate = alertDate;
int bgColorId = note.has(NoteColumns.BG_COLOR_ID) ? note
.getInt(NoteColumns.BG_COLOR_ID) : ResourceParser.getDefaultBgId(mContext);
if (mIsCreate || mBgColorId != bgColorId) {
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);
}
mBgColorId = bgColorId;
//系统文件夹或者文件夹类型的笔记,只能更新摘要和类型,而对于笔记类型的笔记,会解析出一系列字段,并将它们保存在一个 List 中
long createDate = note.has(NoteColumns.CREATED_DATE) ? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate != createDate) {
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);
}
mCreatedDate = createDate;
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment != hasAttachment) {
mDiffNoteValues.put(NoteColumns.HAS_ATTACHMENT, hasAttachment);
}
mHasAttachment = hasAttachment;
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
if (mIsCreate || mModifiedDate != modifiedDate) {
mDiffNoteValues.put(NoteColumns.MODIFIED_DATE, modifiedDate);
}
mModifiedDate = modifiedDate;
long parentId = note.has(NoteColumns.PARENT_ID) ? note
.getLong(NoteColumns.PARENT_ID) : 0;
if (mIsCreate || mParentId != parentId) {
mDiffNoteValues.put(NoteColumns.PARENT_ID, parentId);
}
mParentId = parentId;
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
mDiffNoteValues.put(NoteColumns.SNIPPET, snippet);
}
mSnippet = snippet;
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
mDiffNoteValues.put(NoteColumns.TYPE, type);
}
mType = type;
int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID;
if (mIsCreate || mWidgetId != widgetId) {
mDiffNoteValues.put(NoteColumns.WIDGET_ID, widgetId);
}
mWidgetId = widgetId;
int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note
.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;
if (mIsCreate || mWidgetType != widgetType) {
mDiffNoteValues.put(NoteColumns.WIDGET_TYPE, widgetType);
}
mWidgetType = widgetType;
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;
if (mIsCreate || mOriginParent != originParent) {
mDiffNoteValues.put(NoteColumns.ORIGIN_PARENT_ID, originParent);
}
mOriginParent = originParent;
//分别解析
for (int i = 0; i < dataArray.length(); i++)
{
JSONObject data = dataArray.getJSONObject(i);
SqlData sqlData = null;//未找到设置为null
if (data.has(DataColumns.ID)) //根据数据块 ID 在 mDataList 中查找对应的 SqlData 对象
{
long dataId = data.getLong(DataColumns.ID);//赋值
for (SqlData temp : mDataList) {
if (dataId == temp.getId()) {
sqlData = temp;
}
}
}
if (sqlData == null) {
sqlData = new SqlData(mContext);
mDataList.add(sqlData);//没找到对像,则新建一个对象并添加到 mDataList 中
}
sqlData.setContent(data);
}
}
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
return false;
}//当 JSON 解析出错时,将会抛出 JSONException 异常并被 catch 住
return true;
}
public JSONObject getContent()
//将 SqlData 对象转换为 JSONObject
{
try {
JSONObject js = new JSONObject();
//判断 SqlData 对象是否已经存入数据库中
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
//未存储,返回 null
}
JSONObject note = new JSONObject();
if (mType == Notes.TYPE_NOTE) {
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.ALERTED_DATE, mAlertDate);
note.put(NoteColumns.BG_COLOR_ID, mBgColorId);
note.put(NoteColumns.CREATED_DATE, mCreatedDate);
note.put(NoteColumns.HAS_ATTACHMENT, mHasAttachment);
note.put(NoteColumns.MODIFIED_DATE, mModifiedDate);
note.put(NoteColumns.PARENT_ID, mParentId);
note.put(NoteColumns.SNIPPET, mSnippet);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.WIDGET_ID, mWidgetId);
note.put(NoteColumns.WIDGET_TYPE, mWidgetType);
note.put(NoteColumns.ORIGIN_PARENT_ID, mOriginParent);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
JSONArray dataArray = new JSONArray();
for (SqlData sqlData : mDataList) {
JSONObject data = sqlData.getContent();
if (data != null) {
dataArray.put(data);
}
}//根据 SqlData 对象的类型不同,分别构造 Note 和 Data 两个 JSONObject
// 并放入 META_HEAD_NOTE 和 META_HEAD_DATA 字段中
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
} else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.SNIPPET, mSnippet);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
}
return js;//将其内容转换为 JSONObject 对象并返回
} catch (JSONException e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
return null;//遇到错误会打印日志并返回 null
}
public void setParentId(long id)
//设置 SqlData 对象的父节点 ID
{
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
public void setSyncId(long syncId) {
mDiffNoteValues.put(NoteColumns.SYNC_ID, syncId);
}
public void resetLocalModified() {
mDiffNoteValues.put(NoteColumns.LOCAL_MODIFIED, 0);
}
public long getId() {
return mId;
}
public long getParentId() {
return mParentId;
}
public String getSnippet() {
return mSnippet;
}
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}
public void commit(boolean validateVersion)
//将 SqlData 对象中的属性变化保存到数据库中
{
if (mIsCreate)
//判断该对象是新创建的还是已经存在于数据库中
{
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
mDiffNoteValues.remove(NoteColumns.ID);
}
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);
//新建的对象,则调用 insert 方法将其保存到数据库中
try {
mId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");
}
if (mId == 0) {
throw new IllegalStateException("Create thread id failed");
}//对是否为新值进行判定
if (mType == Notes.TYPE_NOTE) {
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, false, -1);
//validateVersion 参数指定为 falsemVersion 参数指定为 -1
}
}
} else {
if (mId <= 0 && mId != Notes.ID_ROOT_FOLDER && mId != Notes.ID_CALL_RECORD_FOLDER) {
Log.e(TAG, "No such note");
throw new IllegalStateException("Try to update note with invalid id");
}
//判断当前对象的 ID 是否合法,如果不合法则抛出异常
if (mDiffNoteValues.size() > 0) {
mVersion ++;
int result = 0;
if (!validateVersion) {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?)", new String[] {
String.valueOf(mId)
});
} else {
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?) AND (" + NoteColumns.VERSION + "<=?)",
new String[] {
String.valueOf(mId), String.valueOf(mVersion)
});
}
if (result == 0) {
Log.w(TAG, "there is no update. maybe user updates note when syncing");
}
}//判断笔记是否被成功更新,并在更新失败时输出一些日志信息。
if (mType == Notes.TYPE_NOTE)//检查当前对象是否表示笔记对象
{
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, validateVersion, mVersion);//对比参数,不对校验版本号
}
}
}
// refresh local info
loadFromCursor(mId);//逐一转换为 SqlData 对象,并添加到 mDataList 变量中
if (mType == Notes.TYPE_NOTE)//加载笔记内容
loadDataContent();
mDiffNoteValues.clear();//清空 mDiffNoteValues 变量
mIsCreate = false;//标记设置为 false表示当前对象已经存在于数据库中
}
}