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

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

/*
* 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;
/*1. 便签信息提供类该类继承于ContentProvider类由此可见该类主要用于数据的提供的功能供其他模块实现相当于对便签信息的管理该类定义了相关的UriMathcher用于匹配Uri使数据管理更加安全并定义了一些列的方法对该软件创建的数据库进行管理例如,OnCreate, queryinsertupdate, parseSelection等方法用于对被选中的数据对象进行相关的删除插入更新等操作实现对数据库的管理为上层的使用提供了一个较好的接口对数据库信息进行抽象。*/
public class NotesProvider extends ContentProvider {
private static final UriMatcher mMatcher;//UriMatcher是Android提供的用来操作Uri的工具类
private NotesDatabaseHelper mHelper;//创建数据库帮助类实体对象
private static final String TAG = "NotesProvider";//该类的自定义标签
//1-6都是uri资源的id
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模块中只初始化一次提高运行速度以及减少空间浪费。将各个Uri与其代号关联在一起
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);//创建uri工具类实例对象
//注册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);
//SUGGEST_URI_PATH_QUERY 并不属于URI的一部分而应是用于指向此路径的常量
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.
*/
//声明 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;
//note搜索查询
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;
//创建一个便签数据库助手mHelper
public boolean onCreate() {
mHelper = NotesDatabaseHelper.getInstance(getContext());
return true;
}
//查询uri在数据库中对应的位置
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
Cursor c = null;//函数返回对象
/*getReadableDatabase()方法是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。如果该问题成功解决,则只读数据库对象就会关闭,然后返回一个可读写的数据库对象。*/
SQLiteDatabase db = mHelper.getReadableDatabase();//向数据库读操作
String id = null;
switch (mMatcher.match(uri)) {
case URI_NOTE://匹配到标签的uri
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder);//查询的表返回列行如何分组过滤条件,数据库查询语句
break;
case URI_NOTE_ITEM://匹配到标签条目
id = uri.getPathSegments().get(1);//匹配到列表中便签项的路径中的1号字符
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder);//查询的表返回列行如何分组过滤条件,数据库查询语句
break;
case URI_DATA://匹配到数据的uri
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder);//查询的表返回列行如何分组过滤条件,数据库查询语句
break;
case URI_DATA_ITEM://匹配到数据条目
id = uri.getPathSegments().get(1);//匹配到列表中数据项的路径中的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) {
//如果sortOrder或projection不为空抛出错误
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 {
//小于1则取第零个元素
searchString = uri.getQueryParameter("pattern");
}
if (TextUtils.isEmpty(searchString)) {
//如果路径为空则返回空
return null;
}
try {
/*通过上文得到的搜索字符串进行格式加工而后通过rawQuery直接在“NOTES_SNIPPET_SEARCH_QUERY”数据库中搜索ID=searchString的对应信息串。*/
searchString = String.format("%%%s%%", searchString);
/*cursor = db.rawQuery("select name from *** where id=?", new String[]{"1"});*/
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) {
//若getContentResolver发生变化就接收通知
c.setNotificationUri(getContext().getContentResolver(), uri);
}
return c;
}
//插入一个新的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);//向note表插入一个uri
break;
case URI_DATA:
if (values.containsKey(DataColumns.NOTE_ID)) {//如果数据包含主键
noteId = values.getAsLong(DataColumns.NOTE_ID);//转换为long型
} else {
Log.d(TAG, "Wrong data format without note id:" + values.toString());//信息不含主键抛出异常错误
}
insertedId = dataId = db.insert(TABLE.DATA, null, values);//向数据表插入一个uri
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);//不匹配的uri
}
// Notify the note uri报告note id
if (noteId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
}
// Notify the data uri报告data id
if (dataId > 0) {
getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
}
return ContentUris.withAppendedId(uri, insertedId);//返回插入uri的路径
}
//删除一个uri
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 ";//要删除的note的信息
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) {
// 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);
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;//返回删除数量
}
//更新一个uri
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);//获取该item的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;
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;//返回更新的数量
}
private String parseSelection(String selection) {
//如果selection不是空字符那么返回" AND (" + 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) {//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()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句
mHelper.getWritableDatabase().execSQL(sql.toString());
}
@Override
public String getType(Uri uri) {//获取uri的数据类型实际永远返回null
// TODO Auto-generated method stub
return null;
}
}