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;
}
}
};
}