幾萬年都不見得用一次的ContentProvider鞋仍,這幾天說要用到,除了記得他是四大組件搅吁,還真是沒啥印象了威创。。
用到provider谎懦,無非是想要跨進(jìn)程進(jìn)行DB操作肚豺,AIDL,或者兩個app界拦,我就是用了AIDL吸申,再說吧。。
先來看下怎么使用ContentProvider進(jìn)行數(shù)據(jù)操作呛谜。
Uri uri = Uri.parse("content://com.example.test.aidl.provider/student");
ContentValues values = new ContentValues();
values.put("name", "sss");
values.put("age", 555);
values.put("stuno", 222);
getContentResolver().insert(uri, values);
調(diào)用getContentResolver()得到ContentResolver對象在跳,根據(jù)傳入的uri,可以知道調(diào)用方期望獲取的是哪個provider隐岛,哪張表猫妙,哪條數(shù)據(jù)。
數(shù)據(jù)庫
既然是DB操作聚凹,肯定要有DB了割坠,先搞個DB
public class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table if not exists student(id integer primary key autoincrement,name varchar(20),age integer,stuno varchar(20))";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
創(chuàng)建DB的時候,新建了一張student表妒牙,包含姓名彼哼,年齡,學(xué)號還有自增ID
ContentProvider
首先創(chuàng)建一個DBProvider繼承ContentProvider湘今,默認(rèn)實現(xiàn)有六個方法敢朱,分別為onCreate,query,insert,delete,update,還有g(shù)etType。
public class DBProvider extends ContentProvider {
@Override
public boolean onCreate() {
return false;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
return null;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
}
當(dāng)ContentResolver嘗試訪問Provider時摩瞎,Provider才會初始化拴签,所以在onCreate里創(chuàng)建數(shù)據(jù)庫
public boolean onCreate() {
//provider 初始化時創(chuàng)建一個名字為stu.db 版本為1的數(shù)據(jù)庫,這時數(shù)據(jù)庫中有student表
dbOpenHelper = new DBOpenHelper(getContext(),"stu.db",null,1);
return true;
}
再說下URI
一個標(biāo)準(zhǔn)的Uri如下格式
content://com.example.test.aidl.provider/student 訪問student表
content://com.example.test.aidl.provider/student/1 訪問student表下id為1的數(shù)據(jù)
包括
- 聲明協(xié)議: content://
- authority :com.example.test.aidl.provider(自定義旗们,一般為包名+.provider)
- path : student (表名)
- id:1(可不加蚓哩,不加時訪問整張表)
uri支持通配符
- ** * **匹配任意字符
- ** # ** 匹配任意數(shù)字
例如
content://com.example.test.aidl.provider/*可以匹配該provider下的任意表
content://com.example.test.aidl.provider/student/#可以匹配student表下的任意一行數(shù)據(jù)
關(guān)于uri的匹配
用到UriMatcher這個類
在靜態(tài)代碼塊中,初始化匹配規(guī)則
private static final int STUDENT_DIR = 0;
private static final int STUDENT_ITEM =1;
private static String AUTHORITY = "com.example.test.aidl.provider";
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);
uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);
}
addURI方法添加我們的匹配規(guī)則上渴,第一個參數(shù)是自定義的AUTHORITY岸梨,第二個是Path,可以是表名稠氮,也可以是表名下的id結(jié)尾曹阔,這里#就是上面說的通配符,匹配任意數(shù)字括袒,第三個參數(shù)是成功匹配uri時返回的自定義整型碼
而uri的作用次兆,都體現(xiàn)在除了onCreate之外的五個實現(xiàn)方法中,下面是整個ContentProvider的代碼
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
/**
* Created by walker on 2016/12/7.
*/
public class DBProvider extends ContentProvider {
private DBOpenHelper dbOpenHelper;
private static final int STUDENT_DIR = 0;
private static final int STUDENT_ITEM =1;
private static String AUTHORITY = "com.example.test.aidl.provider";
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, "student", STUDENT_DIR);
uriMatcher.addURI(AUTHORITY, "student/#", STUDENT_ITEM);
}
@Override
public boolean onCreate() {
dbOpenHelper = new DBOpenHelper(getContext(),"stu.db",null,1);
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
Cursor cursor = null;
switch(uriMatcher.match(uri)){
case STUDENT_DIR:
cursor = db.query("student", projection, selection, selectionArgs, null, null, sortOrder);
break;
case STUDENT_ITEM:
String id = uri.getPathSegments().get(1); //切割URI AUTHORITY之后的字符锹锰,0是路徑芥炭,1是id
cursor = db.query("student", projection, "id = ?", new String[]{id}, null, null, sortOrder);
break;
}
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
//==============================================================
//返回各個Uri對象對應(yīng)的MIME類型,MIME由三個部分組成恃慧,以vnd開頭园蝠,
//如果URI以路徑結(jié)尾,接android.cursor.dir/ 如果以id結(jié)尾痢士,接android.cursor.item/
//最后接vnd.權(quán)限.路徑
//對于content://com.example.test.aidl.provider/student
//對應(yīng)的MIME為 vnd.android.cursor.dir/vnd.com.example.test.aidl.provider.student
//==============================================================
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case STUDENT_DIR:
return "vnd.android.cursor.dir/vnd.com.example.test.aidl.provider.student";
case STUDENT_ITEM:
return "vnd.android.cursor.item/vnd.com.example.test.aidl.provider.student";
default:
break;
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
Uri uriReturn = null;
switch (uriMatcher.match(uri)) {
case STUDENT_DIR:
case STUDENT_ITEM:
long newID = db.insert("student", null, values);
uriReturn = Uri.parse("content://"+AUTHORITY+"/student/"+newID);
break;
default:
break;
}
return uriReturn;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
int deleteRow = 0;
switch (uriMatcher.match(uri)) {
case STUDENT_DIR:
deleteRow = db.delete("student", selection, selectionArgs);
break;
case STUDENT_ITEM:
String id = uri.getPathSegments().get(1);
deleteRow = db.delete("student", "id = ?" , new String[]{id});
break;
}
return deleteRow;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
int updateRows = 0;
switch (uriMatcher.match(uri)) {
case STUDENT_DIR:
updateRows = db.update("student",values, selection, selectionArgs);
break;
case STUDENT_ITEM:
String id = uri.getPathSegments().get(1);
updateRows = db.update("student",values, "id = ?" , new String[]{id});
break;
}
return updateRows;
}
}
可以看到彪薛,switch里面對傳進(jìn)來的uri進(jìn)行了匹配艾少,根據(jù)結(jié)果進(jìn)行不同操作多望,也就是一些db操作
這里說下getPathSegments獲取的是path蓝晒,也就是uri中authority之后的部分惰聂,這部分有路徑,也可能有id易遣,0是路徑彼妻,1是id(如果有)
關(guān)于getType,返回的MIME不知道有啥用豆茫,貌似即使provider不exported出去侨歉,也是能夠讓其他進(jìn)程訪問到。
最后別忘了注冊provider和exported它
<provider
android:exported="true"
android:authorities="com.example.test.aidl.provider"
android:name=".DBProvider" />