Android提供ContentProvider向外界提供数据以及修改数据的方法,以达到应用之间的数据共享。使用ContentProvider进行数据共享的好处在于使用数据者不需要知道数据提供者是以何种方式进行数据存储的,只需要通过数据提供者所提供出来的同一方法即可达到共享数据、操作数据的目的!下面以一个小例子来具体说明是怎么实现的:
数据提供者:
继承ContentProvider
定义访问者URI路径,向外界暴露出真删改查方法
URI形如:content:\\niko.android.demopro/provider/10,其具体组成部分分4部分:
1、scheme:content:\\
2、authority:用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它,如niko.android.demo
3、path:可以用来表示我们要操作的数据,路径的构建应根据业务而定,如 /provider
4、ID:如果没有ID,即表示是对数据整个的访问,有的话就是对具体一些数据的访问,如/10(对于本例就是tid=10的数据)
一般在ContentProvider应用中,需要定义一个常量类来管理URI中一些常量,比如authority,path等,本文的常量类为ConstantsUtil类,因为本例是以Sqlite进行数据存储,所以该常量类中还包括了表的一些结构常量,如表名,字段,版本号等常量。
/**
* 常量类,保存的是数据库表字段名 以及 uri相关
*/
public class ConstantsUtil {
public static final String TABLE = "userinfos";
public static String TID = "tid";
public static final String USERNAME = "username";
public static final String SEX = "sex";
public static final int VERSION = 8;
public static final String SCHEME = "content://";
//authority必须与manifest中配置一致,其作用是解析该uri时可以找到对应的ContentProvider
public static final String AUTHORITY = "niko.android.demo";
public static final String PATH = "provider";
public static final Uri CONTENT_URI = Uri.parse(SCHEME + AUTHORITY + "/"+PATH);
//Mime类型所对应的匹配码
public static final int CODE_ALL_DATA = 1;
public static final int CODE_SPECIFIC_DATA = 2;
//Mime类型
public static final String CONTENT_ALL_TYPE = "vnd.android.cursor.item/"+"android.provider.demo";//单一数据
public static final String CONTENT_SPECIFIC_TYPE = "vnd.android.cursor.dir/"+"android.provider.demo";//多项数据
}
public class MyProvider extends ContentProvider {
private static final String TAG = "provider";
private Context mContext;
private DbHelper helper;
private SQLiteDatabase database;
private static final UriMatcher uriMatcher;
//添加URI匹配
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(ConstantsUtil.AUTHORITY, ConstantsUtil.PATH, ConstantsUtil.CODE_ALL_DATA);
uriMatcher.addURI(ConstantsUtil.AUTHORITY, ConstantsUtil.PATH+"/#", ConstantsUtil.CODE_SPECIFIC_DATA);
}
@Override
public boolean onCreate() {
//外界调用ContentResolver时调用
mContext = this.getContext();
helper = new DbHelper(mContext);
return true;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
case ConstantsUtil.CODE_ALL_DATA:
return ConstantsUtil.CONTENT_ALL_TYPE;
case ConstantsUtil.CODE_SPECIFIC_DATA:
return ConstantsUtil.CONTENT_SPECIFIC_TYPE;
default:
throw new IllegalArgumentException("Unknown URI"+uri);
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
database = helper.getWritableDatabase();
long rowId = database.insert(ConstantsUtil.TABLE,"",values);
Uri noteUri = ContentUris.withAppendedId(ConstantsUtil.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
database = helper.getWritableDatabase();
int count = 0;
switch (uriMatcher.match(uri)) {
case ConstantsUtil.CODE_ALL_DATA:
count = database.delete(ConstantsUtil.TABLE, selection, selectionArgs);
break;
case ConstantsUtil.CODE_SPECIFIC_DATA:
//uri.getPathSegments()得到一个集合,内容分别为 uri的path和_id 即 [provider , _id]
String id = uri.getPathSegments().get(1);
count = database.delete(ConstantsUtil.TABLE, ConstantsUtil.TID+"="+id+(!TextUtils.isEmpty(selection)?" AND("+selection+')':""),selectionArgs);
break;
default:
throw new IllegalArgumentException("Unknown URI"+uri);
}
//getContext().getContentResolver().notifyChange(uri, null);
return count;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int count = 0;
database = helper.getWritableDatabase();
count = database.update(ConstantsUtil.TABLE, values, selection, selectionArgs);
/*getContext().getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()){
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
}
});*/
return count;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
database = helper.getReadableDatabase();
Cursor c = null;
switch (uriMatcher.match(uri)) {
case ConstantsUtil.CODE_ALL_DATA:
c = database.query(ConstantsUtil.TABLE, projection, selection, selectionArgs, null, null, null);
break;
case ConstantsUtil.CODE_SPECIFIC_DATA:
//uri.getPathSegments()得到一个集合,内容分别为 uri的path和_id 即 [provider , _id]
String id = uri.getPathSegments().get(1);
c = database.query(ConstantsUtil.TABLE, projection, ConstantsUtil.TID+"="+id+(!TextUtils.isEmpty(selection)?" AND("+selection+')':""),selectionArgs, null, null, sortOrder);
break;
default:
throw new IllegalArgumentException("Unknown URI"+uri);
}
return c;
}
}
public class DbHelper extends SQLiteOpenHelper {
private static final String TAG = "";
public DbHelper(Context context){
super(context, ConstantsUtil.TABLE, null, ConstantsUtil.VERSION);
}
public DbHelper(Context context, String name, CursorFactory factory,
int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table "+ConstantsUtil.TABLE+"(" +
ConstantsUtil.TID+" integer primary key autoincrement not null,"+
ConstantsUtil.USERNAME+" text not null," +
ConstantsUtil.SEX+" text not null);");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS "+ConstantsUtil.TABLE);
onCreate(db);
}
public void add(String username,String sex){
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(ConstantsUtil.USERNAME, username);
values.put(ConstantsUtil.SEX, sex);
db.insert(ConstantsUtil.TABLE, "", values);
}
}
在同一个应用中访问ContentProvider提供的数据:
public class ContentProviderDemoActivity extends Activity {
private DbHelper helper;
private ContentResolver contentResolver;
private TextView tv;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView)findViewById(R.id.tv);
helper = new DbHelper(this);
helper.add("ZhangJin", "男");
helper.add("Niko", "男");
helper.add("Lucy", "女");
contentResolver = this.getContentResolver();
Cursor cursor = contentResolver.query(
ConstantsUtil.CONTENT_URI,
new String[] {
ConstantsUtil.TID,
ConstantsUtil.USERNAME,
ConstantsUtil.SEX },
null, null, null);
while (cursor.moveToNext()) {
String text = "tid : "+cursor.getString(0)+" , name : "+cursor.getString(1)+" , sex : "+cursor.getString(2);
tv.append(text+"\n");
}
startManagingCursor(cursor); //查找后关闭游标
}
}
在另一个应用中访问数据并且操作数据(把那个ConstantsUtil常量工具类copy到另一个工程中)
public class ContentResolverDemoActivity extends Activity {
private ContentResolver contentResolver;
private TextView tv;
private Button btn,btn1,btn2;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView)findViewById(R.id.tv);
btn = (Button)findViewById(R.id.btn);
btn1 = (Button)findViewById(R.id.btn1);
btn2 = (Button)findViewById(R.id.btn2);
contentResolver = this.getContentResolver();
Cursor cursor = contentResolver.query(ConstantsUtil.CONTENT_URI,
new String[] { ConstantsUtil.TID, ConstantsUtil.USERNAME,
ConstantsUtil.SEX }, null, null, null);
while (cursor.moveToNext()) {
String text = "tid : " + cursor.getString(0) + " , name : "
+ cursor.getString(1) + " , sex : " + cursor.getString(2);
tv.append(text + "\n");
}
startManagingCursor(cursor); // 查找后关闭游标
btn.setOnClickListener(listener);
btn1.setOnClickListener(listener);
btn2.setOnClickListener(listener);
}
private OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn:
//按条件查询
Uri uri = Uri.parse("content://niko.android.demo/provider/#");
Cursor c = contentResolver.query(uri,
new String[] {
ConstantsUtil.TID,
ConstantsUtil.USERNAME,
ConstantsUtil.SEX },
ConstantsUtil.USERNAME+" = ?",
new String[]{"Lucy"},
null);
while(c.moveToNext()){
String text = "tid : "+c.getString(0)+" , name : "+c.getString(1)+" , sex : "+c.getString(2);
btn.append(text);
}
c.close();
break;
case R.id.btn1:
//删除
Uri uri1 = Uri.parse("content://niko.android.demo/provider/#");
int res = contentResolver.delete(uri1, ConstantsUtil.USERNAME+" = ? ", new String[]{"Niko"});
setTitle("已经删除 "+res+" 数据");
break;
case R.id.btn2:
//更新
Uri uri2 = Uri.parse("content://niko.android.demo/provider/#");
ContentValues values = new ContentValues();
values.put(ConstantsUtil.USERNAME, "Jack");
values.put(ConstantsUtil.SEX, "女");
int res2 = contentResolver.update(uri2, values, ConstantsUtil.USERNAME+" = ? ", new String[]{"ZhangJin"});
setTitle("已经更新 "+res2+" 数据");
break;
default:
break;
}
}
};
}