代码分析

master
ptka4xvyr 2 years ago
parent 8bc9311fa6
commit ec1f11abe2

@ -1,54 +1,38 @@
/*
* 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.tool;
import android.content.Context;
import android.database.Cursor;
import android.os.Environment;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;
//定义小米便签类:功能类
import android.content.Context;//导入小米便签需要的各项函数
import android.database.Cursor;//android查询数据库类
import android.os.Environment;//安卓操作系统环境包
import android.text.TextUtils;//导入安卓文本功能包
import android.text.format.DateFormat;//用于转化日期格式
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.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.DataColumns;// 数据类型类
import net.micode.notes.data.Notes.DataConstants;//常数类
import net.micode.notes.data.Notes.NoteColumns;//便签类
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileNotFoundException;//文件未找到的错误处理
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.IOException;//操作错误处理
import java.io.PrintStream;
public class BackupUtils {
private static final String TAG = "BackupUtils";
// Singleton stuff
private static BackupUtils sInstance; //类里面为什么可以定义自身类的对象?
private static BackupUtils sInstance; // 类里面为什么可以定义自身类的对象?
public static synchronized BackupUtils getInstance(Context context) {
//ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程例如线程A
//运行到这个方法时,都要检查有没有其它线程B或者C、 D等正在用这个方法(或者该类的其他同步方法)有的话要等正在使用synchronized方法的线程B或者C 、D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
//它包括两种用法synchronized 方法和 synchronized 块。
// ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程例如线程A
// 运行到这个方法时,都要检查有没有其它线程B或者C、
// D等正在用这个方法(或者该类的其他同步方法)有的话要等正在使用synchronized方法的线程B或者C
// 、D运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。
// 它包括两种用法synchronized 方法和 synchronized 块。
if (sInstance == null) {
//如果当前备份不存在,则新声明一个
// 如果当前备份不存在,则新声明一个
sInstance = new BackupUtils(context);
}
return sInstance;
@ -59,86 +43,94 @@ public class BackupUtils {
* status
*/
// Currently, the sdcard is not mounted SD卡没有被装入手机
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist 备份文件夹不存在
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs 数据已被破坏,可能被修改
public static final int STATE_DATA_DESTROIED = 2;
// Some run-time exception which causes restore or backup fails 超时异常
public static final int STATE_SYSTEM_ERROR = 3;
// Backup or restore success 成功存储
public static final int STATE_SUCCESS = 4;
public static final int STATE_SD_CARD_UNMOUONTED = 0;
// The backup file not exist 备份文件夹不存在
public static final int STATE_BACKUP_FILE_NOT_EXIST = 1;
// The data is not well formated, may be changed by other programs 数据已被破坏,可能被修改
public static final int STATE_DATA_DESTROIED = 2;
// Some run-time exception which causes restore or backup fails 超时异常
public static final int STATE_SYSTEM_ERROR = 3;
// Backup or restore success 成功存储
public static final int STATE_SUCCESS = 4;
private TextExport mTextExport;
private BackupUtils(Context context) { //初始化函数
private BackupUtils(Context context) { // 初始化函数
mTextExport = new TextExport(context);
}
private static boolean externalStorageAvailable() { //外部存储功能是否可用
private static boolean externalStorageAvailable() { // 外部存储功能是否可用
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
public int exportToText() {
// 输出至文本
return mTextExport.exportToText();
}
public String getExportedTextFileName() {
// 返回文件名
return mTextExport.mFileName;
}
public String getExportedTextFileDir() {
// 返回文件的路径
return mTextExport.mFileDirectory;
}
private static class TextExport {
// 内部类文本输出定义笔记ID、修改日期等笔记、内容、日期、电话号码的数据和格式等常量
private static final String[] NOTE_PROJECTION = {
// 定义了一个数组储存便签的信息
NoteColumns.ID,
NoteColumns.MODIFIED_DATE,
NoteColumns.SNIPPET,
NoteColumns.TYPE
};
// 标识设定笔记ID标识为0笔记的修改日期标识为1笔记的数据标识为2.
private static final int NOTE_COLUMN_ID = 0;
// 定义了一个数组储存的是数据的信息
private static final int NOTE_COLUMN_MODIFIED_DATE = 1;
// 定义了一个数组储存的是数据的信息
private static final int NOTE_COLUMN_SNIPPET = 2;
// 初始化上述一些参数
private static final String[] DATA_PROJECTION = {
// 数据在数据库中的信息
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
DataColumns.MIME_TYPE, // 变量:该资源的媒体类型,决定怎么用这个资源
DataColumns.DATA1,
DataColumns.DATA2,
DataColumns.DATA3,
DataColumns.DATA4,
};
// 标识设定数据内容标识为0媒体类型标识为1访问日期标识为2电话号码标识为4
private static final int DATA_COLUMN_CONTENT = 0;
private static final int DATA_COLUMN_MIME_TYPE = 1;
// 数据媒体类型标识为1
private static final int DATA_COLUMN_CALL_DATE = 2;
// 日期标识为2
private static final int DATA_COLUMN_PHONE_NUMBER = 4;
private final String [] TEXT_FORMAT;
private static final int FORMAT_FOLDER_NAME = 0;
private static final int FORMAT_NOTE_DATE = 1;
private static final int FORMAT_NOTE_CONTENT = 2;
// 初始化上述一些参数
private final String[] TEXT_FORMAT;// 文档格式标识:名称=>0;日期=>1;内容=>2
private static final int FORMAT_FOLDER_NAME = 0;
private static final int FORMAT_NOTE_DATE = 1;// 便签内容数据格式
private static final int FORMAT_NOTE_CONTENT = 2;
private Context mContext;
private String mFileName;
private String mFileDirectory;
private String mFileName;// 文件名
private String mFileDirectory;// 文件路径
public TextExport(Context context) {
// 从context类实例中获取信息给对应的属性赋初始值
TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note);
// 根据文件定义的地址处获取文件格式的数组
mContext = context;
mFileName = ""; //为什么为空?
mFileName = ""; // 为什么为空?
mFileDirectory = "";
}
private String getFormat(int id) { //获取文本的组成部分
private String getFormat(int id) { // 获取文本的组成部分
return TEXT_FORMAT[id];
}
@ -146,22 +138,25 @@ public class BackupUtils {
* Export the folder identified by folder id to text
*/
private void exportFolderToText(String folderId, PrintStream ps) {
// Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note
// Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note
Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] {
folderId
}, null);
if (notesCursor != null) {
// ps里面保存有这份note的日期
if (notesCursor.moveToFirst()) {
do {
// Print note's last modified date ps里面保存有这份note的日期
// Print note's last modified date ps里面保存有这份note的日期
// 函数:打印最后修改日期
ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
mContext.getString(R.string.format_datetime_mdhm),
notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
// Query data belong to this note
String noteId = notesCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps); //将文件导出到text
// 代码块通过将便签内容打印到屏幕上检查是不是这个note的数据
exportNoteToText(noteId, ps); // 将文件导出到text
} while (notesCursor.moveToNext());
}
notesCursor.close();
@ -172,35 +167,41 @@ public class BackupUtils {
* Export note identified by id to a print stream
*/
private void exportNoteToText(String noteId, PrintStream ps) {
// 函数:将便签的内容以文本的形式显示在屏幕上。比如电话号码、打电话的日期等。
Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI,
// 利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] {
noteId
}, null);
if (dataCursor != null) { //利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
if (dataCursor != null) { // 利用光标来扫描内容区别为callnote和note两种靠ps.printline输出
if (dataCursor.moveToFirst()) {
do {
do {// 位置
String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE);
if (DataConstants.CALL_NOTE.equals(mimeType)) {
// Print phone number
// 语句:判断便签的内容,如果是电话记录,那么在这一个代码块内打印
String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER);
long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE);
String location = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(phoneNumber)) { //判断是否为空字符
if (!TextUtils.isEmpty(phoneNumber)) { // 判断是否为空字符
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
phoneNumber));
phoneNumber));// 输出电话号码phoneNumber
}
// Print call date
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat
// 输出calldate
.format(mContext.getString(R.string.format_datetime_mdhm),
callDate)));
// Print call attachment location
if (!TextUtils.isEmpty(location)) {
// 输出位置location
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
location));
}
} else if (DataConstants.NOTE.equals(mimeType)) {
// print a line separator between note
String content = dataCursor.getString(DATA_COLUMN_CONTENT);
if (!TextUtils.isEmpty(content)) {
ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT),
@ -213,18 +214,18 @@ public class BackupUtils {
}
// print a line separator between note
try {
ps.write(new byte[] {
ps.write(new byte[] { // 语句块在note下面输出一条线
Character.LINE_SEPARATOR, Character.LETTER_NUMBER
});
} catch (IOException e) {
Log.e(TAG, e.toString());
Log.e(TAG, e.toString());// 捕获错误信息并记录异常日志
}
}
/**
* Note will be exported as text which is user readable
*/
public int exportToText() { //总函数调用上面的exportFolder和exportNote
public int exportToText() { // 总函数调用上面的exportFolder和exportNote
if (!externalStorageAvailable()) {
Log.d(TAG, "Media was not mounted");
return STATE_SD_CARD_UNMOUONTED;
@ -235,20 +236,21 @@ public class BackupUtils {
Log.e(TAG, "get print stream error");
return STATE_SYSTEM_ERROR;
}
// First export folder and its notes 导出文件夹,就是导出里面包含的便签
// First export folder and its notes 导出文件夹,就是导出里面包含的便签
Cursor folderCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
"(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
+ NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
+ NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER,
null, null);
if (folderCursor != null) {
if (folderCursor.moveToFirst()) {
do {
// Print folder's name
String folderName = "";
if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
if (folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
folderName = mContext.getString(R.string.call_record_folder_name);
} else {
folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
@ -263,12 +265,13 @@ public class BackupUtils {
folderCursor.close();
}
// Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出)
// Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出)
Cursor noteCursor = mContext.getContentResolver().query(
Notes.CONTENT_NOTE_URI,
NOTE_PROJECTION,
NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ "=0", null, null);
+ "=0",
null, null);
if (noteCursor != null) {
if (noteCursor.moveToFirst()) {
@ -279,7 +282,7 @@ public class BackupUtils {
// Query data belong to this note
String noteId = noteCursor.getString(NOTE_COLUMN_ID);
exportNoteToText(noteId, ps);
} while (noteCursor.moveToNext());
} while (noteCursor.moveToNext());// 文件夹的光标下移
}
noteCursor.close();
}
@ -292,10 +295,13 @@ public class BackupUtils {
* Get a print stream pointed to the file {@generateExportedTextFile}
*/
private PrintStream getExportToTextPrintStream() {
// 获取指向文件的打印流
File file = generateFileMountedOnSDcard(mContext, R.string.file_path,
// .在预先的目录里创建文件
R.string.file_name_txt_format);
if (file == null) {
Log.e(TAG, "create file to exported failed");
//记录异常日志
return null;
}
mFileName = file.getName();
@ -303,7 +309,7 @@ public class BackupUtils {
PrintStream ps = null;
try {
FileOutputStream fos = new FileOutputStream(file);
ps = new PrintStream(fos); //将ps输出流输出到特定的文件目的就是导出到文件而不是直接输出
ps = new PrintStream(fos); // 将ps输出流输出到特定的文件目的就是导出到文件而不是直接输出
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
@ -320,16 +326,16 @@ public class BackupUtils {
*/
private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) {
StringBuilder sb = new StringBuilder();
sb.append(Environment.getExternalStorageDirectory()); //外部SD卡的存储路径
sb.append(context.getString(filePathResId)); //文件的存储路径
File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息
sb.append(Environment.getExternalStorageDirectory()); // 外部SD卡的存储路径
sb.append(context.getString(filePathResId)); // 文件的存储路径
File filedir = new File(sb.toString()); // filedir应该就是用来存储路径信息
sb.append(context.getString(
fileNameFormatResId,
DateFormat.format(context.getString(R.string.format_date_ymd),
System.currentTimeMillis())));
File file = new File(sb.toString());
try { //如果这些文件不存在,则新建
try { // 如果这些文件不存在,则新建
if (!filedir.exists()) {
filedir.mkdir();
}
@ -342,9 +348,7 @@ public class BackupUtils {
} catch (IOException e) {
e.printStackTrace();
}
// try catch 异常处理
// try catch 异常处理
return null;
}
}

@ -16,8 +16,11 @@
package net.micode.notes.tool;
//使用的包
import android.content.ContentProviderOperation;
// 导入相关的库
import android.content.ContentProviderResult;
//批量删除笔记
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@ -29,18 +32,21 @@ import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.NoteColumns;
//便签栏的数据
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
import java.util.ArrayList;
import java.util.HashSet;
public class DataUtils {
// 数据的集成工具类
public static final String TAG = "DataUtils";
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) { //直接删除多个笔记
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) { // 直接删除多个笔记
// 这是一个处理批量删除便签的方法
if (ids == null) {
Log.d(TAG, "the ids is null");
// Android Logcat使用起来可以方便的观察调试内容
return true;
}
if (ids.size() == 0) {
@ -48,26 +54,29 @@ public class DataUtils {
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); //提供一个任务列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); // 提供一个任务列表
for (long id : ids) {
if(id == Notes.ID_ROOT_FOLDER) {
if (id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root");
continue;
} //如果发现是根文件夹,则不删除
} // 如果发现是根文件夹,则不删除
ContentProviderOperation.Builder builder = ContentProviderOperation
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //用newDelete实现删除功能
operationList.add(builder.build()); //
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); // 用newDelete实现删除功能
operationList.add(builder.build()); //
}
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);//主机名或叫Authority用于唯一标识这个ContentProvider外部调用者可以根据这个标识来找到它。
//数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);// 主机名或叫Authority用于唯一标识这个ContentProvider外部调用者可以根据这个标识来找到它。
// 数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
// 检测当前要删除的便签是否是根目录,如果是根目录,,返回异常信息
return false;
}
return true;
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
// 函数String.format(Locale locale, String format, Object… args)
// 使用指定的语言环境,制定字符串格式和参数生成格式化的字符串。
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
@ -75,37 +84,46 @@ public class DataUtils {
}
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
ContentValues values = new ContentValues();
// 将笔记移动至文件夹
ContentValues values = new ContentValues();// 将PARENT_ID更改为目标目录ID
values.put(NoteColumns.PARENT_ID, desFolderId);
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
values.put(NoteColumns.LOCAL_MODIFIED, 1);
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新然后用update实现
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); // 对需要移动的便签进行数据更新然后用update实现
}
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) {
// 批量移动
long folderId) {
// ID为空的情况
if (ids == null) {
Log.d(TAG, "the ids is null");
// ID为空的情况
return true;
}
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) {
// 为uri加上id
ContentProviderOperation.Builder builder = ContentProviderOperation
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); //通过withAppendedId方法为该Uri加上ID
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); // 通过withAppendedId方法为该Uri加上ID
builder.withValue(NoteColumns.PARENT_ID, folderId);
// 代码块以下两句话和上面一个方法类似就是修改便签的父节点id为新的文件夹的id然后更改修改标志
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
// 更改状态置为1
operationList.add(builder.build());
}//将ids里包含的每一列的数据逐次加入到operationList中等待最后的批量处理
} // 将ids里包含的每一列的数据逐次加入到operationList中等待最后的批量处理
try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //applyBatch一次性处理一个操作列表
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); // applyBatch一次性处理一个操作列表
// 调用applybatch一次性处理一个操作列表
if (results == null || results.length == 0 || results[0] == null) {
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
return false;
}
return true;
} catch (RemoteException e) {
// . 确定格式
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
@ -117,16 +135,18 @@ public class DataUtils {
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
*/
public static int getUserFolderCount(ContentResolver resolver) {
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI,
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { "COUNT(*)" },
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
null); //筛选条件源文件不为trash folder
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) },
null); // 筛选条件源文件不为trash folder
int count = 0;
if(cursor != null) {
if(cursor.moveToFirst()) {
if (cursor != null) {
// 语句块:尝试得到用户文件夹的数量
if (cursor.moveToFirst()) {
try {
// .异常处理
count = cursor.getInt(0);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "get folder count failed:" + e.toString());
@ -139,15 +159,16 @@ public class DataUtils {
}
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), //通过withAppendedId方法为该Uri加上ID
// 在数据库中是否可见
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), // 通过withAppendedId方法为该Uri加上ID
null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
new String [] {String.valueOf(type)},
null); //查询条件type符合且不属于垃圾文件夹
new String[] { String.valueOf(type) },
null); // 查询条件type符合且不属于垃圾文件夹
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {//用getcount函数判断cursor是否为空
if (cursor.getCount() > 0) {// 用getcount函数判断cursor是否为空
exist = true;
}
cursor.close();
@ -156,6 +177,7 @@ public class DataUtils {
}
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
// 判断该note是否在数据库中存在
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
@ -170,12 +192,14 @@ public class DataUtils {
}
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
// 检查文件名字是否可见
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
// 通过URI与dataId在数据库中查找数据
boolean exist = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
// 调用对应的uri的数据值进行查询
exist = true;
}
cursor.close();
@ -184,15 +208,17 @@ public class DataUtils {
}
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
// 函数:通过名字查询文件是否存在
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
// 语句:筛选类型正确的、未被删除的和名字对应得上的
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
//通过名字查询文件是否存在
// 通过名字查询文件是否存在
boolean exist = false;
if(cursor != null) {
if(cursor.getCount() > 0) {
if (cursor != null) {
if (cursor.getCount() > 0) {
exist = true;
}
cursor.close();
@ -201,26 +227,28 @@ public class DataUtils {
}
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
// 使用hashset来存储不同窗口的id和type并且建立对应关系
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?",
new String[] { String.valueOf(folderId) },
null); //查询条件父ID是传入的folderId;
null); // 查询条件父ID是传入的folderId;
HashSet<AppWidgetAttribute> set = null;
if (c != null) {
// 语句块将app窗口的属性加入到HashSet中
if (c.moveToFirst()) {
set = new HashSet<AppWidgetAttribute>();
do {
try {
AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0); //0对应的NoteColumns.WIDGET_ID
widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE
widget.widgetId = c.getInt(0); // 0对应的NoteColumns.WIDGET_ID
widget.widgetType = c.getInt(1); // 1对应的NoteColumns.WIDGET_TYPE
set.add(widget);
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, e.toString());
}
} while (c.moveToNext()); //查询下一条
} while (c.moveToNext()); // 查询下一条
}
c.close();
}
@ -228,13 +256,15 @@ public class DataUtils {
}
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
// 通过笔记ID获取号码
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER },
new String[] { CallNote.PHONE_NUMBER },
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null);
new String[] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null);// 新建字符列表
if (cursor != null && cursor.moveToFirst()) {
// 语句块: 获取电话号码,并处理异常。
try {
return cursor.getString(0);
} catch (IndexOutOfBoundsException e) {
@ -247,18 +277,19 @@ public class DataUtils {
}
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
// 同样的通过映射关系通过号码和日期获取ID
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID },
new String[] { CallNote.NOTE_ID },
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
+ CallNote.PHONE_NUMBER + ",?)",
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
new String[] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null);
//通过数据库操作查询条件是callDate和phoneNumber匹配传入参数的值
// 通过数据库操作查询条件是callDate和phoneNumber匹配传入参数的值
if (cursor != null) {
if (cursor.moveToFirst()) {
try {
return cursor.getLong(0); //0对应的CallNote.NOTE_ID
return cursor.getLong(0); // 0对应的CallNote.NOTE_ID
} catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call note id fails " + e.toString());
}
@ -269,11 +300,12 @@ public class DataUtils {
}
public static String getSnippetById(ContentResolver resolver, long noteId) {
// 按ID获取片段
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET },
new String[] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?",
new String [] { String.valueOf(noteId)},
null);//查询条件noteId
new String[] { String.valueOf(noteId) },
null);// 查询条件noteId
if (cursor != null) {
String snippet = "";
@ -284,8 +316,11 @@ public class DataUtils {
return snippet;
}
throw new IllegalArgumentException("Note is not found with id: " + noteId);
//1. IllegalArgumentException是非法传参异常也就是参数传的类型冲突属于RunTimeException运行时异常
}
public static String getFormattedSnippet(String snippet) { //对字符串进行格式处理,将字符串两头的空格去掉,同时将换行符去掉
public static String getFormattedSnippet(String snippet) { // 对字符串进行格式处理,将字符串两头的空格去掉,同时将换行符去掉
// 按ID获取片段
if (snippet != null) {
snippet = snippet.trim();
int index = snippet.indexOf('\n');
@ -296,4 +331,4 @@ public class DataUtils {
return snippet;
}
}
}

@ -17,38 +17,11 @@
package net.micode.notes.gtask.remote;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.app.Service;
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;
import android.content.Intent;
import android.os.Bundle;
import android.os.IBinder;
public class GTaskManager {
private static final String TAG = GTaskManager.class.getSimpleName();
public static final int STATE_SUCCESS = 0;
@ -767,7 +740,7 @@ public class GTaskManager {
// update remotely
node.setContentByLocalJSON(sqlNote.getContent());
GTaskClient.getInstance().addUpdateNode(node); //GTaskClient用途为从本地登陆远端服务器
GTaskClient.getInstance().addUpdateNode(node); //GTaskClient用途为从本地登陆远端服务器
// update meta
updateRemoteMeta(node.getGid(), sqlNote);

@ -1,53 +1,36 @@
/*
* 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.tool;
//简介定义了很多的静态字符串目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,这是非常好的编程规范
package net.micode.notes.tool;
//这个类就是定义了一堆static string实际就是为jsonObject提供Key把这些定义全部写到一个类里方便查看管理是一个非常好的编程习惯
public class GTaskStringUtils {
public final static String GTASK_JSON_ACTION_ID = "action_id";
public final static String GTASK_JSON_ACTION_ID = "action_id";// 行动ID
public final static String GTASK_JSON_ACTION_LIST = "action_list";
public final static String GTASK_JSON_ACTION_LIST = "action_list";// 任务列表
public final static String GTASK_JSON_ACTION_TYPE = "action_type";
public final static String GTASK_JSON_ACTION_TYPE = "action_type";// 任务类型
public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create";
public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create";// 新建
public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all";
public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move";
public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move";// 移动
public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update";
public final static String GTASK_JSON_CREATOR_ID = "creator_id";
public final static String GTASK_JSON_CHILD_ENTITY = "child_entity";
public final static String GTASK_JSON_CHILD_ENTITY = "child_entity";// 95.子实体
public final static String GTASK_JSON_CLIENT_VERSION = "client_version";
public final static String GTASK_JSON_CLIENT_VERSION = "client_version";// 客户端
public final static String GTASK_JSON_COMPLETED = "completed";
public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id";
public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id";// 当前列表位置
public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id";
public final static String GTASK_JSON_DELETED = "deleted";
public final static String GTASK_JSON_DELETED = "deleted";// 删除
public final static String GTASK_JSON_DEST_LIST = "dest_list";
@ -63,7 +46,7 @@ public class GTaskStringUtils {
public final static String GTASK_JSON_ID = "id";
public final static String GTASK_JSON_INDEX = "index";
public final static String GTASK_JSON_INDEX = "index";// 索引
public final static String GTASK_JSON_LAST_MODIFIED = "last_modified";
@ -109,8 +92,8 @@ public class GTaskStringUtils {
public final static String META_HEAD_NOTE = "meta_note";
public final static String META_HEAD_DATA = "meta_data";
public final static String META_HEAD_DATA = "meta_data";// 数据
public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE";
}
}

@ -15,30 +15,32 @@
*/
package net.micode.notes.model;
import android.content.ContentProviderOperation;//批量的更新、插入、删除数据。
import android.content.ContentProviderResult;//操作的结果
import android.content.ContentUris;//用于添加和获取Uri后面的ID
import android.content.ContentValues;//一种用来存储基本数据类型数据的存储机制
import android.content.Context;//需要用该类来弄清楚调用者的实例
import android.content.OperationApplicationException;//操作应用程序容错
import android.net.Uri;//表示待操作的数据
import android.os.RemoteException;//远程容错
import android.util.Log;//输出日志,比如说出错、警告等
import android.content.ContentProviderOperation;//更新、插入、删除数据
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;//存储基本数据类型数据
import android.content.Context;
import android.content.OperationApplicationException;//操作数据容错
import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataColumns;//小米便签数据处理操作(数据栏)
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.data.Notes.TextNote;//小米便签数据处理操作(文本操作)
import java.util.ArrayList;
public class Note {
// private ContentValues mNoteDiffValues;
ContentValues mNoteDiffValues;//
// 这个类是用来刻画单个Note的
// private ContentValues mNoteDiffValues;
ContentValues mNoteDiffValues;
// ContentValues是用于给其他应用调用小米便签的内容的共享数据
private NoteData mNoteData;
private static final String TAG = "Note";
private static final String TAG = "Note";// 软件的名称
/**
* Create a new note id for adding a new note to databases
@ -46,24 +48,32 @@ public class Note {
public static synchronized long getNewNoteId(Context context, long folderId) {
// Create a new note in the database
ContentValues values = new ContentValues();
// Create a new note in the database
long createdTime = System.currentTimeMillis();
// 读取当前系统时间
values.put(NoteColumns.CREATED_DATE, createdTime);
// 将创建时间和修改时间都更改为当前系统时间
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 更改时间
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 便签类型
values.put(NoteColumns.LOCAL_MODIFIED, 1);
values.put(NoteColumns.PARENT_ID, folderId);//将数据写入数据库表格
values.put(NoteColumns.PARENT_ID, folderId);// 将数据写入数据库表格
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
//ContentResolver()主要是实现外部应用对ContentProvider中的数据
//进行添加、删除、修改和查询操作
// ContentResolver()主要是实现外部应用对ContentProvider中的数据
// 进行添加、删除、修改和查询操作
long noteId = 0;
try {
noteId = Long.valueOf(uri.getPathSegments().get(1));
// 获取便签的id
} catch (NumberFormatException e) {
Log.e(TAG, "Get note id error :" + e.toString());
// 获取id错误
noteId = 0;
}//try-catch异常处理
} // try-catch异常处理
if (noteId == -1) {
throw new IllegalStateException("Wrong note id:" + noteId);
// 非法状态时返回出错便签编号
}
return noteId;
}
@ -71,37 +81,37 @@ public class Note {
public Note() {
mNoteDiffValues = new ContentValues();
mNoteData = new NoteData();
}//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容
}// 定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容
public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}//设置数据库表格的标签属性数据
}// 设置数据库表格的标签属性数据
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}//设置数据库表格的标签文本内容的数据
}// 设置数据库表格的标签文本内容的数据
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}//设置文本数据的ID
}// 设置文本数据的ID
public long getTextDataId() {
return mNoteData.mTextDataId;
}//得到文本数据的ID
}// 得到文本数据的ID
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}//设置电话号码数据的ID
}// 设置电话号码数据的ID
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}//得到电话号码数据的ID
}// 得到电话号码数据的ID
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}//判断是否是本地修改
}// 判断是否是本地修改
public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) {
@ -113,8 +123,10 @@ public class Note {
}
/**
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
* In theory, once data changed, the note should be updated on
* {@link NoteColumns#LOCAL_MODIFIED} and
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails,
* we also update the
* note data info
*/
if (context.getContentResolver().update(
@ -124,34 +136,36 @@ public class Note {
// Do not return, fall through
}
mNoteDiffValues.clear();
// 初始化便签特征值
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
// 如果向内容接收者推送上下文失败,则返回错误
return false;
}
return true;
}//判断数据是否同步
}// 判断数据是否同步
private class NoteData {//定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
private class NoteData {// 定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
private long mTextDataId;
private ContentValues mTextDataValues;//文本数据
private ContentValues mTextDataValues;// 文本数据
private long mCallDataId;
private ContentValues mCallDataValues;//电话号码数据
private ContentValues mCallDataValues;// 电话号码数据
private static final String TAG = "NoteData";
public NoteData() {
// 定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
//下面是上述几个函数的具体实现
// 下面是上述几个函数的具体实现
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
@ -163,97 +177,115 @@ public class Note {
mTextDataId = id;
}
void setCallDataId(long id) {
void setCallDataId(long id) {// 设定文本数据id
if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0");
// id保证大于0
}
mCallDataId = id;
}
// 设置电话号码对应的id
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 系统修改时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
// 设置文本数据
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
// 设置修改时间为当前系统时间
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
//下面函数的作用是将新的数据通过Uri的操作存储到数据库
// 下面函数的作用是将新的数据通过Uri的操作存储到数据库
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* Check for safety
*/
if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId);
}//判断数据是否合法
} // 判断数据是否合法
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
ContentProviderOperation.Builder builder = null;//数据库的操作列表
ContentProviderOperation.Builder builder = null;// 数据库的操作列表
if (mTextDataValues.size() > 0) {
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
// 把文本数据存入DataColumns
mTextDataValues.put(DataColumns.NOTE_ID, noteId);// 设定文本数据的属性
if (mTextDataId == 0) {
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
// MIMEMIME(MultipurposeInternet Mail Extensions)多用途互联网邮件扩展类型。
// 是设定某种扩展名的文件用一种应用程序来打开的方式类型,
// 当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。
// 多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
try {// 尝试重新给它设置id
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
// 插入数据失败
mTextDataValues.clear();
// 把电话号码数据存入DataColumns
return null;
}
} else {
} else {// 内容提供者的更新操作因为这个uri对应的数据是已经存在的所以不需要向上面一样新建而是更新即可
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
Notes.CONTENT_DATA_URI, mTextDataId));// 语句: 将uri和id合并后更新
builder.withValues(mTextDataValues);
operationList.add(builder.build());
}
mTextDataValues.clear();
}//把文本数据存入DataColumns
} // 把文本数据存入DataColumns
if (mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataValues.size() > 0) {// 对于电话号码的数据也是和文本数据一样的同步处理
mCallDataValues.put(DataColumns.NOTE_ID, noteId);// 写入noteID
if (mCallDataId == 0) {
// 将电话号码的id设定为uri提供的id
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
try {// 异常处理
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
// 异常处理返回1
} catch (NumberFormatException e) {
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
// 插入电话号码数据失败
mCallDataValues.clear();
return null;
}
} else {
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
// 内容提供者的更新操作这个uri对应的数据是已经存在的因此进行更新即可
builder.withValues(mCallDataValues);
operationList.add(builder.build());
}
mCallDataValues.clear();
}//把电话号码数据存入DataColumns
} // 把电话号码数据存入DataColumns
if (operationList.size() > 0) {
// 存储过程中如果遇到异常,通过如下进行处理
try {
// Android源码中对通讯录的操作应用端使用ContentProvider提供的applyBatch进行批量处理通讯录的联系人入库
ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList);
return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
// 异常日志
return null;
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
}
}//存储过程中的异常处理
} // 存储过程中的异常处理
return null;
}
}
}

