Android四大組件之一CotentProvider相信做Android開發的人都知道。ContentProvider是Android中提供的專門用於不同應用間進行數據共享的方式。和Messenger一樣,CotentProvider的底層實現也是Binder。這裏也簡單記錄一下。
系統中預置了許多CotentProvider,如通訊錄,日曆,短信等等。要跨進程訪問這些信息,只需要通過使用CotentProvider的query
,update
,insert
,delete
方法即可。
這裏自定義一個ContentProvider。
CotentProvider主要以表格形式來組織數據,並且可以包含多個表,對每個表格來說,它們都具有行和列的層次性,行往往對應一條記錄,而列對應一條記錄中的一個字段,這點和數據庫很類似。除了表格在形式,ContentProvider還支持文件數據,比如圖片,視頻等。
話不多說,上代碼。
先上數據庫,創建Book和User兩個表。
/**
* Created by Kevin on 2019/4/10<br/>
* Blog:https://blog.csdn.net/student9128<br/>
* Describe:<br/>
*/
public class DbOpenHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "book_provider.db";
public static final String BOOK_TABLE_NAME = "book";
public static final String USER_TABLE_NAME = "user";
public static final int DB_VERSION = 1;
private String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS " + BOOK_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT)";
private String CREATE_USER_TABLE = "CREATE TABLE IF NOT EXISTS " + USER_TABLE_NAME + "(_id INTEGER PRIMARY KEY," + "name TEXT,gender INT)";
public DbOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_BOOK_TABLE);
db.execSQL(CREATE_USER_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists " + BOOK_TABLE_NAME);
db.execSQL("drop table if exists " + USER_TABLE_NAME);
onCreate(db);
}
}
自定義ContentProvider,名爲BookProvider。
ContentProvider通過Uri來區分外界要訪問的數據集合,本例子中支持對BookProvider中的book和user的訪問,爲了知道要訪問的是哪個表,需要爲它們定義單獨的Uri和UriCode。通過UriMatcher中的addURI將Uri和UriCode關聯起來。這樣就可以通過UriCode來找到Uril知道外界要訪問的那個表格了。
/**
* Created by Kevin on 2019/4/10<br/>
* Blog:https://blog.csdn.net/student9128<br/>
* Describe:<br/>
*/
public class BookProvider extends ContentProvider {
private static final String TAG = "BookProvider";
public static final String AUTHORITY = "com.kevin.server.provider";
public static final Uri BOOK_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/book");
public static final Uri USER_CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/user");
public static final int BOOK_URI_CODE = 0;
public static final int USER_URI_CODE = 1;
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private Context mContext;
private SQLiteDatabase mDb;
static {
sUriMatcher.addURI(AUTHORITY, "book", BOOK_URI_CODE);
sUriMatcher.addURI(AUTHORITY, "user", USER_URI_CODE);
}
@Override
public boolean onCreate() {
Log.d(TAG, "onCreate, current thread: " + Thread.currentThread().getName());
mContext = getContext();
initProviderData();
return true;
}
private void initProviderData() {
mDb = new DbOpenHelper(mContext, DbOpenHelper.DB_NAME, null, DbOpenHelper.DB_VERSION).getWritableDatabase();
mDb.execSQL("delete from " + DbOpenHelper.BOOK_TABLE_NAME);
mDb.execSQL("delete from " + DbOpenHelper.USER_TABLE_NAME);
mDb.execSQL("insert into book values(3,'Android');");
mDb.execSQL("insert into book values(4,'iOS');");
mDb.execSQL("insert into book values(5,'Html5');");
mDb.execSQL("insert into user values(1,'Jack', 1);");
mDb.execSQL("insert into user values(2,'LiLy',0);");
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.d(TAG, "query,current thread:" + Thread.currentThread().getName());
String tableName = getTableName(uri);
if (tableName == null) {
throw new IllegalArgumentException("Unsupported URI: " + uri);
}
return mDb.query(tableName, projection, selection, selectionArgs, null, null, sortOrder, null);
}
@Override
public String getType(Uri uri) {
Log.d(TAG, "getType");
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
Log.d(TAG, "insert");
String tableName = getTableName(uri);
if (tableName == null) {
throw new IllegalArgumentException("Unsupported URI: " + uri + " for insert.");
}
mDb.insert(tableName, null, values);
mContext.getContentResolver().notifyChange(uri, null);
return uri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
Log.d(TAG, "delete");
String tableName = getTableName(uri);
if (tableName == null) {
throw new IllegalArgumentException("Unsupported URI: " + uri + " for delete.");
}
int count = mDb.delete(tableName, selection, selectionArgs);
if (count > 0) {
mContext.getContentResolver().notifyChange(uri, null);
}
return count;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
Log.d(TAG, "update");
String tableName = getTableName(uri);
if (tableName == null) {
throw new IllegalArgumentException("Unsupported Uri: " + uri + " for update.");
}
int row = mDb.update(tableName, values, selection, selectionArgs);
if (row > 0) {
mContext.getContentResolver().notifyChange(uri, null);
}
return row;
}
private String getTableName(Uri uri) {
switch (sUriMatcher.match(uri)) {
case BOOK_URI_CODE:
return DbOpenHelper.BOOK_TABLE_NAME;
case USER_URI_CODE:
return DbOpenHelper.USER_TABLE_NAME;
}
return null;
}
}
AndroidMainfest清單文件配置:
<permission
android:name="com.kevin.server.ACCESS_PROVIDER"
android:protectionLevel="normal" />
<provider
android:name=".BookProvider"
android:authorities="com.kevin.server.provider"
android:enabled="true"
android:exported="true"
android:permission="com.kevin.server.ACCESS_PROVIDER" />
其中android:authorities="com.kevin.server.provider"
是ContentProvider的唯一標識,通過這個屬性外部應用就可以訪問BookProvider,因此android:authorities
必須是唯一的。因爲是進程間通信,這裏爲BookProvider添加了權限。註冊以後,外部應用就可以訪問BookProvider了。
/**
* Created by Kevin on 2019/4/10<br/>
* Blog:https://blog.csdn.net/student9128<br/>
* Describe:<br/>
*/
public class ProviderActivity extends AppCompatActivity {
private static final String TAG = "ProviderActivity";
private ContentResolver contentResolver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Uri bookUri = Uri.parse("content://com.kevin.server.provider/book");
ContentValues contentValues = new ContentValues();
contentValues.put("_id", 6);
contentValues.put("name", "程序設計的藝術");
contentResolver = getContentResolver();
contentResolver.insert(bookUri, contentValues);
Cursor bookCursor = contentResolver.query(bookUri, new String[]{"_id", "name"}, null, null, null);
while (bookCursor.moveToNext()) {
Book book = new Book();
book.id = bookCursor.getInt(0);
book.name = bookCursor.getString(1);
Log.d(TAG, "query book: " + book.toString());
}
bookCursor.close();
Uri userUri = Uri.parse("content://com.kevin.server.provider/user");
Cursor userCursor = contentResolver.query(userUri, new String[]{"_id", "name", "gender"}, null, null, null);
while (userCursor.moveToNext()) {
User user = new User();
user.userId = userCursor.getInt(0);
user.userName = userCursor.getString(1);
user.isMale = userCursor.getInt(2) == 1;
Log.d(TAG, "query user: " + user.userId + "=" + user.userName + "=" + user.isMale);
}
userCursor.close();
}
}
查詢結果如下圖所示
注:本文章知識點來自學習《Android開發藝術探索》一書