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

344 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.

/*
* 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;
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 {
//初始化静态成员变量
private static final UriMatcher mMatcher;//UriMatcher用于匹配URI并根据定义的规则进行操作
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 {
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);
}//为NotesProvider中的不同URI模式分配匹配码以便在ContentProvider中根据URI执行相应的操作
/**
* 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.
*在SQLite中十六进制表示法x'0A'代表换行符'\n'。在搜索结果中,针对标题和内容,开发人员会去除换行符'\n'和空格,以便在展示信息时能够呈现更多内容,而不受这些额外字符的干扰
*/
//NOTES_SEARCH_PROJECTION这是一个字符串常量用于定义搜索结果的投影即要从数据库中检索哪些列的数据.
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;
//NOTES_SNIPPET_SEARCH_QUERY是一个字符串常量表示执行搜索时使用的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类中的onCreate()方法
@Override//这是一个注解表示这个方法是对父类ContentProvider中的方法进行重写
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
//query方法根据提供的Uri执行数据库查询操作从而提供所需的数据。它支持对不同表的查询、对单个记录的查询以及搜索功能
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder)
//query方法的声明它接收一个Uri对象、投影、选择条件、选择参数和排序顺序作为参数并返回一个Cursor对象
{
Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null;
switch (mMatcher.match(uri)) //UriMatcher来匹配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);
}
if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
//这是一个用于处理数据插入的方法。根据提供的URI它会将内容值插入相应的数据库表中。如果插入的是笔记数据它会将笔记ID返回如果插入的是数据项它会检查数据是否包含笔记ID并将其返回。最后它会通知相关URI的观察者以便更新UI
@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:
// 插入笔记数据
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 {
// 如果数据项不包含笔记ID则记录错误并打印相关数据
Log.d(TAG, "Wrong data format without note id:" + values.toString());
}
insertedId = dataId = db.insert(TABLE.DATA, null, values);
break;
default:
// 对于未知的URI抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// Notify the note uri
// 通知笔记URI
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri
// 通知数据URI
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
// 返回插入的URI
return ContentUris.withAppendedId(uri, insertedId);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0;
String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false;
switch (mMatcher.match(uri)) {
case URI_NOTE:
// 删除操作的条件确保ID大于0
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
*ID小于0的是系统文件夹不能放入回收站
* trash
*/
long noteId = Long.valueOf(id);
if (noteId <= 0) {
break;
}
// 根据指定ID执行删除操作并根据传入的条件进行筛选
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);
// 根据指定ID执行删除操作并根据传入的条件进行筛选
count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
deleteData = true;
break;
default:
// 未知的URI抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果有数据被删除
if (count > 0) {
// 如果删除的是数据表中的数据,则通知内容解析器数据已更改
if (deleteData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
// 通知内容解析器指定URI的数据已更改
getContext().getContentResolver().notifyChange(uri, null);
}
// 返回受影响的行数
return count;
}
//根据指定条件更新数据库中的数据根据uri的不同匹配到相应的表和记录并进行更新操作
@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:
// 增加笔记版本
increaseNoteVersion(-1, selection, selectionArgs);
// 执行更新操作,并获取受影响的行数
count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break;
case URI_NOTE_ITEM:
// 获取URI中的ID
id = uri.getPathSegments().get(1);
// 增加指定笔记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:
// 获取URI中的ID
id = uri.getPathSegments().get(1);
// 根据指定ID执行更新操作并根据传入的条件进行筛选
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs);
updateData = true;
break;
default:
// 未知的URI抛出异常
throw new IllegalArgumentException("Unknown URI " + uri);
}
// 如果有数据被更新
if (count > 0) {
if (updateData) {
// 如果更新的是数据表中的数据,则通知内容解析器数据已更改
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 + ')' : "");
}
//用于管理和操作笔记数据的版本号
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 构建SQL语句
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");// 更新操作
sql.append(TABLE.NOTE);// 要更新的表名
sql.append(" SET ");
sql.append(NoteColumns.VERSION);// 版本号字段
sql.append("=" + NoteColumns.VERSION + "+1 ");// 版本号自增1
// 如果存在ID或者选择条件非空则添加WHERE子句
if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE ");
}
// 如果存在ID添加ID等于指定ID的条件
if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id));
}
// 如果选择条件非空解析选择条件并添加到SQL语句中
if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0 ? parseSelection(selection) : selection;
for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args);
}
sql.append(selectString);
}
// 执行SQL语句更新数据库中笔记版本号
mHelper.getWritableDatabase().execSQL(sql.toString());
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}