Content Provider用来管理数据的集中存储库,Content Provider主要功能是使应用的数据可以被其他应用访问。
一、在实现Content Provider时,先考虑一下是否有必要使用Content Provider来管理数据。一般在满足一下几种情况下:
1. 需要为其他应用程序提供复杂的数据或者文件2. 允许其他应用程序拷贝自己的应用程序复杂数据
3. 需要提供在搜索框架下提供自己的搜索建议
另外,没有必要为自己应用实现一个Content Provider使用SQLite DataBase来管理数据。
二、如何创建一个Provider:
1. 设计原始数据,Content Provider提供两方面的数据:
a. 文件数据:如图片、视频、音频文件等,将文件保存在应用的空间中,Content Provider需要为其提供文件句柄供其他应用访问使用。
b. 结构数据,即可以保存在数据库、数组和类似结构的数据。数据将保存在一个兼容形势的表中,行表示一个实体,列表示实体的属性等。通常的做法是将这类数据保存在一个SQLite DataBase中。
2. 定义Provider的authority 、URIS和字段,如果需要Provider处理intent,定义action、extras、和flags,以及定义需要访问应用数据的权限。可以考虑将这些常量写在一个独立的类中,即Contract class。
3. 定义一个ContentProvider的子类,并实现它的方法。这个类就是ContentProvider的子类你的应用数据和其它android系统交互的接口。
4. 添加其它项,如一些示例数据、或者实现一个可以同步Provider和运数据的AbstractThreadedSyncAdapter的子类。
三、如何实现一个ContentProvider,其中上面提到1、4步忽略
2.实现Contract class
package com.example.logcontentprovider;
import android.net.Uri;
public class LogInfo {
//db info
public static final String DB_NAME = "errordb";
public static final String TABLE_ANR_NAME = "anrinfo";
public static final String TABLE_CRASH_NAME = "crashinfo";
public static final int VERSION = 1;
//column name for anr
public static String ANR_ID = "anr_id";
public static final String ANR_ACTIVITY = "anr_activity";
public static final String ANR_CAUSE = "anr_cause";
public static final String ANR_CPU = "anr_cpu";
//column name for crash
public static String CRASH_ID = "crash_id";
public static final String EXCEPTION_CLASSNAME = "exception_classname";
public static final String EXCEPTION_MESSAGE = "eccption_messge";
public static final String THROW_FILENAME = "throw_filename";
public static final String THROW_CLASSNAME = "throw_classname";
public static final String THROW_METHODNAME = "throw_methodname";
public static final String THROW_LINENUMBER = "throw_linenumber";
//define authority eg:com.example.<appname>.provider
public static final String AUTOHORITY = "com.example.logcontentprovider";
//define URIs eg: content://<authority>/<path> or content://<authority>/<path>/<id>
public static final Uri ANR_CONTENT_URI = Uri.parse("content://" + AUTOHORITY + "/" +TABLE_ANR_NAME);
public static final Uri CRASH_CONTENT_URI = Uri.parse("content://" + AUTOHORITY + "/" +TABLE_CRASH_NAME);
}
3. 定义一个ContentProvider的子类
package com.example.logcontentprovider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
public class LogContentProvider extends ContentProvider{
private static final UriMatcher sUriMatcher;
static{
sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(LogInfo.AUTOHORITY, LogInfo.TABLE_CRASH_NAME, 1);
sUriMatcher.addURI(LogInfo.AUTOHORITY, LogInfo.TABLE_CRASH_NAME + "/#", 2);
sUriMatcher.addURI(LogInfo.AUTOHORITY, LogInfo.TABLE_ANR_NAME, 3);
sUriMatcher.addURI(LogInfo.AUTOHORITY, LogInfo.TABLE_ANR_NAME + "/#", 4);
}
//create anr table
private static final String SQL_CREATE_TABLE_ANR = "CREATE TABLE "
+ LogInfo.TABLE_ANR_NAME + "(" + LogInfo.ANR_ID
+ " integer primary key autoincrement not null,"
+ LogInfo.ANR_ACTIVITY + " text," + LogInfo.ANR_CAUSE
+ " text," + LogInfo.ANR_CPU + " text);";
//create crash table
private static final String SQL_CREATE_TABLE_CRASH = "CREATE TABLE "
+ LogInfo.TABLE_CRASH_NAME + "(" + LogInfo.CRASH_ID
+ " integer primary key autoincrement not null,"
+ LogInfo.EXCEPTION_CLASSNAME + " text,"
+ LogInfo.EXCEPTION_MESSAGE + " text,"
+ LogInfo.THROW_CLASSNAME + " text,"
+ LogInfo.THROW_FILENAME + " text,"
+ LogInfo.THROW_METHODNAME + " text,"
+ LogInfo.THROW_LINENUMBER + " integer);";
private MainDatabaseHelper mOpenHelper;
private SQLiteDatabase db;
public LogContentProvider() {
// TODO Auto-generated constructor stub
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
db = mOpenHelper.getWritableDatabase();
int count = 0;
String id = "";
switch (sUriMatcher.match(uri)){
case 1:
count = db.delete(LogInfo.TABLE_CRASH_NAME, selection,
selectionArgs);
break;
case 2:
id = uri.getPathSegments().get(1);
count = db.delete(LogInfo.TABLE_CRASH_NAME, 2
+ " = "
+ id
+ (!TextUtils.isEmpty(LogInfo.CRASH_ID = "?") ? "AND("
+ selection + ')' : ""), selectionArgs);
break;
case 3:
count = db.delete(LogInfo.TABLE_ANR_NAME, selection,
selectionArgs);
break;
case 4:
id = uri.getPathSegments().get(1);
count = db.delete(LogInfo.TABLE_ANR_NAME, 2
+ " = "
+ id
+ (!TextUtils.isEmpty(LogInfo.ANR_ID = "?") ? "AND("
+ selection + ')' : ""), selectionArgs);
break;
default:
Log.e("zy", "not usfull uri = " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
db = mOpenHelper.getWritableDatabase();
long rowId = 0 ;
Uri insertUri = null;
switch (sUriMatcher.match(uri)){
case 1:
rowId = db.insert(LogInfo.TABLE_CRASH_NAME, LogInfo.CRASH_ID, values);
if(rowId > 0){
insertUri = ContentUris.withAppendedId(LogInfo.ANR_CONTENT_URI, rowId);
}
break;
case 2:
Log.e("zy", "this uri is not usfull for insert, uri = " + uri );
break;
case 3:
rowId = db.insert(LogInfo.TABLE_ANR_NAME, LogInfo.ANR_ID, values);
if(rowId > 0){
insertUri = ContentUris.withAppendedId(LogInfo.ANR_CONTENT_URI, rowId);
}
break;
case 4:
Log.e("zy", "this uri is not usfull for insert, uri = " + uri );
break;
default:
Log.e("zy", "not usfull uri = " + uri);
}
if(rowId > 0){
getContext().getContentResolver().notifyChange(insertUri, null);
}
return insertUri;
}
@Override
public boolean onCreate() {
mOpenHelper = new MainDatabaseHelper(this.getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
db = mOpenHelper.getWritableDatabase();
Cursor c = null;
String id = "";
switch (sUriMatcher.match(uri)) {
case 1:
c = db.query(LogInfo.TABLE_CRASH_NAME, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case 2:
id = uri.getPathSegments().get(1);
c = db.query(LogInfo.TABLE_CRASH_NAME, projection, LogInfo.ANR_ID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? "AND(" + selection + ')'
: ""), selectionArgs, null, null, sortOrder);
break;
case 3:
c = db.query(LogInfo.TABLE_ANR_NAME, projection, selection,
selectionArgs, null, null, sortOrder);
break;
case 4:
c = db.query(LogInfo.TABLE_ANR_NAME, projection, LogInfo.ANR_ID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? "AND(" + selection + ')'
: ""), selectionArgs, null, null, sortOrder);
break;
default:
Log.e("zy", "not usfull uri = " + uri);
}
return c;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
db = mOpenHelper.getWritableDatabase();
int count = 0;
String id = "";
switch (sUriMatcher.match(uri)) {
case 1:
count = db.update(LogInfo.TABLE_CRASH_NAME, values, selection,
selectionArgs);
break;
case 2:
id = uri.getPathSegments().get(1);
count = db.update(
LogInfo.TABLE_CRASH_NAME,
values,
LogInfo.CRASH_ID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? "AND("
+ selection + ")" : ""), selectionArgs);
break;
case 3:
count = db.update(LogInfo.TABLE_ANR_NAME, values, selection,
selectionArgs);
break;
case 4:
id = uri.getPathSegments().get(1);
count = db.update(
LogInfo.TABLE_ANR_NAME,
values,
LogInfo.ANR_ID
+ "="
+ id
+ (!TextUtils.isEmpty(selection) ? "AND("
+ selection + ")" : ""), selectionArgs);
break;
default:
Log.e("zy", "not usfull uri = " + uri);
}
return count;
}
protected static final class MainDatabaseHelper extends SQLiteOpenHelper {
public MainDatabaseHelper(Context context) {
super(context, LogInfo.DB_NAME, null, LogInfo.VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_TABLE_CRASH);
db.execSQL(SQL_CREATE_TABLE_ANR);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
}
}
}
另外:别忘了在AndroidManifest.xml文件中注册:
<provider android:name="com.example.logcontentprovider.LogContentProvider"
android:authorities="com.example.logcontentprovider"
android:permission="true">
</provider>
四、使用ContentResolver来访问ContentProvider中的数据库:
private Uri saveErrorInfo(){
ContentResolver resolver = getContentResolver();
values.put(LogInfo.EXCEPTION_CLASSNAME, “a1”);
values.put(LogInfo.EXCEPTION_MESSAGE,“a2”);
values.put(LogInfo.THROW_CLASSNAME, “a3”);
values.put(LogInfo.THROW_FILENAME, “a4”);
values.put(LogInfo.THROW_METHODNAME, “a5”);
values.put(LogInfo.THROW_LINENUMBER, “a6”);
Uri uri = Uri.parse("content://com.example.logcontentprovider/crashinfo");
return resolver.insert(uri, values); //返回insert成功后对应行的Uri eg:content://<authority>/<path>/<id>
}
成功后可以导出db文件查看到插入到数据库中的数据.
以上,即完成了一个ContentProvider的创建和使用过程。