From ec1f11abe29bdd787152d64140a403727f83e898 Mon Sep 17 00:00:00 2001 From: ptka4xvyr <2190210566@qq.com> Date: Sun, 4 Jun 2023 23:15:49 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/成员代码分析/jbc/BackupUtils.java | 178 ++++++------- doc/成员代码分析/jbc/DataUtils.java | 125 +++++---- doc/成员代码分析/jbc/GTaskManager.java | 37 +-- .../jbc/GTaskStringUtils.java | 43 +--- doc/成员代码分析/jbc/Note.java | 132 ++++++---- doc/成员代码分析/jbc/WorkingNote.java | 78 ++++-- doc/成员代码分析/jhw/Contact.java | 86 +++++-- doc/成员代码分析/jhw/MetaData.java | 11 +- doc/成员代码分析/jhw/Notes.java | 93 +++++-- .../jhw/NotesDatabaseHelper.java | 239 +++++++----------- doc/成员代码分析/jhw/NotesProvider.java | 29 ++- doc/成员代码分析/lzb/SqlNote.java | 92 ++++--- doc/成员代码分析/lzb/Task.java | 72 +++--- doc/成员代码分析/lzb/TaskList.java | 64 ++++- 14 files changed, 720 insertions(+), 559 deletions(-) diff --git a/doc/成员代码分析/jbc/BackupUtils.java b/doc/成员代码分析/jbc/BackupUtils.java index 11c21f3..b407e84 100644 --- a/doc/成员代码分析/jbc/BackupUtils.java +++ b/doc/成员代码分析/jbc/BackupUtils.java @@ -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; } } - - diff --git a/doc/成员代码分析/jbc/DataUtils.java b/doc/成员代码分析/jbc/DataUtils.java index abfd276..5c06a95 100644 --- a/doc/成员代码分析/jbc/DataUtils.java +++ b/doc/成员代码分析/jbc/DataUtils.java @@ -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 ids) { //直接删除多个笔记 + + public static boolean batchDeleteNotes(ContentResolver resolver, HashSet 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 operationList = new ArrayList(); //提供一个任务列表 + ArrayList operationList = new ArrayList(); // 提供一个任务列表 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 ids, - long folderId) { + // 批量移动 + long folderId) { + // ID为空的情况 if (ids == null) { Log.d(TAG, "the ids is null"); + // ID为空的情况 return true; } ArrayList operationList = new ArrayList(); 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 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 set = null; if (c != null) { + // 语句块:将app窗口的属性加入到HashSet中 if (c.moveToFirst()) { set = new HashSet(); 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; } -} +} \ No newline at end of file diff --git a/doc/成员代码分析/jbc/GTaskManager.java b/doc/成员代码分析/jbc/GTaskManager.java index aaceb47..1b24acb 100644 --- a/doc/成员代码分析/jbc/GTaskManager.java +++ b/doc/成员代码分析/jbc/GTaskManager.java @@ -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); diff --git a/doc/成员代码分析/jbc/GTaskStringUtils.java b/doc/成员代码分析/jbc/GTaskStringUtils.java index 7988601..5ea2685 100644 --- a/doc/成员代码分析/jbc/GTaskStringUtils.java +++ b/doc/成员代码分析/jbc/GTaskStringUtils.java @@ -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"; -} +} \ No newline at end of file diff --git a/doc/成员代码分析/jbc/Note.java b/doc/成员代码分析/jbc/Note.java index 345f47b..a20cc8e 100644 --- a/doc/成员代码分析/jbc/Note.java +++ b/doc/成员代码分析/jbc/Note.java @@ -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 operationList = new ArrayList(); - 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); + // MIME:MIME(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; } } } - diff --git a/doc/成员代码分析/jbc/WorkingNote.java b/doc/成员代码分析/jbc/WorkingNote.java index 6e3acf2..3575008 100644 --- a/doc/成员代码分析/jbc/WorkingNote.java +++ b/doc/成员代码分析/jbc/WorkingNote.java @@ -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:当前活动的上下文 + * + * @folderId:当前文件夹的ID + */ // 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()) { + // moveToFirst:will 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,文件夹id,widget,背景颜色 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); } -} \ No newline at end of file +} diff --git a/doc/成员代码分析/jhw/Contact.java b/doc/成员代码分析/jhw/Contact.java index 199bb2a..41aad99 100644 --- a/doc/成员代码分析/jhw/Contact.java +++ b/doc/成员代码分析/jhw/Contact.java @@ -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 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(); } - - // 查找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; diff --git a/doc/成员代码分析/jhw/MetaData.java b/doc/成员代码分析/jhw/MetaData.java index 596429d..c5fd1af 100644 --- a/doc/成员代码分析/jhw/MetaData.java +++ b/doc/成员代码分析/jhw/MetaData.java @@ -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数据对象设置元数据内容 - * 实现过程:调用父类Task中的setContentByRemoteJSON ()函数,并 - * 参数注解: + * 功能描述:使用远程json数据对象设置元数据内容实现过程: + * 调用父类Task中的setContentByRemoteJSON ()函数,并参数注解: */ @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 { */ } - -} +} \ No newline at end of file diff --git a/doc/成员代码分析/jhw/Notes.java b/doc/成员代码分析/jhw/Notes.java index 7cf0140..d3a648e 100644 --- a/doc/成员代码分析/jhw/Notes.java +++ b/doc/成员代码分析/jhw/Notes.java @@ -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 + * 系统根据data查询所需的Uri常量 */ 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 *

Type: INTEGER (long)

*/ - 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 *

Type: INTEGER (long)

+ * 创建时间 */ public static final String CREATED_DATE = "created_date"; /** * Latest modified date *

Type: INTEGER (long)

+ * 提醒时间 */ public static final String MODIFIED_DATE = "modified_date"; @@ -97,30 +111,35 @@ public class Notes { /** * Alert date *

Type: INTEGER (long)

+ * 提醒时间 */ public static final String ALERTED_DATE = "alert_date"; /** * Folder's name or text content of note *

Type: TEXT

+ * 文件夹名字或文件内容 */ public static final String SNIPPET = "snippet"; /** * Note's widget id *

Type: INTEGER (long)

+ * 小部件ID */ public static final String WIDGET_ID = "widget_id"; /** * Note's widget type *

Type: INTEGER (long)

+ * 小部件类型 */ public static final String WIDGET_TYPE = "widget_type"; /** * Note's background color's id *

Type: INTEGER (long)

+ * 背景颜色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 *

Type: INTEGER

+ * 是否有附件 */ public static final String HAS_ATTACHMENT = "has_attachment"; /** * Folder's count of notes *

Type: INTEGER (long)

+ * 文件夹中标签的数量 */ public static final String NOTES_COUNT = "notes_count"; /** * The file type: folder or note *

Type: INTEGER

+ * 文件或者便签的类型 */ public static final String TYPE = "type"; /** * The last sync id *

Type: INTEGER (long)

+ * 最后一次同步的ID */ public static final String SYNC_ID = "sync_id";//同步 /** * Sign to indicate local modified or not *

Type: INTEGER

+ * 标识本地是否修改 */ public static final String LOCAL_MODIFIED = "local_modified"; /** * Original parent id before moving into temporary folder *

Type : INTEGER

+ * 移动到当前文件夹之前的父文件夹ID */ public static final String ORIGIN_PARENT_ID = "origin_parent_id"; /** * The gtask id *

Type : TEXT

+ * 后台任务ID */ public static final String GTASK_ID = "gtask_id"; /** * The version code *

Type : INTEGER (long)

+ * 版本代号 */ public static final String VERSION = "version"; }//这些常量主要是定义便签的属性的。 @@ -179,80 +206,93 @@ public class Notes { /** * The unique ID for a row *

Type: INTEGER (long)

+ * 一行独立的便签ID */ public static final String ID = "_id"; /** * The MIME type of the item represented by this row. *

Type: Text

+ * MIME类型能包含视频、图像、文本、音频、应用程序等数据 */ public static final String MIME_TYPE = "mime_type"; /** * The reference id to note that this data belongs to *

Type: INTEGER (long)

+ * 便签ID */ public static final String NOTE_ID = "note_id"; /** * Created data for note or folder *

Type: INTEGER (long)

+ * 创建时间 */ public static final String CREATED_DATE = "created_date"; /** * Latest modified date *

Type: INTEGER (long)

+ * 最后的修改日期 */ public static final String MODIFIED_DATE = "modified_date"; /** * Data's content *

Type: TEXT

+ * 数据的内容 */ 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, + *

+ * used for * integer data type *

Type: INTEGER

*/ 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, + *

+ * used for * integer data type *

Type: INTEGER

*/ 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, + *

+ * used for * TEXT data type *

Type: TEXT

*/ 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, + *

+ * used for * TEXT data type *

Type: TEXT

*/ 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, + *

+ * used for * TEXT data type *

Type: TEXT

*/ 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的URI,parse方法返回的是一个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 diff --git a/doc/成员代码分析/jhw/NotesDatabaseHelper.java b/doc/成员代码分析/jhw/NotesDatabaseHelper.java index aa5a860..9eb4049 100644 --- a/doc/成员代码分析/jhw/NotesDatabaseHelper.java +++ b/doc/成员代码分析/jhw/NotesDatabaseHelper.java @@ -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 + * 在文件夹中删除note时,更新文件夹的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";//在文件夹中删除一个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} + * 当Note插入新的数据时,更新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";//在文件夹中对一个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 + * 构建一条SQL语句,用于实现在note中改变data后,进行当前状态的更新 */ - 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 + * 对根文件夹修改,先将values实例的内容清空,然后存入values,再插入对象 */ 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是什么意思 } \ No newline at end of file diff --git a/doc/成员代码分析/jhw/NotesProvider.java b/doc/成员代码分析/jhw/NotesProvider.java index 6897999..b732cd0 100644 --- a/doc/成员代码分析/jhw/NotesProvider.java +++ b/doc/成员代码分析/jhw/NotesProvider.java @@ -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); diff --git a/doc/成员代码分析/lzb/SqlNote.java b/doc/成员代码分析/lzb/SqlNote.java index 634665b..ea7c39c 100644 --- a/doc/成员代码分析/lzb/SqlNote.java +++ b/doc/成员代码分析/lzb/SqlNote.java @@ -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:用于支持小米便签最底层的数据库相关操作,和sqldata的关系上是父集关系,即note是data的子父集。 + * Description:用于支持小米便签最底层的数据库相关操作,和sqldata的关系上是父集关系,即note是data的父集。 * 和SqlData相比,SqlNote算是真正意义上的数据了。 */ - -/* - * 功能描述: - * 实现过程: - * 参数注解: - * 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 { } /* - * 功能描述:给当前id设置Gtaskid + * 功能描述:用当前id设置Gtaskid * 参数注解: * 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; } -} +} \ No newline at end of file diff --git a/doc/成员代码分析/lzb/Task.java b/doc/成员代码分析/lzb/Task.java index 7ce867f..196753b 100644 --- a/doc/成员代码分析/lzb/Task.java +++ b/doc/成员代码分析/lzb/Task.java @@ -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) { //��metadata����ʵʩ + 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; } + //获取父节点列表 } \ No newline at end of file diff --git a/doc/成员代码分析/lzb/TaskList.java b/doc/成员代码分析/lzb/TaskList.java index 9598063..d82d70d 100644 --- a/doc/成员代码分析/lzb/TaskList.java +++ b/doc/成员代码分析/lzb/TaskList.java @@ -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; } -} \ No newline at end of file + } + + 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 getChildTaskList() { + return this.mChildren; + } + + public void setIndex(int index) { + this.mIndex = index; + } + + public int getIndex() { + return this.mIndex; + } +}