@ -1,6 +1,6 @@
/*
* 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
@ -16,14 +16,15 @@
package net.micode.notes.model;
import android.appwidget.AppWidgetManager;
//在model包中
import android.appwidget.AppWidgetManager;//以下下为引用的一些库文件
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.database.Cursor;//游标的使用
import android.text.TextUtils;
import android.util.Log;
import net.micode.notes.data.Notes;
import net.micode.notes.data.Notes;//小米便签操作的整体属性
import net.micode.notes.data.Notes.CallNote;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
@ -31,9 +32,10 @@ import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.Notes.TextNote;
import net.micode.notes.tool.ResourceParser.NoteBgResources;
public class WorkingNote {
// 申明WorkingNote类,创建小米便签的主要类,包括创建空便签,保存便签,加载小米便签内容,和设置小米便签的一些小部件之类的操作
// Note for the working note
// 下列定义了一系列变量用于设置便签的不同属性以及相关功能
private Note mNote;
// Note Id
private long mNoteId;
@ -41,23 +43,31 @@ public class WorkingNote {
private String mContent;
// Note mode
private int mMode;
// 是否是清单模式
private long mAlertDate;
// 设置闹钟时间
private long mModifiedDate;
// 最后修改时间
private int mBgColorId;
// 背景颜色ID
private int mWidgetId;
// 控件ID
private int mWidgetType;
// 控件类型有Notes.TYPE_WIDGET_INVALIDE(-1)、TYPE_WIDGET_2X(0)、TYPE_WIDGET_4X(1)三种
private long mFolderId;
//// 便签文件夹ID
private Context mContext;
// 当前便签的上下文
private static final String TAG = "WorkingNote";
// .声明 DATA_PROJECTION字符串数组
private boolean mIsDeleted;
// 是否应该被删除
private NoteSettingChangedListener mNoteSettingStatusListener;
// 一个用来监听设置是否有变化的接口
// 声明 DATA_PROJECTION字符串数组
public static final String[] DATA_PROJECTION = new String[] {
// 声明 NOTE_PROJECTION字符串数组
DataColumns.ID,
DataColumns.CONTENT,
DataColumns.MIME_TYPE,
@ -65,10 +75,11 @@ public class WorkingNote {
DataColumns.DATA2,
DataColumns.DATA3,
DataColumns.DATA4,
};
};// 声明各个常量
// 声明 NOTE_PROJECTION字符串数组
public static final String[] NOTE_PROJECTION = new String[] {
// 保存便签自身属性的字符串数组
NoteColumns.PARENT_ID,
NoteColumns.ALERTED_DATE,
NoteColumns.BG_COLOR_ID,
@ -78,52 +89,74 @@ public class WorkingNote {
};
private static final int DATA_ID_COLUMN = 0;
// 规定每一个数据类型在哪一行
private static final int DATA_CONTENT_COLUMN = 1;
private static final int DATA_MIME_TYPE_COLUMN = 2;
private static final int DATA_MODE_COLUMN = 3;
private static final int NOTE_PARENT_ID_COLUMN = 0;
// 以下6个常量表示便签投影的0-5列
private static final int NOTE_ALERTED_DATE_COLUMN = 1;
private static final int NOTE_BG_COLOR_ID_COLUMN = 2;
private static final int NOTE_WIDGET_ID_COLUMN = 3;
private static final int NOTE_WIDGET_TYPE_COLUMN = 4;
private static final int NOTE_MODIFIED_DATE_COLUMN = 5;
/*
* ID便
* 便
* @context
*
* @folderIdID
*/
// New note construct
public WorkingNote(Context context, long folderId) {
mContext = context;
mAlertDate = 0;
mModifiedDate = System.currentTimeMillis();
// 系统现在的时间,时间的表达格式为当前计算机时间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数
mFolderId = folderId;
// 默认最后一次修改日期为当前时间
mNote = new Note();
// 加载一个已存在的便签
mNoteId = 0;
mIsDeleted = false;
// 没有提供id所以默认为0
mMode = 0;
mWidgetType = Notes.TYPE_WIDGET_INVALIDE;
// 默认是不可见
}
// WorkingNote的构造函数
// Existing note construct
private WorkingNote(Context context, long noteId, long folderId) {
// 加载Note
// 该方法初始化类里的各项变量
mContext = context;
// 调用query函数找到第一个条目
mNoteId = noteId;
mFolderId = folderId;
mIsDeleted = false;
mNote = new Note();
loadNote();
// 加载便签
}
// 加载Note
// 通过数据库调用query函数找到第一个条目
private void loadNote() {
// 加载已有的便签
Cursor cursor = mContext.getContentResolver().query(
// 存在第一个条目
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null,
null, null);
// 若存在,储存相应信息
if (cursor != null) {
// 通过数据库调用query函数找到第一个条目
if (cursor.moveToFirst()) {
// moveToFirstwill return false if the cursor is empty
mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN);
mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN);
mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN);// 关闭cursor游标
mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN);
mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN);
mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN);
@ -159,7 +192,7 @@ public class WorkingNote {
} else {
Log.d(TAG, "Wrong note type with type:" + type);
}
} while (cursor.moveToNext());//查阅所有项,直到为空
} while (cursor.moveToNext());// 查阅所有项,直到为空
}
cursor.close();
} else {
@ -171,7 +204,7 @@ public class WorkingNote {
// 创建空的Note
// 传参context文件夹idwidget背景颜色
public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId,
int widgetType, int defaultBgColorId) {
int widgetType, int defaultBgColorId) {
WorkingNote note = new WorkingNote(context, folderId);
// 设定相关属性
note.setBgColorId(defaultBgColorId);
@ -186,7 +219,7 @@ public class WorkingNote {
// 保存Note
public synchronized boolean saveNote() {
if (isWorthSaving()) { //是否值得保存
if (isWorthSaving()) { // 是否值得保存
if (!existInDatabase()) { // 是否存在数据库中
if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) {
Log.e(TAG, "Create new note fail with id:" + mNoteId);
@ -226,7 +259,6 @@ public class WorkingNote {
}
}
// 设置mNoteSettingStatusListener
public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) {
mNoteSettingStatusListener = l;
@ -257,7 +289,7 @@ public class WorkingNote {
// 设定背景颜色
public void setBgColorId(int id) {
if (id != mBgColorId) { //设定条件 id != mBgColorId
if (id != mBgColorId) { // 设定条件 id != mBgColorId
mBgColorId = id;
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onBackgroundColorChanged();
@ -269,7 +301,7 @@ public class WorkingNote {
// 设定检查列表模式
// 参数mode
public void setCheckListMode(int mode) {
if (mMode != mode) { //设定条件 mMode != mode
if (mMode != mode) { // 设定条件 mMode != mode
if (mNoteSettingStatusListener != null) {
mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode);
}
@ -278,11 +310,10 @@ public class WorkingNote {
}
}
// 设定WidgetType
// 参数type
public void setWidgetType(int type) {
if (type != mWidgetType) {//设定条件 type != mWidgetType
if (type != mWidgetType) {// 设定条件 type != mWidgetType
mWidgetType = type;
mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType));
// 调用Note的setNoteValue方法更改WidgetType
@ -292,7 +323,7 @@ public class WorkingNote {
// 设定WidgetId
// 参数id
public void setWidgetId(int id) {
if (id != mWidgetId) {//设定条件 id != mWidgetId
if (id != mWidgetId) {// 设定条件 id != mWidgetId
mWidgetId = id;
mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId));
// 调用Note的setNoteValue方法更改WidgetId
@ -302,7 +333,7 @@ public class WorkingNote {
// 设定WorkingTex
// 参数更改的text
public void setWorkingText(String text) {
if (!TextUtils.equals(mContent, text)) {//设定条件 mContent, text内容不同
if (!TextUtils.equals(mContent, text)) {// 设定条件 mContent, text内容不同
mContent = text;
mNote.setTextData(DataColumns.CONTENT, mContent);
// 调用Note的setTextData方法更改WorkingText
@ -398,9 +429,10 @@ public class WorkingNote {
/**
* Call when switch between check list mode and normal mode
*
* @param oldMode is previous mode before change
* @param newMode is new mode
*/
void onCheckListModeChanged(int oldMode, int newMode);
}
}
}

@ -1,66 +1,96 @@
/*
* 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.data;
//导入android自带的Context类
import android.content.Context;
//从数据库导入cursor表示数据库中的每行数据下标
import android.database.Cursor;
//android系统应用开发框架功能之一提供访问android内容提供者的类。导入里面联系人的号码这个是需要CommonDataKinds提供权限
import android.provider.ContactsContract.CommonDataKinds.Phone;
//导入Data包含通讯录中的每个人的全部信息。
import android.provider.ContactsContract.Data;
//1.Telephony 服务为电话应用程序编程接口 (TAPI) 提供支持。通过使用此硬件您可以通过直接连接到本地计算机、电话线、LAN、WAN 和 Internet 以进行通信。提供处理Phone Number的各种应用工具
import android.telephony.PhoneNumberUtils;
//安卓的日志类工具,方便后面调试使用
import android.util.Log;
//引用了STL里面的HashMap用来映射联系人和电话号码
import java.util.HashMap;
//change
public class Contact { //联系人
public class Contact { //联系人
private static HashMap<String, String> sContactCache;
//写入Cache而创建的一个成员变量
private static final String TAG = "Contact";
// 定义字符串CALLER_ID_SELECTION
//在日志中查看由哪个类打印的日志
// 定义字符串CALLER_ID_SELECTION,表示为每个用户存储了相应的信息,当插入新的用户时,系统会检查系统中是否已存在用户
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL("
+ Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN "
+ "(SELECT raw_contact_id "
+ " FROM phone_lookup"
+ " WHERE min_match = '+')";
+ Phone.NUMBER + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + " AND " + Data.RAW_CONTACT_ID + " IN " + "(SELECT raw_contact_id " + " FROM phone_lookup" + " WHERE min_match = '+')";
// 获取联系人
/**
*
*
* @param context
* @param phoneNumber
* @return
*/
public static String getContact(Context context, String phoneNumber) {
if(sContactCache == null) {
//判断联系人cache是否为空如果为空则初始化一个cache
if (sContactCache == null) {
sContactCache = new HashMap<String, String>();
}
// 查找HashMap中是否已有phoneNumber信息
if(sContactCache.containsKey(phoneNumber)) {
// 查找HashMap中是否已有对应联系人phoneNumber信息
if (sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber);
}
String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 查找数据库中phoneNumber的信息
Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME },
// 修改原先数据库语句Caller_ID_SELECTION用函数形参phonenumber的后七位电话号码代替"+"
String selection = CALLER_ID_SELECTION.replace("+", PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
//从数据库中读取数据query是查询方法。cursor类是对数据库的操作获取整行的数据.Ressolver是对联系人内容的读取其中provider提供了联系人数据
Cursor cursor = context.getContentResolver().query(Data.CONTENT_URI,//uri是区别provider的标志
new String[]{Phone.DISPLAY_NAME},
//该参数告诉provider要返回的内容这里是要返回联系人的名字
selection,
new String[] { phoneNumber },
//该参数相当于数据库中where条件筛选只拥有特定电话号码的信息
new String[]{phoneNumber},
//筛选条件即参数phonenumber
null);
// 判定查询结果
// moveToFirst()返回第一条
//设置查询是否按顺序排列,这里的意思是不按顺序排列
/**
*
*
*/
if (cursor != null && cursor.moveToFirst()) {
try {
// 找到相关信息
// 获取联系人姓名,写入联系人缓存
String name = cursor.getString(0);
sContactCache.put(phoneNumber, name);
return name;
// 异常
} catch (IndexOutOfBoundsException e) {
// 将异常信息写入日志
Log.e(TAG, " Cursor get string error " + e.toString());
return null;
} finally {
cursor.close();
}
// 未找到相关信息
// 未找到相关信息就写入日志
} else {
Log.d(TAG, "No contact matched with number:" + phoneNumber);
return null;

@ -24,7 +24,6 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONException;
import org.json.JSONObject;
public class MetaData extends Task {
/*
* TAG
@ -62,16 +61,14 @@ public class MetaData extends Task {
}
/*
*
* Made By CuiCan
*/
@Override
public boolean isWorthSaving() {
return getNotes() != null;
}
/*
* 使json
* TasksetContentByRemoteJSON ()
*
* 使json
* TasksetContentByRemoteJSON ()
*/
@Override
public void setContentByRemoteJSON(JSONObject js) {
@ -79,6 +76,7 @@ public class MetaData extends Task {
if (getNotes() != null) {
try {
JSONObject metaInfo = new JSONObject(getNotes().trim());
//设置ID
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) {
Log.w(TAG, "failed to get related gid");
@ -126,5 +124,4 @@ public class MetaData extends Task {
*/
}
}
}

@ -1,16 +1,21 @@
//表示在哪个包,依赖关系
package net.micode.notes.data;
//uri是统一资源标识符涉及到安卓权限
import android.content.ContentUris;
import android.net.Uri;
// Notes 类中定义了很多常量这些常量大多是int型和string型
//Notes 类中定义了很多常量这些常量大多是int型和string型
public class Notes {
public static final String AUTHORITY = "micode_notes";
// 定义了一个权限名这里是为了符合Uri的格式而定义的
public static final
String AUTHORITY = "micode_notes";
// 设置标签表示APP的名称是Notes
public static final String TAG = "Notes";
//以下三个常量对NoteColumns.TYPE的值进行设置时会用到
public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2;
/**
* Following IDs are system folders' identifiers
@ -18,11 +23,15 @@ public class Notes {
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records
*/
//垃圾文件夹
public static final int ID_ROOT_FOLDER = 0;
//临时警报
public static final int ID_TEMPARAY_FOLDER = -1;
//通话记录文件夹
public static final int ID_CALL_RECORD_FOLDER = -2;
//垃圾文件夹3
public static final int ID_TRASH_FOLER = -3;
//定义string字符串
public static final String INTENT_EXTRA_ALERT_DATE =
"net.micode.notes.alert_date";
@ -41,11 +50,11 @@ public class Notes {
public static final String INTENT_EXTRA_CALL_DATE =
"net.micode.notes.call_date";
public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0;
public static final int TYPE_WIDGET_4X = 1;
//定义查询便签和指针
public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0;
public static final int TYPE_WIDGET_4X = 1;
//DataContants类存放textnotes和callnotes地址
public static class DataConstants {
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
@ -54,6 +63,7 @@ public class Notes {
/**
* Uri to query all notes and folders
*/
//创建URI访问实例parse中的参数分三部分scheme访问资源的命名机制authority存放资源的主机名path资源自身的名称
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" +
AUTHORITY + "/note");//定义查询便签和文件夹的指针。
@ -62,6 +72,7 @@ public class Notes {
/**
* Uri to query data
* dataUri
*/
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" +
@ -79,17 +90,20 @@ public class Notes {
* The parent's id for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String PARENT_ID = "parent_id";//为什么会有parent_id
//父节点的ID
public static final String PARENT_ID = "parent_id";
/**
* Created data for note or folder
* <P> Type: INTEGER (long) </P>
*
*/
public static final String CREATED_DATE = "created_date";
/**
* Latest modified date
* <P> Type: INTEGER (long) </P>
*
*/
public static final String MODIFIED_DATE = "modified_date";
@ -97,30 +111,35 @@ public class Notes {
/**
* Alert date
* <P> Type: INTEGER (long) </P>
*
*/
public static final String ALERTED_DATE = "alert_date";
/**
* Folder's name or text content of note
* <P> Type: TEXT </P>
*
*/
public static final String SNIPPET = "snippet";
/**
* Note's widget id
* <P> Type: INTEGER (long) </P>
* ID
*/
public static final String WIDGET_ID = "widget_id";
/**
* Note's widget type
* <P> Type: INTEGER (long) </P>
*
*/
public static final String WIDGET_TYPE = "widget_type";
/**
* Note's background color's id
* <P> Type: INTEGER (long) </P>
* ID
*/
public static final String BG_COLOR_ID = "bg_color_id";
@ -128,48 +147,56 @@ public class Notes {
* For text note, it doesn't has attachment, for multi-media
* note, it has at least one attachment
* <P> Type: INTEGER </P>
*
*/
public static final String HAS_ATTACHMENT = "has_attachment";
/**
* Folder's count of notes
* <P> Type: INTEGER (long) </P>
*
*/
public static final String NOTES_COUNT = "notes_count";
/**
* The file type: folder or note
* <P> Type: INTEGER </P>
* 便
*/
public static final String TYPE = "type";
/**
* The last sync id
* <P> Type: INTEGER (long) </P>
* ID
*/
public static final String SYNC_ID = "sync_id";//同步
/**
* Sign to indicate local modified or not
* <P> Type: INTEGER </P>
*
*/
public static final String LOCAL_MODIFIED = "local_modified";
/**
* Original parent id before moving into temporary folder
* <P> Type : INTEGER </P>
* ID
*/
public static final String ORIGIN_PARENT_ID = "origin_parent_id";
/**
* The gtask id
* <P> Type : TEXT </P>
* ID
*/
public static final String GTASK_ID = "gtask_id";
/**
* The version code
* <P> Type : INTEGER (long) </P>
*
*/
public static final String VERSION = "version";
}//这些常量主要是定义便签的属性的。
@ -179,80 +206,93 @@ public class Notes {
/**
* The unique ID for a row
* <P> Type: INTEGER (long) </P>
* 便ID
*/
public static final String ID = "_id";
/**
* The MIME type of the item represented by this row.
* <P> Type: Text </P>
* MIME
*/
public static final String MIME_TYPE = "mime_type";
/**
* The reference id to note that this data belongs to
* <P> Type: INTEGER (long) </P>
* 便ID
*/
public static final String NOTE_ID = "note_id";
/**
* Created data for note or folder
* <P> Type: INTEGER (long) </P>
*
*/
public static final String CREATED_DATE = "created_date";
/**
* Latest modified date
* <P> Type: INTEGER (long) </P>
*
*/
public static final String MODIFIED_DATE = "modified_date";
/**
* Data's content
* <P> Type: TEXT </P>
*
*/
public static final String CONTENT = "content";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* Generic data column, the meaning is {@link #MIMETYPE} specific,
* <p>
* used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA1 = "data1";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* Generic data column, the meaning is {@link #MIMETYPE} specific,
* <p>
* used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA2 = "data2";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* Generic data column, the meaning is {@link #MIMETYPE} specific,
* <p>
* used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA3 = "data3";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* Generic data column, the meaning is {@link #MIMETYPE} specific,
* <p>
* used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA4 = "data4";
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific,
used for
* Generic data column, the meaning is {@link #MIMETYPE} specific,
* <p>
* used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA5 = "data5";
}//主要是定义存储便签内容数据的
//文本数据TextNote通过关键字implements来实现接口继承了DataColumns的所有定义常量
public static final class TextNote implements DataColumns {
/**
* Mode to indicate the text in check list mode or not
@ -269,12 +309,13 @@ public class Notes {
public static final String CONTENT_ITEM_TYPE =
"vnd.android.cursor.item/text_note";
// 访问该content_provider的URIparse方法返回的是一个URI类型。通过这个uri可以访问一个网络上或者本地上的资源
public static final Uri CONTENT_URI = Uri.parse("content://" +
AUTHORITY + "/text_note");
}//文本内容的数据结构
}
//文本内容的数据结构
//TextNote作为DataColumns的子类进行扩展用于记录通话数据的表头
public static final class CallNote implements DataColumns {
/**
* Call date for this record

@ -1,205 +1,130 @@
//数据库操作SQLOpenhelper,对一些note和文件进行数据库的操作。比如删除文件后将文件里的note也相应删除
package net.micode.notes.data;
import android.content.ContentValues;//就是用于保存一些数据string boolean byte double float int long short ...)信息,这些信息可以被数据库操作时使用。
import android.content.Context;//加载和访问资源。android中主要是这两个功能但是这里具体不清楚
import android.database.sqlite.SQLiteDatabase;//主要提供了对应于添加、删除、更新、查询的操作方法: insert()、delete()、update()和query()。配合content.values
import android.database.sqlite.SQLiteOpenHelper;//用来管理数据的创建和版本更新
//保存一些数据信息,这些数据可以被数据库操作
import android.content.ContentValues;
//加载和访问资源
import android.content.Context;
//主要提供了对应于添加、删除、更新、查询的操作
import android.database.sqlite.SQLiteDatabase;
//数据库的更新和创建
import android.database.sqlite.SQLiteOpenHelper;
//安卓日志类接口
import android.util.Log;
//导入Notes.java中的DataColumns, NoteColumns接口和类DataConstants
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
//数据库操作用SQLOpenhelper,对一些note和文件进行数据库的操作比如删除文件后将文件里的note也相应删除
//继承于SQLiteOpenHelper的类NotesDatabaseHelper用于实现对便签或者 文件的数据库操作,例如删除便签
public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 4;
public interface TABLE { //接口分成note和data在后面的程序里分别使用过
public interface TABLE {
//接口分成note和data在后面的程序里分别使用过
public static final String NOTE = "note";
public static final String DATA = "data";
}
//创建一个表格用来储存标签编号
private static final String TAG = "NotesDatabaseHelper";
//实例化一个NoteDatabaseHelper
private static NotesDatabaseHelper mInstance;
/**
* 便便
* ID便ID
*
*
* db.execSQL("字符串")
*/
private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")";
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";//数据库中需要存储的项目的名称,就相当于创建一个表格的表头的内容。
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";//和上面的功能一样,主要是存储的项目不同
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";//存储便签编号的一个数据表格
//大体同上,这里储存的是便签内容的信息,
// 用这些信息作为数据库对便签内容存储的表头
private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + DataColumns.MIME_TYPE + " TEXT NOT NULL," + DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA1 + " INTEGER," + DataColumns.DATA2 + " INTEGER," + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + ")";
//创建索引名称为note_id_index在TABLE.DATA表格的DataCloumns.NOTE_ID列
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";//存储便签编号的一个数据表格
/**
* Increase folder's note count when move note to the folder
* 便便
* db.execSQL()
* update
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";//在文件夹中移入一个Note之后需要更改的数据的表格。
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER increase_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END";
/**
* Decrease folder's note count when move note from folder
* 便便1
* db.execSQL()
* updata
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_update " +
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END";//在文件夹中移出一个Note之后需要更改的数据的表格。
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " END";
/**
* Increase folder's note count when insert new note to the folder
* 便便+1
* insert
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_insert " +
" AFTER INSERT ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";//在文件夹中插入一个Note之后需要更改的数据的表格。
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + " AFTER INSERT ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END";
/**
* Decrease folder's note count when delete note from the folder
* notenote
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";//在文件夹中删除一个Note之后需要更改的数据的表格。
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0;" + " END";
/**
* Update note's content when insert data with type {@link DataConstants#NOTE}
* Notenote
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
" AFTER INSERT ON " + TABLE.DATA +
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";//在文件夹中对一个Note导入新的数据之后需要更改的数据的表格。
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + " AFTER INSERT ON " + TABLE.DATA + " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
* SQLnotedata
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER update_note_content_on_update " +
" AFTER UPDATE ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";//Note数据被修改后需要更改的数据的表格。
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + " AFTER UPDATE ON " + TABLE.DATA + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
* note
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " +
" AFTER delete ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";//Note数据被删除后需要更改的数据的表格。
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + " AFTER delete ON " + TABLE.DATA + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=''" + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " END";
/**
* Delete datas belong to note which has been deleted
* 便
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";//删除已删除的便签的数据后需要更改的数据的表格。
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN" + " DELETE FROM " + TABLE.DATA + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + " END";
/**
* Delete notes belong to folder which has been deleted
* 便
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";//删除已删除的文件夹的便签后需要更改的数据的表格。
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN" + " DELETE FROM " + TABLE.NOTE + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END";
/**
* Move notes belong to folder which has been moved to trash folder
* 便
*/
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
"CREATE TRIGGER folder_move_notes_on_trash " +
" AFTER UPDATE ON " + TABLE.NOTE +
" WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";//还原垃圾桶中便签后需要更改的数据的表格。
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + " AFTER UPDATE ON " + TABLE.NOTE + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END";
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}//构造函数,传入数据库的名称和版本
}
//构造函数,传入数据库的名称和版本
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}//创建表格(用来存储标签属性)
}
//创建表格(用来存储标签属性)
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
@ -217,7 +142,8 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}//execSQL是数据库操作的API主要是更改行为的SQL语句。
}
//execSQL是数据库操作的API主要是更改行为的SQL语句。
//在这里主要是用来重新创建上述定义的表格用的,先删除原来有的数据库的触发器再重新创建新的数据库
private void createSystemFolder(SQLiteDatabase db) {
@ -225,6 +151,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* call record foler for call notes
* ContenValues
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
@ -232,6 +159,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* root folder which is default folder
* valuesvalues
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
@ -240,6 +168,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* temporary folder which is used for moving note
*
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
@ -248,12 +177,14 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
/**
* create trash folder
*
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}//创建几个系统文件夹
}
//创建几个系统文件夹
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
@ -270,14 +201,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}//同上面的execSQL
}//创建用于表格初始化,删除触发器,然后更新触发器
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
}//上网查是为解决同一时刻只能有一个线程执行.
}
//上网查是为解决同一时刻只能有一个线程执行.
//在写程序库代码时,有时有一个类需要被所有的其它类使用,
//但又要求这个类只能被实例化一次,是个服务类,定义一次,其它类使用同一个这个类的实例
@ -289,43 +221,47 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//是否重建的信号
boolean reCreateTriggers = false;
//是否从V2升级到V3
boolean skipV2 = false;
//判断旧版本是不是V1如果是就升级版本到V2
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
//判断旧版本是V2且未跳过V2版本就升级版本到V3
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
//如果旧版本是V3就升级版本到V4
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
}
//若重构触发器的值为真,那么,
// 要把便签note和数据data表单的数据库触发器重构调用以上的定义
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
}
//旧版本与最新版本不一致,抛出异常
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
throw new IllegalStateException("Upgrade notes database to version " + newVersion + "fails");
}
}//数据库版本的更新(数据库内容的更改)
}
//数据库版本的更新(数据库内容的更改)
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
createNoteTable(db);
createDataTable(db);
}//更新到V2版本
}
//更新到V2版本,删除note和data表然后新建表
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
@ -333,17 +269,16 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper {
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
// add a column for gtask id
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
+ " TEXT NOT NULL DEFAULT ''");
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''");
// add a trash system folder
ContentValues values = new ContentValues();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}//更新到V3版本
}
//更新到V3版本删除触发器新增gtask和trash行然后在表中增添表头
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0");
}//更新到V4版本,但是不知道V2、V3、V4是什么意思
}

@ -1,4 +1,5 @@
package net.micode.notes.data;
//说明当前文件所在包
import android.app.SearchManager;
import android.content.ContentProvider;
@ -16,6 +17,7 @@ import net.micode.notes.R;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.NoteColumns;
import net.micode.notes.data.NotesDatabaseHelper.TABLE;
//为存储和获取数据提供接口。可以在不同的应用程序之间共享数据
//ContentProvider提供的方法
//query查询
@ -26,11 +28,11 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE;
public class NotesProvider extends ContentProvider {
// UriMatcher用于匹配Uri
private static final UriMatcher mMatcher;
//数据库辅助类的实例对象
private NotesDatabaseHelper mHelper;
//写入日志时的标签名
private static final String TAG = "NotesProvider";
//Uri资源的ID共6个
private static final int URI_NOTE = 1;
private static final int URI_NOTE_ITEM = 2;
private static final int URI_DATA = 3;
@ -56,7 +58,7 @@ public class NotesProvider extends ContentProvider {
* x'0A' represents the '\n' character in sqlite. For title and content in the search result,
* we will trim '\n' and white space in order to show more information.
*/
// 声明 NOTES_SEARCH_PROJECTION
// 声明 字符串NOTES_SEARCH_PROJECTION,作为实参相当于where语句
private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + ","
+ NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + ","
@ -64,7 +66,7 @@ public class NotesProvider extends ContentProvider {
+ R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + ","
+ "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + ","
+ "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA;
// 声明NOTES_SNIPPET_SEARCH_QUERY
// 声明NOTES_SNIPPET_SEARCH_QUERY,作用同上
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?"
@ -83,6 +85,7 @@ public class NotesProvider extends ContentProvider {
// 查询uri在数据库中对应的位置
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
//先声明一个游标
Cursor c = null;
// 获取可读数据库
SQLiteDatabase db = mHelper.getReadableDatabase();
@ -124,6 +127,7 @@ public class NotesProvider extends ContentProvider {
searchString = uri.getPathSegments().get(1);
}
} else {
//利用URi的getQueryParameter方法可以获取字符串参数
searchString = uri.getQueryParameter("pattern");
}
@ -133,9 +137,11 @@ public class NotesProvider extends ContentProvider {
try {
searchString = String.format("%%%s%%", searchString);
//通过上文得到的搜索字符串进行格式加工,然后用于下面数据库查询条件
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString });
} catch (IllegalStateException ex) {
//捕捉异常
Log.e(TAG, "got exception: " + ex.toString());
}
break;
@ -144,6 +150,7 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (c != null) {
//若getContentResolver发生变化就接收通知
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
@ -173,13 +180,14 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
// notifyChange获得一个ContextResolver对象并且更新里面的内容
// 获的一个content对象若发生了变化则调用getContentResolver由notifyChange对监听它的对象进行通知
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri
//更新Data ID
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
@ -200,7 +208,9 @@ public class NotesProvider extends ContentProvider {
boolean deleteData = false;
switch (mMatcher.match(uri)) {
case URI_NOTE:
//筛选语句如下
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
//删除相应数据
count = db.delete(TABLE.NOTE, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
@ -210,9 +220,11 @@ public class NotesProvider extends ContentProvider {
* trash
*/
long noteId = Long.valueOf(id);
//将ID值转为长整数
if (noteId <= 0) {
break;
}
//执行删除操作,三个参数分别为要删除的表,删除筛选条件,
count = db.delete(TABLE.NOTE,
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
@ -230,6 +242,7 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri);
}
if (count > 0) {
//判断是否进行了删除操作,并对监听了删除操作的其他部分给予提醒
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
@ -247,6 +260,7 @@ public class NotesProvider extends ContentProvider {
boolean updateData = false;
switch (mMatcher.match(uri)) {
case URI_NOTE:
//note版本更新数据更新以下各部分一致
increaseNoteVersion(-1, selection, selectionArgs);
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
@ -267,9 +281,10 @@ public class NotesProvider extends ContentProvider {
updateData = true;
break;
default:
//查询异常处理
throw new IllegalArgumentException("Unknown URI " + uri);
}
//在执行了更新的操作之后,要对监听更新操作的其他部分给予提醒
if (count > 0) {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);

@ -1,18 +1,3 @@
/*
* 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;
@ -37,21 +22,11 @@ import org.json.JSONObject;
import java.util.ArrayList;
/*
* Description便sqldatanotedata
* Description便sqldatanotedata
* SqlDataSqlNote
*/
/*
*
*
*
* Made By CuiCan
*/
public class SqlNote {
/*
* TAG
@ -59,7 +34,7 @@ public class SqlNote {
* Made By CuiCan
*/
private static final String TAG = SqlNote.class.getSimpleName();
//将INVALID_ID 初始化为-99999
private static final int INVALID_ID = -99999;
// 集合了interface NoteColumns中所有SF常量17个
public static final String[] PROJECTION_NOTE = new String[] {
@ -157,9 +132,11 @@ public class SqlNote {
mId = INVALID_ID;
mAlertDate = 0;
mBgColorId = ResourceParser.getDefaultBgId(context);
mCreatedDate = System.currentTimeMillis();//调用系统函数获得创建时间
mCreatedDate = System.currentTimeMillis();
//调用系统函数获得创建时间
mHasAttachment = 0;
mModifiedDate = System.currentTimeMillis();//最后一次修改时间初始化为创建时间
mModifiedDate = System.currentTimeMillis();
//最后一次修改时间初始化为创建时间
mParentId = 0;
mSnippet = "";
mType = Notes.TYPE_NOTE;
@ -220,10 +197,12 @@ public class SqlNote {
c = mContentResolver.query(Notes.CONTENT_NOTE_URI, PROJECTION_NOTE, "(_id=?)",
new String[] {
String.valueOf(id)
}, null);//通过id获得对应的ContentResolver中的cursor
}, null);
//通过id获得对应的ContentResolver中的cursor
if (c != null) {
c.moveToNext();
loadFromCursor(c);//然后加载数据进行初始化,这样函数
loadFromCursor(c);
//然后加载数据进行初始化,这样函数
//SqlNote(Context context, long id)与SqlNote(Context context, long id)的实现方式基本相同
} else {
Log.w(TAG, "loadFromCursor: cursor = null");
@ -239,7 +218,7 @@ public class SqlNote {
* Made By CuiCan
*/
private void loadFromCursor(Cursor c) {
//直接从一条记录中获得以下变量的初始值
//直接从一条记录中获得以下变量的初始值
mId = c.getLong(ID_COLUMN);
mAlertDate = c.getLong(ALERTED_DATE_COLUMN);
mBgColorId = c.getInt(BG_COLOR_ID_COLUMN);
@ -293,9 +272,12 @@ public class SqlNote {
public boolean setContent(JSONObject js) {
try {
JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
//创建一个JSONObject对象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) : "";
@ -311,13 +293,17 @@ public class SqlNote {
}
mType = type;
} else if (note.getInt(NoteColumns.TYPE) == Notes.TYPE_NOTE) {
//如果是便签则直接进入,下面一句是获取提示日期
JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
//获取数据的ID
long id = note.has(NoteColumns.ID) ? note.getLong(NoteColumns.ID) : INVALID_ID;
//如果只是通过上下文对note进行数据库操作或者该ID与原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) {
@ -325,12 +311,14 @@ public class SqlNote {
}
mAlertDate = alertDate;
//获取背景颜色ID
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;
//获取创建日期
long createDate = note.has(NoteColumns.CREATED_DATE) ? note
.getLong(NoteColumns.CREATED_DATE) : System.currentTimeMillis();
if (mIsCreate || mCreatedDate != createDate) {
@ -338,6 +326,7 @@ public class SqlNote {
}
mCreatedDate = createDate;
//取数据的有无附件的布尔值
int hasAttachment = note.has(NoteColumns.HAS_ATTACHMENT) ? note
.getInt(NoteColumns.HAS_ATTACHMENT) : 0;
if (mIsCreate || mHasAttachment != hasAttachment) {
@ -345,6 +334,7 @@ public class SqlNote {
}
mHasAttachment = hasAttachment;
//对最近修改日期的操作
long modifiedDate = note.has(NoteColumns.MODIFIED_DATE) ? note
.getLong(NoteColumns.MODIFIED_DATE) : System.currentTimeMillis();
if (mIsCreate || mModifiedDate != modifiedDate) {
@ -352,6 +342,7 @@ public class SqlNote {
}
mModifiedDate = modifiedDate;
//获取数据的父节点ID
long parentId = note.has(NoteColumns.PARENT_ID) ? note
.getLong(NoteColumns.PARENT_ID) : 0;
if (mIsCreate || mParentId != parentId) {
@ -359,6 +350,7 @@ public class SqlNote {
}
mParentId = parentId;
//对摘要操作
String snippet = note.has(NoteColumns.SNIPPET) ? note
.getString(NoteColumns.SNIPPET) : "";
if (mIsCreate || !mSnippet.equals(snippet)) {
@ -366,6 +358,7 @@ public class SqlNote {
}
mSnippet = snippet;
//对类型操作
int type = note.has(NoteColumns.TYPE) ? note.getInt(NoteColumns.TYPE)
: Notes.TYPE_NOTE;
if (mIsCreate || mType != type) {
@ -373,6 +366,7 @@ public class SqlNote {
}
mType = type;
//获取小部件的ID
int widgetId = note.has(NoteColumns.WIDGET_ID) ? note.getInt(NoteColumns.WIDGET_ID)
: AppWidgetManager.INVALID_APPWIDGET_ID;
if (mIsCreate || mWidgetId != widgetId) {
@ -380,6 +374,7 @@ public class SqlNote {
}
mWidgetId = widgetId;
//对小部件的类型操作
int widgetType = note.has(NoteColumns.WIDGET_TYPE) ? note
.getInt(NoteColumns.WIDGET_TYPE) : Notes.TYPE_WIDGET_INVALIDE;
if (mIsCreate || mWidgetType != widgetType) {
@ -387,6 +382,7 @@ public class SqlNote {
}
mWidgetType = widgetType;
//获取数据的原始父文件夹ID
long originParent = note.has(NoteColumns.ORIGIN_PARENT_ID) ? note
.getLong(NoteColumns.ORIGIN_PARENT_ID) : 0;
if (mIsCreate || mOriginParent != originParent) {
@ -394,6 +390,7 @@ public class SqlNote {
}
mOriginParent = originParent;
//遍历 dataArray查找 id 为 dataId 的数据
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
SqlData sqlData = null;
@ -437,7 +434,8 @@ public class SqlNote {
}
JSONObject note = new JSONObject();
if (mType == Notes.TYPE_NOTE) {//类型为note时
if (mType == Notes.TYPE_NOTE) {
//类型为note时,将13个键值对的值写入note中然后再设置为js键值对中的一个值
note.put(NoteColumns.ID, mId);
note.put(NoteColumns.ALERTED_DATE, mAlertDate);
note.put(NoteColumns.BG_COLOR_ID, mBgColorId);
@ -453,14 +451,17 @@ public class SqlNote {
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
JSONArray dataArray = new JSONArray();
//将note中的所有数据存进dataarray中
for (SqlData sqlData : mDataList) {
JSONObject data = sqlData.getContent();
if (data != null) {
dataArray.put(data);
}
}
//将dataArray存进js中
js.put(GTaskStringUtils.META_HEAD_DATA, dataArray);
} else if (mType == Notes.TYPE_FOLDER || mType == Notes.TYPE_SYSTEM) {//类型为文件夹或者
} 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);
@ -486,7 +487,7 @@ public class SqlNote {
}
/*
* idGtaskid
* idGtaskid
*
* Made By CuiCan
*/
@ -549,16 +550,18 @@ public class SqlNote {
}
/*
* commit
* commit
*
* Made By CuiCan
*/
public void commit(boolean validateVersion) {
if (mIsCreate) {
//如果是第一种构造方式ID为无效ID且包含该ID则删除
if (mId == INVALID_ID && mDiffNoteValues.containsKey(NoteColumns.ID)) {
mDiffNoteValues.remove(NoteColumns.ID);
}
//插入便签的uri
Uri uri = mContentResolver.insert(Notes.CONTENT_NOTE_URI, mDiffNoteValues);
try {
mId = Long.valueOf(uri.getPathSegments().get(1));
@ -571,11 +574,14 @@ public class SqlNote {
}
if (mType == Notes.TYPE_NOTE) {
for (SqlData sqlData : mDataList) {//直接使用sqldata中的实现
//如果类型为便签类型
for (SqlData sqlData : mDataList) {
//直接使用sqldata中的实现方法来实现
sqlData.commit(mId, false, -1);
}
}
} else {
//如果该便签ID是无效ID报错没有这个便签
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");
@ -583,7 +589,8 @@ public class SqlNote {
if (mDiffNoteValues.size() > 0) {
mVersion ++;
int result = 0;
if (!validateVersion) {//构造字符串
if (!validateVersion) {
//构造字符串
result = mContentResolver.update(Notes.CONTENT_NOTE_URI, mDiffNoteValues, "("
+ NoteColumns.ID + "=?)", new String[] {
String.valueOf(mId)
@ -595,24 +602,27 @@ public class SqlNote {
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) {
//如果类型为便签类型那么就调用SqlData中的方法来写入修改记录
for (SqlData sqlData : mDataList) {
sqlData.commit(mId, validateVersion, mVersion);
}
}
}
// refresh local info
//通过 cursor 从当前 id 处加载数据
loadFromCursor(mId);
if (mType == Notes.TYPE_NOTE)
loadDataContent();
//清空,回到初始化状态
mDiffNoteValues.clear();
//改变数据库构造模式
mIsCreate = false;
}
}
}

@ -1,19 +1,3 @@
/*
* 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.database.Cursor;
@ -30,23 +14,27 @@ import net.micode.notes.tool.GTaskStringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
//创建Task类继承父类Node
public class Task extends Node {
//通过getSimpleName获得类名
private static final String TAG = Task.class.getSimpleName();
private boolean mCompleted;//是否完成
private boolean mCompleted;
//是否完成
private String mNotes;
private JSONObject mMetaInfo;//将在实例中存储数据的类型
private JSONObject mMetaInfo;
//将在实例中存储数据的类型
private Task mPriorSibling;//对应的优先兄弟Task的指针待完善
private Task mPriorSibling;
//对应的优先兄弟Task的指针
private TaskList mParent;//所在的任务列表的指针
private TaskList mParent;
//所在的任务列表的指针
public Task() {
//调用父类的构造方法
super();
mCompleted = false;
mNotes = null;
@ -56,12 +44,14 @@ public class Task extends Node {
}
public JSONObject getCreateAction(int actionId) {
//新建一个 JSONObject 的对象用来存放同步过程中所用到的 task 信息
JSONObject js = new JSONObject();
try {
// action_type
js.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE,
GTaskStringUtils.GTASK_JSON_ACTION_TYPE_CREATE);
//共享数据存入动作类型action_ type,以下同类
// action_id
js.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, actionId);
@ -69,15 +59,17 @@ public class Task extends Node {
// index
js.put(GTaskStringUtils.GTASK_JSON_INDEX, mParent.getChildTaskIndex(this));
// entity_delta
// 创建实体数据并将name创建者id实体类型存入数据
JSONObject entity = new JSONObject();
entity.put(GTaskStringUtils.GTASK_JSON_NAME, getName());
entity.put(GTaskStringUtils.GTASK_JSON_CREATOR_ID, "null");
entity.put(GTaskStringUtils.GTASK_JSON_ENTITY_TYPE,
GTaskStringUtils.GTASK_JSON_TYPE_TASK);
//如果存在Note也将其放入entity
if (getNotes() != null) {
entity.put(GTaskStringUtils.GTASK_JSON_NOTES, getNotes());
}
//实体存入js
js.put(GTaskStringUtils.GTASK_JSON_ENTITY_DELTA, entity);
// parent_id
@ -100,6 +92,7 @@ public class Task extends Node {
}
} catch (JSONException e) {
//异常处理当create task'失败时
Log.e(TAG, e.toString());
e.printStackTrace();
throw new ActionFailureException("fail to generate task-create jsonobject");
@ -109,6 +102,7 @@ public class Task extends Node {
}
public JSONObject getUpdateAction(int actionId) {
//此函数和上一个getCreatAction的功能差不多一个是creat一个updata都是对action进行操作
JSONObject js = new JSONObject();
try {
@ -141,6 +135,7 @@ public class Task extends Node {
}
public void setContentByRemoteJSON(JSONObject js) {
//通过远端的jsonobject获取任务内容,如果有相应的数据就设置NOTE中的值
if (js != null) {
try {
// id
@ -180,9 +175,11 @@ public class Task extends Node {
}
}
public void setContentByLocalJSON(JSONObject js) { //<2F><>metadata<74><61><EFBFBD><EFBFBD>ʵʩ
public void setContentByLocalJSON(JSONObject js) {
////通过本地的jsonobject获取任务内容,如果有相应的数据就设置NOTE中的值
if (js == null || !js.has(GTaskStringUtils.META_HEAD_NOTE)
|| !js.has(GTaskStringUtils.META_HEAD_DATA)) {
//如果js不存在或者js没有元数据的开头或者js指针没有元数据
Log.w(TAG, "setContentByLocalJSON: nothing is avaiable");
}
@ -198,6 +195,7 @@ public class Task extends Node {
for (int i = 0; i < dataArray.length(); i++) {
JSONObject data = dataArray.getJSONObject(i);
if (TextUtils.equals(data.getString(DataColumns.MIME_TYPE), DataConstants.NOTE)) {
//遍历 dataArray 查找与数据库中DataConstants.NOTE 记录信息一致的 data
setName(data.getString(DataColumns.CONTENT));
break;
}
@ -210,10 +208,11 @@ public class Task extends Node {
}
public JSONObject getLocalJSONFromContent() {
//通过内容更新本地的jsonobject
String name = getName();
try {
if (mMetaInfo == null) {
// new task created from web
//元数据类型信息为空,若名字也为空则新建一个 JSONObject 对象并将其返回
if (name == null) {
Log.w(TAG, "the note seems to be an empty one");
return null;
@ -230,7 +229,7 @@ public class Task extends Node {
js.put(GTaskStringUtils.META_HEAD_NOTE, note);
return js;
} else {
// synced task
// 否则将元数据同步至数据中
JSONObject note = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
JSONArray dataArray = mMetaInfo.getJSONArray(GTaskStringUtils.META_HEAD_DATA);
@ -253,6 +252,7 @@ public class Task extends Node {
}
public void setMetaInfo(MetaData metaData) {
//设置元数据信息
if (metaData != null && metaData.getNotes() != null) {
try {
mMetaInfo = new JSONObject(metaData.getNotes());
@ -264,28 +264,32 @@ public class Task extends Node {
}
public int getSyncAction(Cursor c) {
// 异常处理,进行同步操作,如果不成功按照对应的情况进行异常信息的反馈,比如远端文档被删除、文档不匹配等等
try {
JSONObject noteInfo = null;
if (mMetaInfo != null && mMetaInfo.has(GTaskStringUtils.META_HEAD_NOTE)) {
//元数据信息不为空并且元数据信息还含有“META_HEAD_NOTE”说明便签存在
noteInfo = mMetaInfo.getJSONObject(GTaskStringUtils.META_HEAD_NOTE);
}
if (noteInfo == null) {
//数据未写入时写入日志
Log.w(TAG, "it seems that note meta has been deleted");
return SYNC_ACTION_UPDATE_REMOTE;
}
//如果没有ID
if (!noteInfo.has(NoteColumns.ID)) {
Log.w(TAG, "remote note id seems to be deleted");
return SYNC_ACTION_UPDATE_LOCAL;
}
// validate the note id now
// 如果是无效ID
if (c.getLong(SqlNote.ID_COLUMN) != noteInfo.getLong(NoteColumns.ID)) {
Log.w(TAG, "note id doesn't match");
return SYNC_ACTION_UPDATE_LOCAL;
}
//
if (c.getInt(SqlNote.LOCAL_MODIFIED_COLUMN) == 0) {
// there is no local update
if (c.getLong(SqlNote.SYNC_ID_COLUMN) == getLastModified()) {
@ -317,6 +321,8 @@ public class Task extends Node {
}
public boolean isWorthSaving() {
//判断是否值得存放,即当前数据是否有效,若数据非空 或 名字合法存在且去除空格后的名字长度大于零则返回真值。
//其中 trim() 的作用是去除字符串前后的空格public String trim()返回字符串的副本,忽略前导空白和尾部空白
return mMetaInfo != null || (getName() != null && getName().trim().length() > 0)
|| (getNotes() != null && getNotes().trim().length() > 0);
}
@ -324,33 +330,41 @@ public class Task extends Node {
public void setCompleted(boolean completed) {
this.mCompleted = completed;
}
//设定是否完成的成员变量
public void setNotes(String notes) {
this.mNotes = notes;
}
//设定是note成员变量
public void setPriorSibling(Task priorSibling) {
this.mPriorSibling = priorSibling;
}
//.设置优先兄弟 task 的优先级
public void setParent(TaskList parent) {
this.mParent = parent;
}
//设置父节点列表
public boolean getCompleted() {
return this.mCompleted;
}
//获取 task 是否修改完毕的记录
public String getNotes() {
//获取成员变量 mNotes 的信息
return this.mNotes;
}
public Task getPriorSibling() {
return this.mPriorSibling;
}
//获取优先兄弟 task
public TaskList getParent() {
return this.mParent;
}
//获取父节点列表
}

@ -30,7 +30,6 @@ import org.json.JSONObject;
import java.util.ArrayList;
public class TaskList extends Node {
private static final String TAG = TaskList.class.getSimpleName();//tag标记
@ -398,4 +397,65 @@ public class TaskList extends Node {
public int getIndex() {
return this.mIndex;
}
}
}
public boolean moveChildTask(Task task, int index) {
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "move child task: invalid index");
return false;
}
int pos = mChildren.indexOf(task);
if (pos == -1) {
Log.e(TAG, "move child task: the task should in the list");
return false;
}
if (pos == index)
return true;
return (removeChildTask(task) && addChildTask(task, index));
}
public Task findChildTaskByGid(String gid) {
for (int i = 0; i < mChildren.size(); i++) {
Task t = mChildren.get(i);
if (t.getGid().equals(gid)) {
return t;
}
}
return null;
}
public int getChildTaskIndex(Task task) {
return mChildren.indexOf(task);
}
public Task getChildTaskByIndex(int index) {
if (index < 0 || index >= mChildren.size()) {
Log.e(TAG, "getTaskByIndex: invalid index");
return null;
}
return mChildren.get(index);
}
public Task getChilTaskByGid(String gid) {
for (Task task : mChildren) {
if (task.getGid().equals(gid))
return task;
}
return null;
}
public ArrayList<Task> getChildTaskList() {
return this.mChildren;
}
public void setIndex(int index) {
this.mIndex = index;
}
public int getIndex() {
return this.mIndex;
}
}

Loading…
Cancel
Save