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.
notesMT/NotesProvider.java

362 lines
16 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.

/**
* - 数据通知在数据改变时通过ContentResolver发送通知以便相关的观察者可以及时更新数据。
* - 搜索建议:支持根据关键词模糊搜索笔记的标题和内容,并提供搜索建议功能。
*/
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 {
//这段代码实现了一个ContentProvider其中包含了对数据的查询、插入、删除和更新操作
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;
// 初始化UriMatcher用于匹配不同的URI请求
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE);
mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA);
mMatcher.addURI(Notes.AUTHORITY, "data/#", URI_DATA_ITEM);
mMatcher.addURI(Notes.AUTHORITY, "search", URI_SEARCH);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, URI_SEARCH_SUGGEST);
mMatcher.addURI(Notes.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", URI_SEARCH_SUGGEST);
}
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;
/**
* 当ContentProvider被创建时调用用于初始化数据库帮助类。
*
* @return 总是返回true。
*/
@Override
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
//代码通过调用 getContext() 方法获取当前上下文,并使用
//获取一个数据库帮助类的实例将得到的数据库帮助类实例赋值给成员变量mHelper
return true;
}
/**
* 根据URI查询数据。
*
* @param uri 要查询的数据的URI。
* @param projection 要返回的列。
* @param selection 查询条件。
* @param selectionArgs 用于查询条件的参数。
* @param sortOrder 排序顺序。
* @return 返回匹配的Cursor对象。
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
//用于查询数据。接收一个Uri参数这个Uri参数用于指定要查询的数据。
// 通过查询数据库并返回一个Cursor对象可以获取到相应的数据
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
// 根据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);
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);
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");
}
if (TextUtils.isEmpty(searchString)) {
return null;
}
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;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 设置通知URI以便数据改变时可以通知
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
//查询根据不同的URI进行查询包括查询全部笔记、单个笔记、全部数据和单个数据
@Override
public Uri insert(Uri uri, ContentValues values) {
//用于插入数据。接收一个Uri参数和一个ContentValues参数用于指定要插入的数据。
//通过将数据插入到数据库中并返回新插入数据的Uri可以实现数据的插入操作
SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0;
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)) {
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改变
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
return ContentUris.withAppendedId(uri, insertedId);
}//插入插入新的笔记或数据到数据库中并返回插入数据的URI。
/**
* 根据URI删除数据。
*
* @param uri 要删除数据的URI。
* @param selection 删除条件。
* @param selectionArgs 用于删除条件的参数。
* @return 返回被删除的行数。
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
//用于删除数据。它接收一个Uri参数和一个可选的Selection和SelectionArgs参数用于指定要删除的数据。
//通过在数据库中执行删除操作,并返回受影响的行数,可以实现数据的删除操作。
int count = 0;
String id = null;
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);
/**
* ID小于等于0的笔记是系统文件夹不允许删除
*/
long noteId = Long.valueOf(id);
if (noteId <= 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);
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) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
//删除:删除符合条件的笔记或数据,并返回被删除的行数。
/**
* 更新数据库中的数据。
*
* @param uri 要更新数据的URI。
* @param values 要更新到的数据。
* @param selection 更新条件。
* @param selectionArgs 用于更新条件的参数。
* @return 返回被更新的行数。
*/
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
//用于更新数据。接收一个Uri参数、一个ContentValues参数和一个可选的Selection和SelectionArgs参数用于指定要更新的数据和更新条件。
//通过在数据库中执行更新操作,并返回受影响的行数,可以实现数据的更新操作
int count = 0;
String id = null;
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);
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
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);
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) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
/**
* 解析选择条件,如果存在选择条件,则在条件前后添加" AND (" 和 ')'。
*
* @param selection 用户提供的选择条件。
* @return 如果有选择条件,则返回添加了定界符的选择条件字符串;否则返回空字符串。
*/
private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
/**
* 增加指定笔记的版本号。
*
* @param id 笔记的ID如果为正数则根据ID更新版本号如果为0或负数则根据selection参数更新版本号。
* @param selection 用于选择需要更新的笔记的条件字符串,可以为空。
* @param selectionArgs 与selection参数配合使用的参数数组用于替换selection中的"?"。
*/
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
sql.append(TABLE.NOTE);
sql.append(" SET ");
sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 ");
// 根据ID或选择条件构建SQL的WHERE子句
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0 ? parseSelection(selection) : selection;
// 替换selection中的"?"为selectionArgs中的对应参数
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
}
sql.append(selectString);
}
mHelper.getWritableDatabase().execSQL(sql.toString());
}
/**
* 根据URI获取对应的MIME类型。
* 本方法是个待实现的方法当前仅返回null。
*
* @param uri 请求的URI。
* @return 返回null表示该方法尚未实现。
*/
@Override
public String getType(Uri uri) {
//用于获取数据的类型。
// TODO Auto-generated method stub
return null;
}
}