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.
Dome/src1/net/micode/notes/data/NotesProvider.java

324 lines
15 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; // Android内容提供者基类
import android.content.ContentUris; // 用于操作URI如添加ID到URI中
import android.content.ContentValues; // 用于存储数据的键值对,便于数据库操作
import android.content.Intent; // 用于应用程序之间传递数据的意图
import android.content.UriMatcher; // 用于匹配URI
import android.database.Cursor; // 用于数据库查询结果集的迭代
import android.database.sqlite.SQLiteDatabase; // 用于执行SQL语句和进行数据库操作
import android.net.Uri; // 用于表示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; // 数据表名称常量
// NotesProvider类继承自ContentProvider用于提供数据共享接口
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;//用于标识笔记资源
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时调用UriMatcher(UriMatcher.NO_MATCH)表示不匹配任何路径的返回码
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 把需要匹配URI路径全部给注册上
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 + ","//笔记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;//意图数据类型
// 声明搜索查询
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
// Context只有在onCreate()中才被初始化对mHelper进行实例化
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
@Override
// 查询uri在数据库中对应的位置
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:
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) {
// getPathSegments()方法得到一个String的List
// 在uri.getPathSegments().get(1)为第2个元素
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);
}
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
@Override
// 插入一个uri
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:
insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break;
// 如果存在查找NOTE_ID
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);
}
// Notify the note uri
// notifyChange获得一个ContextResolver对象并且更新里面的内容
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的路径
return ContentUris.withAppendedId(uri, insertedId);
}
@Override
// 删除一个uri
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Uri代表要操作的数据Android上可用的每种资源 -包括 图像、视频片段、音频资源等都可以用Uri来表示。
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 that smaller than 0 is system folder which is not allowed to
* trash
*/
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);
}
if (count > 0) {
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
getContext().getContentResolver().notifyChange(uri, null);
}
return count;
}
@Override
// 更新一个uri
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0; // 记录更新的行数
String id = null; // 用于存储URI中的ID部分
SQLiteDatabase db = mHelper.getWritableDatabase(); // 获取可写的数据库实例
boolean updateData = false; // 标记是否需要更新数据表
// 根据URI匹配不同的操作
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); // 增加指定笔记的版本号
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; // 设置更新数据表的标记为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; // 设置更新数据表的标记为true
break;
default:
// 如果URI不匹配任何已知类型则抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果有行被更新则通知相关URI的监听器
if (count > 0) {
if (updateData) {
// 如果更新了数据表则通知笔记表的URI
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知当前URI的监听器
getContext().getContentResolver().notifyChange(uri, null);
}
return count; // 返回更新的行数
}
/// 将字符串解析成规定格式
private String parseSelection(String selection) {
// 如果传入的选择字符串不为空,则在 selection 前后添加 " AND (" 和 ")",否则返回空字符串
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
}
// 增加一个noteVersion
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 创建StringBuilder对象用于构建SQL语句
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE "); // 添加UPDATE关键字
sql.append(TABLE.NOTE); // 添加表名NOTE
sql.append(" SET "); // 添加SET关键字
sql.append(NoteColumns.VERSION); // 添加版本号列名
sql.append("=" + NoteColumns.VERSION + "+1 "); // 版本号列值加1
// 如果ID大于0或者选择字符串不为空则添加WHERE关键字
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
// 如果ID大于0则添加ID等于指定值的条件
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
// 如果选择字符串不为空,则添加解析后的选择字符串作为条件
if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0 ? parseSelection(selection) : selection;
// 将选择字符串中的占位符替换为实际的参数值
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
}
sql.append(selectString);
}
// 使用execSQL方法执行构建的SQL语句
mHelper.getWritableDatabase().execSQL(sql.toString());
}
@Override
public String getType(Uri uri) {
// TODO: 需要实现该方法来返回给定URI的MIME类型暂时返回null
return null;
}