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.
git-xiaomibianqian/lhy/SqlNote.java

506 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 {//调用getSimpleName ()函数得到类的简写名称存入字符串TAG中
private static final String TAG = SqlNote.class.getSimpleName();
private static final int INVALID_ID = -99999;//将INVALID_ID 初始化为-99999
public static final String[] PROJECTION_NOTE = new String[] {//集合了interface NoteColumns中所有17个SF常量
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
};//以下设置17个列的编号
public static final int ID_COLUMN = 0;//提醒时间
public static final int ALERTED_DATE_COLUMN = 1;//note的背景颜色
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;//以下定义了17个内部变量其中12个可以由content获得5个需要初始化为0或者new
private ContentResolver mContentResolver;
private boolean mIsCreate;
private long mId;//通过ArrayList记录note中的data
private long mAlertDate;
private int mBgColorId;
private long mCreatedDate;
private int mHasAttachment;
private long mModifiedDate;
private long mParentId;
private String mSnippet;
private int mType;
private int mWidgetId;
private int mWidgetType;
private long mOriginParent;
private long mVersion;
private ContentValues mDiffNoteValues;
private ArrayList<SqlData> mDataList;
public SqlNote(Context context) {//构造函数参数只有context初始化新建的对象中的所有变量
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = true;
mId = INVALID_ID;//无效用户
mAlertDate = 0;
mBgColorId = ResourceParser.getDefaultBgId(context);//系统默认背景
mCreatedDate = System.currentTimeMillis();
mHasAttachment = 0;//调用系统函数获得创建时间
mModifiedDate = System.currentTimeMillis();
mParentId = 0;
mSnippet = "";
mType = Notes.TYPE_NOTE;
mWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
mOriginParent = 0;
mVersion = 0;
mDiffNoteValues = new ContentValues();
mDataList = new ArrayList<SqlData>();//新建一个data的列表
}
public SqlNote(Context context, Cursor c) {//构造函数参数有context和cursor对cursor指向的对象进行初始化
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(c);
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)//如果是note类型则调用下面的 loadDataContent()函数,加载数据内容
loadDataContent();
mDiffNoteValues = new ContentValues();
}
public SqlNote(Context context, long id) {//第三种构造方式采用context和id
mContext = context;
mContentResolver = context.getContentResolver();
mIsCreate = false;
loadFromCursor(id);//调用下面的 loadFromCursor函数通过ID从光标处加载数据
mDataList = new ArrayList<SqlData>();
if (mType == Notes.TYPE_NOTE)
loadDataContent();
mDiffNoteValues = new ContentValues();
}
private void loadFromCursor(long id) {//通过id从光标处加载数据
Cursor c = null;
try {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",//通过id获取ContentResolver中的相应内容并赋给cursor
new String[] {
String.valueOf(id)
}, null);//如果获取成功则cursor移动到下一条记录并加载该记录
if (c != null) {
c.moveToNext();
loadFromCursor(c);
} else {
Log.w(TAG, "loadFromCursor: cursor = null");
}
} finally {
if (c != null)
c.close();
}
}
private void loadFromCursor(Cursor c) {//通过游标从光标处加载数据
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);
mCreatedDate = c.getLong(CREATED_DATE_COLUMN);
mHasAttachment = c.getInt(HAS_ATTACHMENT_COLUMN);
mModifiedDate = c.getLong(MODIFIED_DATE_COLUMN);
mParentId = c.getLong(PARENT_ID_COLUMN);
mSnippet = c.getString(SNIPPET_COLUMN);
mType = c.getInt(TYPE_COLUMN);
mWidgetId = c.getInt(WIDGET_ID_COLUMN);
mWidgetType = c.getInt(WIDGET_TYPE_COLUMN);
mVersion = c.getLong(VERSION_COLUMN);
}
//获取ID对应content内容如果查询到该note的id确实有对应项即cursor有对应获取ID对应content内容
private void loadDataContent() {//通过content机制获取共享数据并加载到数据库当前游标处
Cursor c = null;
mDataList.clear();
try {//获取ID对应content内容
c = mContentResolver.query(Notes.CONTENT_DATA_URI, SqlData.PROJECTION_DATA,//获得该ID对应的数据内容
"(note_id=?)", new String[] {
String.valueOf(mId)
}, null);//查询到该note的id确实有对应项即cursor有对应
if (c != null) {
if (c.getCount() == 0) {
Log.w(TAG, "it seems that the note has not data");
return;
}
while (c.moveToNext()) {//记录数量不为0则循环直到记录不存在不断地取出记录放到DataList中
SqlData data = new SqlData(mContext, c);
mDataList.add(data);
}
} else {
Log.w(TAG, "loadDataContent: cursor = null");
}
} finally {//论如何,最后需要关闭数据库游标
if (c != null)
c.close();
}
}
public boolean setContent(JSONObject js) {//设置通过content机制共享的数据信息
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//语句如果共享数据存在摘要则将其赋给snippet变量否则该变量为空
.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)//以下操作都和上面对snippet的操作一样一起根据共享的数据设置SqlNote内容的上述17项
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {//如果是新建的或 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) {//如果只是通过上下文对note进行数据库操作或者该背景颜色与原背景颜色不相同
mDiffNoteValues.put(NoteColumns.BG_COLOR_ID, bgColorId);
}
mBgColorId = bgColorId;
long createDate = note.has(NoteColumns.CREATED_DATE) ? note//对创建日期操作
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate != createDate) {//如果只是通过上下文对note进行数据库操作或者该创建日期与原创建日期不相同
mDiffNoteValues.put(NoteColumns.CREATED_DATE, createDate);//将该创建日期保存在mDiffNoteValue这个变量中说明这两个值不相同
}
mCreatedDate = createDate;//将该创建日期覆盖原创建日期
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment != hasAttachment) {//如果只是通过上下文对note进行数据库操作或者该有无附件的布尔值与原有无附件的布尔值不相同
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) {//如果只是通过上下文对note进行数据库操作或者该修改日期与原修改日期不相同
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)) {//如果只是通过上下文对note进行数据库操作或者该文本片段与原文本片段不相同
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);//将该小部件ID保存在mDiffNoteValue这个变量中说明这两个值不相同
}
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) {//如果只是通过上下文对note进行数据库操作或者该原始父文件夹ID与原原始父文件夹ID不相同
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;
if (data.has(DataColumns.ID)) {//该数据ID对应的数据如果存在将对应的数据存在数据库中
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);
}
sqlData.setContent(data);//最后为数据库数据进行设置
}
}
} catch (JSONException e) {//出现JSONException时日志显示错误同时打印堆栈轨迹
Log.e(TAG, e.toString());//获取异常类型和异常详细消息
e.printStackTrace();
return false;
}
return true;
}
//获取content机制提供的数据并加载到note中
public JSONObject getContent() {//获取content机制提供的数据并加载到note中
try {
JSONObject js = new JSONObject();
if (mIsCreate) {
Log.e(TAG, "it seems that we haven't created this in database yet");
return null;
}
JSONObject note = new JSONObject();//新建变量note用于传输共享数据
if (mType == Notes.TYPE_NOTE) {//note类型
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.ALERTED_DATE, mAlertDate);
note.put(NoteColumns.BG_COLOR_ID, mBgColorId);//背景颜色ID
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) {//将note中的data全部存入JSONArray中
JSONObject data = sqlData.getContent();
if (data != null) {
dataArray.put(data);//再将这个JSONArray对应共享数据mata按键值对存入共享
}
}
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);//将元数据存入数组中
} else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {//类型为系统文件或目录文件时
note.put(NoteColumns.ID, mId);//将id类型以及摘要存入jsonobject,然后对应META_HEAD_NOTE键存入共享
note.put(NoteColumns.TYPE, mType);
note.put(NoteColumns.SNIPPET, mSnippet);
js.put(GTaskStringUtils.META_HEAD_NOTE, note);//并存入元便签中
}
return js;
} catch (JSONException e) {//如果出现异常,则报错
Log.e(TAG, e.toString());
e.printStackTrace();
}
return null;
}
public void setParentId(long id) {
mParentId = id;
mDiffNoteValues.put(NoteColumns.PARENT_ID, id);
}
//设置当前ID的gtask的ID
public void setGtaskId(String gid) {
mDiffNoteValues.put(NoteColumns.GTASK_ID, gid);
}
//同步id
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;
}//获得当前id
public long getParentId() {
return mParentId;
}//获得当前id的父id
public String getSnippet() {
return mSnippet;
}//获取小片段即用于显示的部分便签内容
public boolean isNoteType() {
return mType == Notes.TYPE_NOTE;
}//判断是否为便签类型
//将修改之后的数据上传
public void commit(boolean validateVersion) {
if (mIsCreate) {
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
mDiffNoteValues.remove(NoteColumns.ID);//那么就把这个ID移出便签列
}
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);//插入该便签的uri
try {
mId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {//捕获异常转换出错显示错误“获取note的id出现错误”
Log.e(TAG, "Get note id error :" + e.toString());
throw new ActionFailureException("create note failed");//抛出异常,创建 note 失败
}
if (mId == 0) {
throw new IllegalStateException("Create thread id failed");
}
if (mType == Notes.TYPE_NOTE) {//对于note类型引用sqlData.commit方法操作
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, false, -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 更新 note
}
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) {//对note类型还是对其中的data引用commit从而实现目的
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, validateVersion, mVersion);
}
}
}
// refresh local info//更新本地信息
loadFromCursor(mId);
if (mType == Notes.TYPE_NOTE)//如果是便签类型:
loadDataContent();//获取共享数据并加载到数据库
mDiffNoteValues.clear();//清空,回到初始化状态
mIsCreate = false;
}//改变数据库构造模式
}