diff --git a/src/mi_note/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java b/src/mi_note/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java index ac83138..78a62b9 100644 --- a/src/mi_note/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java +++ b/src/mi_note/app/src/main/java/net/micode/notes/data/NotesDatabaseHelper.java @@ -264,7 +264,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete"); db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash"); - // 重新创建标签表的触发器 + // 重新创建便签表的触发器 db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER); db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER); diff --git a/src/mi_note/app/src/main/java/net/micode/notes/data/NotesProvider.java b/src/mi_note/app/src/main/java/net/micode/notes/data/NotesProvider.java index ff92e9c..faa5b85 100644 --- a/src/mi_note/app/src/main/java/net/micode/notes/data/NotesProvider.java +++ b/src/mi_note/app/src/main/java/net/micode/notes/data/NotesProvider.java @@ -41,21 +41,30 @@ import net.micode.notes.data.NotesDatabaseHelper.TABLE; * 描述:NotesProvider 便签内容提供者 */ public class NotesProvider extends ContentProvider { + // Uri匹配器 private static final UriMatcher mMatcher; + // 数据库帮助类对象 private NotesDatabaseHelper mHelper; private static final String TAG = "NotesProvider"; + // 便签 private static final int URI_NOTE = 1; + // 便签项 private static final int URI_NOTE_ITEM = 2; + // 数据 private static final int URI_DATA = 3; + // 数据项 private static final int URI_DATA_ITEM = 4; + // 搜索 private static final int URI_SEARCH = 5; + // 搜索建议 private static final int URI_SEARCH_SUGGEST = 6; static { + // 初始化UriMatcher mMatcher = new UriMatcher(UriMatcher.NO_MATCH); mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); @@ -70,6 +79,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. */ + // 查询映射,对查询信息进行修剪,去掉换行符和空白字符 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 + "," @@ -78,6 +88,7 @@ public class NotesProvider extends ContentProvider { + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + // 查询便签内容的SQL语句,便签内容作为查询条件 private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION + " FROM " + TABLE.NOTE + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" @@ -86,37 +97,50 @@ public class NotesProvider extends ContentProvider { @Override public boolean onCreate() { + // 获取便签数据库帮助类的实例 mHelper = NotesDatabaseHelper.getInstance(getContext()); return true; } + /** + * 查询的方法 + * @param uri 内容Uri + * @param projection 查询映射 + * @param selection 查询条件 + * @param selectionArgs 要填充的参数 + * @param sortOrder 排序方式 asc:升序,desc:降序 + * @return cursor游标 + */ @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor c = null; SQLiteDatabase db = mHelper.getReadableDatabase(); String id = null; + // 根据uri执行对应的操作 switch (mMatcher.match(uri)) { - case URI_NOTE: + case URI_NOTE: // 查询便签 c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, sortOrder); break; - case URI_NOTE_ITEM: + case URI_NOTE_ITEM: // 查询便签项 指定了便签ID id = uri.getPathSegments().get(1); c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; - case URI_DATA: + case URI_DATA: // 查询数据 c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, sortOrder); break; - case URI_DATA_ITEM: + case URI_DATA_ITEM: // 查询数据项,指定了数据ID id = uri.getPathSegments().get(1); c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs, null, null, sortOrder); break; + // 搜索与搜索建议 case URI_SEARCH: case URI_SEARCH_SUGGEST: + // 不能指定排序方式和查询映射 if (sortOrder != null || projection != null) { throw new IllegalArgumentException( "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); @@ -124,10 +148,13 @@ public class NotesProvider extends ContentProvider { String searchString = null; if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { + // 搜索建议 if (uri.getPathSegments().size() > 1) { searchString = uri.getPathSegments().get(1); } } else { + // 搜索 + // 获取查询参数pattern searchString = uri.getQueryParameter("pattern"); } @@ -136,68 +163,93 @@ public class NotesProvider extends ContentProvider { } try { + // 格式化查询字符串,即 xxx --> %xxx% searchString = String.format("%%%s%%", searchString); + // 执行查询SQL语句 c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, new String[] { searchString }); } catch (IllegalStateException ex) { Log.e(TAG, "got exception: " + ex.toString()); } break; - default: + default: // 未知的Uri,爬出异常 throw new IllegalArgumentException("Unknown URI " + uri); } - if (c != null) { + if (c != null) { // 查询结果不为空 + // 监视内容Uri的更改 c.setNotificationUri(getContext().getContentResolver(), uri); } return c; } + /** + * 插入数据或便签的方法 + * @param uri 内容Uri + * @param values 要插入的内容 + * @return uri + */ @Override public Uri insert(Uri uri, ContentValues values) { + // 获取可写数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); long dataId = 0, noteId = 0, insertedId = 0; switch (mMatcher.match(uri)) { - case URI_NOTE: + case URI_NOTE: // 要插入的是便签 insertedId = noteId = db.insert(TABLE.NOTE, null, values); break; - case URI_DATA: + case URI_DATA: // 要插入的是数据 + // 插入数据时,values需要包含便签ID if (values.containsKey(DataColumns.NOTE_ID)) { + // 获取便签ID noteId = values.getAsLong(DataColumns.NOTE_ID); } else { Log.d(TAG, "Wrong data format without note id:" + values.toString()); } insertedId = dataId = db.insert(TABLE.DATA, null, values); break; - default: + default: // 未知的Uri throw new IllegalArgumentException("Unknown URI " + uri); } // Notify the note uri if (noteId > 0) { + // 通知内容解析器便签发生了更改 getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); } // Notify the data uri if (dataId > 0) { + // 通知内容解析器数据发生了更改 getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); } + // 原来的uri添加id insertedId return ContentUris.withAppendedId(uri, insertedId); } + /** + * 删除数据或便签的方法 + * @param uri 内容Uri + * @param selection 删除的条件 + * @param selectionArgs 填充到删除条件的参数 + * @return 影响的数据库表行数 + */ @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count = 0; String id = null; + // 获取可写数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); + // 记录是否删除了数据,没删除为false boolean deleteData = false; switch (mMatcher.match(uri)) { - case URI_NOTE: + case URI_NOTE: // 要删除便签 + // 保证便签ID大于0,防止删除特殊的记录,如根文件夹、临时文件夹、垃圾文件夹 selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; count = db.delete(TABLE.NOTE, selection, selectionArgs); break; - case URI_NOTE_ITEM: + case URI_NOTE_ITEM: // 要删除指定ID的便签 id = uri.getPathSegments().get(1); /** * ID that smaller than 0 is system folder which is not allowed to @@ -205,26 +257,30 @@ public class NotesProvider extends ContentProvider { */ long noteId = Long.valueOf(id); if (noteId <= 0) { + // 便签ID小于0的系统文件夹不能被删除 break; } + // 执行删除SQL语句 count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; - case URI_DATA: + case URI_DATA: // 要删除数据 count = db.delete(TABLE.DATA, selection, selectionArgs); deleteData = true; break; - case URI_DATA_ITEM: + case URI_DATA_ITEM: // 要删除指定ID的数据 + // 获取数据ID id = uri.getPathSegments().get(1); count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); deleteData = true; break; - default: + default: // 未知的Uri throw new IllegalArgumentException("Unknown URI " + uri); } if (count > 0) { if (deleteData) { + // 删除了数据,通知内容解析器 便签内容发生了改变 getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } getContext().getContentResolver().notifyChange(uri, null); @@ -232,58 +288,84 @@ public class NotesProvider extends ContentProvider { return count; } + /** + * 更新便签或数据的方法 + * @param uri 内容Uri + * @param values 要更新的内容 + * @param selection 更新条件 + * @param selectionArgs 填充更新条件的参数 + * @return 影响的数据库表行数 + */ @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + // 记录影响的行数 int count = 0; String id = null; + // 获取可写的数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); + // 记录数据表是否发生了变化 boolean updateData = false; switch (mMatcher.match(uri)) { - case URI_NOTE: + case URI_NOTE: // 要更新便签 + // 临时文件夹版本号加1 increaseNoteVersion(-1, selection, selectionArgs); count = db.update(TABLE.NOTE, values, selection, selectionArgs); break; - case URI_NOTE_ITEM: + case URI_NOTE_ITEM: // 要更新指定ID的便签项 + // 获取便签ID id = uri.getPathSegments().get(1); + // 便签的版本号加1 increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); break; - case URI_DATA: + case URI_DATA: // 要更新数据 count = db.update(TABLE.DATA, values, selection, selectionArgs); updateData = true; break; - case URI_DATA_ITEM: + case URI_DATA_ITEM: // 要更新指定ID的数据项 id = uri.getPathSegments().get(1); count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); updateData = true; break; - default: + default: // 未知的Uri throw new IllegalArgumentException("Unknown URI " + uri); } if (count > 0) { if (updateData) { + // 如果更新了data表,那么通知内容解析器note内容发生了改变 getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); } + // 通知uri内容发生了改变 getContext().getContentResolver().notifyChange(uri, null); } + // 返回更新操作影响的行数 return count; } + // 解析查询条件 private String parseSelection(String selection) { return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + /** + * 增加指定便签项的版本号的方法 + * @param id 便签ID + * @param selection 更新条件 + * @param selectionArgs 填充条件的参数 + */ private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); sql.append(TABLE.NOTE); + // 将version字段加1 sql.append(" SET "); sql.append(NoteColumns.VERSION); sql.append("=" + NoteColumns.VERSION + "+1 "); + // 如果ID不为空或者条件不为空,sql语句增加更新条件where if (id > 0 || !TextUtils.isEmpty(selection)) { sql.append(" WHERE "); } @@ -291,13 +373,16 @@ public class NotesProvider extends ContentProvider { sql.append(NoteColumns.ID + "=" + String.valueOf(id)); } if (!TextUtils.isEmpty(selection)) { + // 处理更新条件,如果id>0,前面添加AND,否则不添加 String selectString = id > 0 ? parseSelection(selection) : selection; for (String args : selectionArgs) { + // 填充占位符? selectString = selectString.replaceFirst("\\?", args); } sql.append(selectString); } + // 执行SQL语句 mHelper.getWritableDatabase().execSQL(sql.toString()); } diff --git a/src/mi_note/app/src/main/java/net/micode/notes/model/Note.java b/src/mi_note/app/src/main/java/net/micode/notes/model/Note.java index 6706cf6..a3bbe22 100644 --- a/src/mi_note/app/src/main/java/net/micode/notes/model/Note.java +++ b/src/mi_note/app/src/main/java/net/micode/notes/model/Note.java @@ -34,6 +34,12 @@ import net.micode.notes.data.Notes.TextNote; import java.util.ArrayList; +/** + * @author hzx + * 版本:1.0 + * 创建日期:2023/10/28 + * 描述:Note + */ public class Note { private ContentValues mNoteDiffValues; private NoteData mNoteData;