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

347 lines
18 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.
* 总体分析
这段 Java 代码定义了NotesProvider类它继承自ContentProvider是安卓应用中用于在不同组件间共享数据的重要组件在笔记应用里充当数据提供者的角色。通过UriMatcher对不同的Uri进行匹配以此来区分是对笔记表note表、数据表data表进行查询、插入、删除、更新等操作还是处理搜索及搜索建议相关的逻辑并且在操作数据后会根据情况发送数据变更通知以保证相关组件能及时知晓数据的变化整体实现了数据在应用内的统一管理与共享交互功能。
函数分析
NotesProvider类构造函数相关静态代码块部分
所属类NotesProvider
功能在静态代码块中初始化UriMatcher对象mMatcher向其中添加不同的Uri匹配规则涵盖了笔记表、数据表、搜索以及搜索建议对应的Uri模式例如匹配笔记表的Uri"note"对应URI_NOTE匹配笔记表中单个记录的Uri"note/#"对应URI_NOTE_ITEM等用于后续根据传入的Uri准确判断操作类型及对应的表。
onCreate方法
所属类NotesProvider
功能重写了父类ContentProvider的onCreate方法在内容提供者被创建时调用通过NotesDatabaseHelper的单例模式获取数据库帮助类实例mHelper并返回true表示创建成功用于初始化与数据库相关的操作对象为后续数据库操作做准备。
query方法
所属类NotesProvider
功能重写了父类的query方法用于处理数据查询操作。首先获取可读数据库对象然后根据UriMatcher对传入Uri的匹配结果分情况处理
若匹配到URI_NOTE则对笔记表执行查询操作若匹配到URI_NOTE_ITEM则先获取Uri路径中的记录ID再对笔记表中指定ID的记录进行查询。
对于URI_DATA和URI_DATA_ITEM类似地分别对数据表进行全表查询以及对数据表中指定ID的记录查询查询时会结合传入的投影projection、选择条件selection等参数构建查询语句。
当匹配到URI_SEARCH或URI_SEARCH_SUGGEST时先获取搜索字符串若为空则返回null否则格式化搜索字符串后执行自定义的搜索查询语句NOTES_SNIPPET_SEARCH_QUERY获取搜索结果游标。最后若游标不为null设置其通知Uri以便数据变化时能收到通知最终返回游标用于获取查询到的数据整体实现了根据不同Uri进行对应数据查询的功能。
insert方法
所属类NotesProvider
功能重写了父类的insert方法用于处理数据插入操作。获取可写数据库对象后根据UriMatcher对传入Uri的匹配结果分情况插入数据
若匹配到URI_NOTE则向笔记表插入数据并记录插入的记录IDnoteId
若匹配到URI_DATA先获取所属笔记ID若不存在则记录日志提示错误数据格式再向数据表插入数据并记录插入的记录IDdataId。插入成功后根据插入的ID是否大于0分别向笔记表对应的ContentUriNotes.CONTENT_NOTE_URI和数据表对应的ContentUriNotes.CONTENT_DATA_URI发送数据变更通知最后返回插入数据后对应Uri通过ContentUris.withAppendedId构建整体实现了向不同表插入数据并发送相应通知的功能。
delete方法
所属类NotesProvider
功能重写了父类的delete方法用于处理数据删除操作。获取可写数据库对象后按照UriMatcher对传入Uri的匹配结果分情况删除数据
对于URI_NOTE添加额外条件确保ID大于0避免删除系统文件夹等情况后删除笔记表中的记录。
对于URI_NOTE_ITEM获取Uri路径中的记录ID判断ID合法大于0后删除对应笔记记录。
对于URI_DATA和URI_DATA_ITEM分别删除数据表中的记录以及数据表中指定ID的记录同时标记是否删除的数据表相关deleteData变量。若删除的记录数大于0根据是否与数据表相关向相应的Uri笔记表Uri或操作对应的Uri发送数据变更通知最后返回删除的记录数量整体实现了按不同Uri删除对应数据并发送通知的功能。
update方法
所属类NotesProvider
功能重写了父类的update方法用于处理数据更新操作。获取可写数据库对象后依据UriMatcher对传入Uri的匹配结果分情况更新数据
对于URI_NOTE和URI_NOTE_ITEM分别更新笔记表中的记录以及笔记表中指定ID的记录更新前会调用increaseNoteVersion方法增加笔记版本号然后执行更新操作并根据更新的记录数判断是否发送数据变更通知向笔记表Uri或操作对应的Uri
对于URI_DATA和URI_DATA_ITEM类似地更新数据表中的记录以及数据表中指定ID的记录并标记是否更新的数据表相关updateData变量根据更新记录数情况发送相应的通知最后返回更新的记录数量整体实现了按不同Uri更新对应数据并发送通知的功能。
parseSelection方法
所属类NotesProvider
功能接收一个选择条件字符串selection判断其不为空时在其前后添加" AND ("和")",用于将传入的选择条件和已有的查询条件进行合理拼接,辅助其他数据库操作方法构建完整准确的查询、删除、更新等操作的条件语句。
increaseNoteVersion方法
所属类NotesProvider
功能构建一个用于更新笔记表中版本号NoteColumns.VERSION的SQL语句根据传入的笔记IDid以及选择条件selection、选择条件参数selectionArgs来确定WHERE子句的内容然后通过数据库帮助类获取可写数据库对象并执行该SQL语句用于在更新笔记相关数据时增加笔记的版本号保证数据版本管理的一致性。
getType方法
所属类NotesProvider
功能重写了父类的getType方法目前方法体为空按照ContentProvider规范该方法应该返回对应Uri所代表的数据的MIME类型不过此处尚未实现具体逻辑可能需要根据实际需求补充代码来准确返回不同Uri对应的数据类型信息。
*/
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;
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);
}
/**
* 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 + ","
+ "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
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;
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);
}
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;
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);
}
// 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);
}
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:
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
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:
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);
}
if (count > 0) {
if (updateData) {
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
}
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) {
StringBuilder sql = new StringBuilder(120);
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)) {
sql.append(" WHERE ");
}
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);
}
mHelper.getWritableDatabase().execSQL(sql.toString());
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
}