You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomibianqian/NotesProvider.java

296 lines
13 KiB

This file contains ambiguous Unicode characters!

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

package net.micode.notes.data;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
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;
public class NotesProvider extends ContentProvider {
// 定义 UriMatcher 以匹配不同的 URI
private static final UriMatcher mMatcher;
// 数据库帮助类的实例
private NotesDatabaseHelper mHelper;
private static final String TAG = "NotesProvider"; // 日志标签
// 定义 URI 常量
private static final int URI_NOTE = 1; // 笔记 URI
private static final int URI_NOTE_ITEM = 2; // 单个笔记项 URI
private static final int URI_DATA = 3; // 数据 URI
private static final int URI_DATA_ITEM = 4; // 单个数据项 URI
private static final int URI_SEARCH = 5; // 搜索 URI
private static final int URI_SEARCH_SUGGEST = 6; // 搜索建议 URI
// 静态初始化块,初始化 UriMatcher
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); // 匹配笔记 URI
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); // 匹配单个笔记项 URI
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); // 匹配数据 URI
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM); // 匹配单个数据项 URI
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH); // 匹配搜索 URI
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST); // 匹配搜索建议 URI
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST); // 匹配带参数的搜索建议 URI
}
/**
* x'0A' 表示 SQLite 中的换行符 '\n'。对于搜索结果中的标题和内容,
* 我们将修剪 '\n' 和空白,以显示更多信息。
*/
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 + ","
+ "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + ","
+ 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;
// 用于搜索笔记的 SQL 查询语句
private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION
+ " FROM " + TABLE.NOTE // 从笔记表中选择
+ " WHERE " + NoteColumns.SNIPPET + " LIKE ?" // 根据摘要搜索
+ " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER // 排除垃圾箱中的笔记
+ " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; // 确保笔记类型是常规笔记
@Override
public boolean onCreate() {
// 初始化数据库助手
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true; // 返回成功创建
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null; // 声明游标
SQLiteDatabase db = mHelper.getReadableDatabase(); // 获取可读数据库
String id = null; // 声明 ID 变量
// 根据 URI 匹配执行不同的查询
switch (mMatcher.match(uri)) {
case URI_NOTE: // 查询所有笔记
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_NOTE_ITEM: // 查询单个笔记项
id = uri.getPathSegments().get(1); // 获取 URI 中的 ID
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);
break;
case URI_DATA: // 查询所有数据
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder);
break;
case URI_DATA_ITEM: // 查询单个数据项
id = uri.getPathSegments().get(1); // 获取 URI 中的 ID
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");
}
String searchString = null; // 声明搜索字符串
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
// 获取搜索建议中的搜索字符串
if (uri.getPathSegments().size() > 1) {
searchString = uri.getPathSegments().get(1);
}
} else {
// 获取查询参数中的模式
searchString = uri.getQueryParameter("pattern");
}
// 如果搜索字符串为空,返回 null
if (TextUtils.isEmpty(searchString)) {
return null;
}
try {
// 格式化搜索字符串以用于 LIKE 查询
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;
default:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知 URI 异常
}
// 设置通知 URI
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c; // 返回结果游标
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库
long dataId = 0, noteId = 0, insertedId = 0; // 声明 ID 变量
switch (mMatcher.match(uri)) {
case URI_NOTE: // 插入新笔记
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
case URI_DATA: // 插入新数据
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:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知 URI 异常
}
// 通知笔记 URI 更新
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// 通知数据 URI 更新
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
return ContentUris.withAppendedId(uri, insertedId); // 返回插入的 URI
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0; // 记录受影响行数
String id = null; // 声明 ID 字符串
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库
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: // 删除单个笔记项
id = uri.getPathSegments().get(1); // 获取 URI 中的 ID
long noteId = Long.valueOf(id);
if (noteId <= 0) { // 系统文件夹 ID 小于等于 0不允许删除
break;
}
count = db.delete(TABLE.NOTE, NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break;
case URI_DATA: // 删除所有数据
count = db.delete(TABLE.DATA, selection, selectionArgs); // 执行删除操作
deleteData = true;
break;
case URI_DATA_ITEM: // 删除单个数据项
id = uri.getPathSegments().get(1); // 获取 URI 中的 ID
count = db.delete(TABLE.DATA, DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知 URI 异常
}
if (count > 0) {
if (deleteData) { // 如果删除了数据项,通知笔记 URI 更新
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null); // 通知 URI 更新
}
return count; // 返回受影响行数
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0; // 记录受影响行数
String id = null; // 声明 ID 字符串
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写数据库
boolean updateData = false; // 是否更新数据项标志
switch (mMatcher.match(uri)) {
case URI_NOTE: // 更新所有笔记
increaseNoteVersion(-1, selection, selectionArgs); // 增加笔记版本号
count = db.update(TABLE.NOTE, values, selection, selectionArgs); // 执行更新操作
break;
case URI_NOTE_ITEM: // 更新单个笔记项
id = uri.getPathSegments().get(1); // 获取 URI 中的 ID
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); // 根据 ID 增加笔记版本号
count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs); // 执行更新操作
break;
case URI_DATA: // 更新所有数据
count = db.update(TABLE.DATA, values, selection, selectionArgs); // 执行更新操作
updateData = true;
break;
case URI_DATA_ITEM: // 更新单个数据项
id = uri.getPathSegments().get(1); // 获取 URI 中的 ID
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs); // 执行更新操作
updateData = true;
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri); // 未知 URI 异常
}
if (count > 0) {
if (updateData) { // 如果更新了数据项,通知笔记 URI 更新
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null); // 通知 URI 更新
}
return count; // 返回受影响行数
}
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); // 解析限制条件
}
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120); // 构建 SQL 语句
sql.append("UPDATE "); // 更新操作
sql.append(TABLE.NOTE); // 笔记表
sql.append(" SET ");
sql.append(NoteColumns.VERSION); // 增加版本号操作
sql.append("=" + NoteColumns.VERSION + "+1 ");
if (id > 0 || !TextUtils.isEmpty(selection)) { // 如果指定了 ID 或选择条件,添加限制条件
sql.append(" WHERE ");
}
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id)); // 添加 ID 等于指定值的限制
}
if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0 ? parseSelection(selection) : selection; // 解析限制条件
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args); // 替换参数中的占位符
}
sql.append(selectString); // 添加限制条件
}
mHelper.getWritableDatabase().execSQL(sql.toString()); // 执行 SQL 语句
}
@Override
public String getType(Uri uri) {
return null; // 返回类型为 null
}