android uri db,Android ContentProvider封装数据库和文件读写总结
本文是我各處東拼西湊加上自己實現一個ContentProvider的使用總結,留做后用,主要介紹ContentProvider的集成方法。
一、綜述
ContentProvider是Android四大組件之一,其核心功能是提供應用間的統一的數據訪問方式,當然也可以用于應用內的數據封裝。ContentProvider類似C/S結構,應用A實現ContentProvider向外提供應用內的數據訪問,應用B使用Context.getContentResolver()來間接與應用A的Provider交互。
ContentProvider提供一套類似數據庫的query/delete/insert/update的方法來操作數據,開發者可以以此來屏蔽管理數據的真正方式 (SharePreference/File/SQLite等)。另外,ContentProvider也提供了直接操作文件的方式(覆寫openFile),第三方應用可以通過該方式讀寫當前應用的私有文件(data/data等)。
二、相關知識
2.1 UriMatcher和ContentUris的使用
UriMatcher主要用戶判斷Uri是否符合特定格式,用法如下:
private static final int TYPE_ALL = 1;
private static final int TYPE_SINGLE = 2;
private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
mUriMatcher.addURI(AUTHORITY, "person", TYPE_ALL);
mUriMatcher.addURI(AUTHORITY, "person/#", TYPE_SINGLE);//#號表示一個數字
}
以上為其聲明與配置,下面是使用方法:
switch (mUriMatcher.match(uri)) {
case TYPE_ALL:
//uri匹配到第一種類型
case TYPE_SINGLE:
//uri匹配到第二種類型
default:
//uri沒有匹配到這兩種類型
}
這樣我們就可以知道外部傳入的Uri的類型了。
2.2 ContentUris用法
ContentUris用于處理Uri后面的id部分(純數字),常用函數有:
parseId(uri): 解析Uri里的最后的id
withAppendedId(uri, id):在路徑后面加上id部分
三、封裝ContentProvider的步驟
提供Provider的工程簡稱應用A。下面是封裝ContentProvider的步驟:
3.1 在Manifest中聲明ContentProvider:
android:authorities="org.test.auth"
android:exported="true"/>
聲明后,應用安裝到設備上第三方應用就能通過ContentResolver訪問此Provider。
3.2 ContentProvider的代碼
package org.test.auth;
import java.io.File;
import java.io.FileNotFoundException;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
import android.util.Log;
public class MyDataProvider extends ContentProvider {
private static final String AUTHORITY = "org.test.auth";
private static final int TYPE_ALL = 1;
private static final int TYPE_SINGLE = 2;
private static final String TAG = "TEST111_DataProvider";
private MyDBHelper mDbHelper;
private SQLiteDatabase mDatabase;
private static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
mUriMatcher.addURI(AUTHORITY, "person", TYPE_ALL);
mUriMatcher.addURI(AUTHORITY, "person/#", TYPE_SINGLE);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
switch (mUriMatcher.match(uri)) {
case TYPE_ALL:
return mDatabase.delete(MyDBHelper.TABLE_NAME,
selection,
selectionArgs);
case TYPE_SINGLE:
long id = ContentUris.parseId(uri);
String where = MyDBHelper.COLUMN_ID + " = " + id;
if(!TextUtils.isEmpty(selection)) {
where = where + " and " + selection;
}
return mDatabase.delete(MyDBHelper.TABLE_NAME,
where,
selectionArgs);
default:
return -1;
}
}
@Override
public String getType(Uri uri) {
switch (mUriMatcher.match(uri)) {
case TYPE_ALL:
return "vnd.android.cursor.dir/person";
case TYPE_SINGLE:
return "vnd.android.cursor.item/person";
default:
return null;
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//由于此時的values中具體是否含有數據是不確定的,所以此時需要在第二個參數中添加person表中的非主鍵的一列
long id = mDatabase.insert(MyDBHelper.TABLE_NAME, MyDBHelper.COLUMN_NAME, values);
return ContentUris.withAppendedId(uri, id);
}
@Override
public boolean onCreate() {
mDbHelper = new MyDBHelper(getContext());
mDatabase = mDbHelper.getWritableDatabase();
return true;
}
@Override
public Cursor query(Uri uri, String[] columns,
String selection, String[] selectionArgs,
String orderBy) {
switch (mUriMatcher.match(uri)) {
case TYPE_ALL:
return mDatabase.query(MyDBHelper.TABLE_NAME, columns, selection, selectionArgs, null, null, orderBy);
case TYPE_SINGLE:
long id = ContentUris.parseId(uri);
String where = MyDBHelper.COLUMN_ID + " = " + id;
if(!TextUtils.isEmpty(selection)) {
where = where + " and " + selection;
}
return mDatabase.query(MyDBHelper.TABLE_NAME, columns, where, selectionArgs, null, null, orderBy);
default:
return null;
}
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
switch (mUriMatcher.match(uri)) {
case TYPE_ALL:
return mDatabase.update(MyDBHelper.TABLE_NAME, values,
selection, selectionArgs);
case TYPE_SINGLE:
long id = ContentUris.parseId(uri);
String where = MyDBHelper.COLUMN_ID + " = " + id;
if(!TextUtils.isEmpty(selection)) {
where = where + " and " + selection;
}
return mDatabase.update(MyDBHelper.TABLE_NAME, values,
where, selectionArgs);
default:
return -1;
}
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File root = new File(getContext().getFilesDir() + "/" + uri.getPath());
root.getParentFile().mkdirs();
int imode = 0;
if (mode.contains("w")) {
imode |= ParcelFileDescriptor.MODE_WRITE_ONLY;
if (!root.exists()) {
try {
root.createNewFile();
} catch (Exception ex) {
Log.d(TAG, "error happened", ex);
}
}
}
if (mode.contains("r")) imode |= ParcelFileDescriptor.MODE_READ_ONLY;
if (mode.contains("+")) imode |= ParcelFileDescriptor.MODE_APPEND;
return ParcelFileDescriptor.open(root, imode);
}
}
此示例中使用的數據操作方式是數據庫,onCreate執行ContentProvider啟動時的初始化操作,query/insert/delete/update操作數據,getType返回指定Uri對應的數據類型。“vnd.android.cursor.dir”表示cursor集合,“vnd.android.cursor.item”表示cursor條目。
覆寫openFile方法提供私有文件的對外訪問,在該方法內可以控制是否提供文件讀寫,本例代碼來自網絡,支持讀寫操作。
附上數據庫幫助類代碼:
package org.test.auth;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDBHelper extends SQLiteOpenHelper {
public static final String DB_NAME = "test.db";
public static final String TABLE_NAME = "person";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_AGE = "age";
public static final String COLUMN_NAME = "name";
public static final int DB_VERSION = 1;
public MyDBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase database) {
String sql = "create table if not exists " + TABLE_NAME + "( " +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_NAME +" varchar(100), " +
COLUMN_AGE + " integer" +
" )" ;
database.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) {
}
}
四、測試代碼
測試代碼在另一個工程中,簡稱應用B。
package com.example.testcontentprovider;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;
public class MainActivity extends Activity {
private static final String URI = "content://org.test.auth/person";
private static final String TAG = "TEST111_";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
doTest();
}
private void doTest() {
ContentResolver cr = getContentResolver();
String typeAll = cr.getType(Uri.parse(URI));
Log.d(TAG, "get all type= " + typeAll);
String typeOne = cr.getType(Uri.parse(URI + "/1"));
Log.d(TAG, "get one type= " + typeOne);
insertValue(cr, "張三", 12);
insertValue(cr, "李四", 23);
//查詢所有數據
query(cr, -1);
//查詢單條數據
query(cr, 1);
//更改id=1的數據
updateValue(cr, 1, "王五", 20, null, null);
//查詢所有數據
query(cr, -1);
//更改name=李四的數據
updateValue(cr, 2, "哈哈", 34, "name=?", new String[] {"李四"});
//查詢所有數據
query(cr, -1);
//更改所有數據
updateValue(cr, -1, "小明", 15, null, null);
//查詢所有數據
query(cr, -1);
//刪除id=1數據
int affectedColumnCountOne = cr.delete(Uri.parse(URI + "/1"), null, null);
Log.d(TAG, "delete one affectedColumnCount= " + affectedColumnCountOne);
//查詢所有數據
query(cr, -1);
//刪除所有數據
int affectedColumnCountAll = cr.delete(Uri.parse(URI), null, null);
Log.d(TAG, "delete all affectedColumnCount= " + affectedColumnCountAll);
//查詢所有數據
query(cr, -1);
//測試文件讀寫
try {
OutputStream os = cr.openOutputStream(Uri.parse(URI+"/provider_file.txt"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
bw.append("think who am I?!");
bw.flush();
bw.close();
InputStream is = cr.openInputStream(Uri.parse(URI+"/provider_file.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String result = br.readLine();
br.close();
Log.d(TAG, "read file result : " + result);
} catch (Exception e) {
Log.d(TAG, "file op failed", e);
}
}
private void query(ContentResolver cr, int id) {
String idCause = "";
if(id >= 0) {
idCause = "/" + id;
}
Cursor cursorResultAll = cr.query(Uri.parse(URI + idCause), null, null, null, null);
if(null != cursorResultAll) {
while(cursorResultAll.moveToNext()) {
int result = cursorResultAll.getInt(0);
String name = cursorResultAll.getString(1);
int age = cursorResultAll.getInt(2);
Log.d(TAG, "query()| originid= " + id +"; id = " + result + " name= " + name + " age= " + age);
}
}
}
private void insertValue(ContentResolver cr, String name, int age) {
ContentValues value = new ContentValues();
value.put("name", name);
value.put("age", age);
Uri insertColumn = cr.insert(Uri.parse(URI), value);
Log.d(TAG, "insertValue() insert at column: " + insertColumn);
}
private void updateValue(ContentResolver cr, int id, String name, int age,
String selection, String[] selectionArgs) {
if (id >= 0) {
ContentValues value = new ContentValues();
value.put("name", name);
value.put("age", age);
int affectedColumnCount = cr.update(Uri.parse(URI + "/" + id), value, selection, selectionArgs);
Log.d(TAG, "updateValue() affectedColumnCount: " + affectedColumnCount);
} else {
ContentValues value = new ContentValues();
value.put("name", name);
value.put("age", age);
int affectedColumnCount = cr.update(Uri.parse(URI), value,
selection, selectionArgs);
Log.d(TAG, "updateValue() affectedColumnCount: " + affectedColumnCount);
}
}
}
以上,就是實現一個ContentProvider的方法,后續需要補充ContentProvider的原理部分,據說進程間通信是基于共享內存的,以后有時間需要分析一下。
總結
以上是生活随笔為你收集整理的android uri db,Android ContentProvider封装数据库和文件读写总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 双路由器桥接设置图解(双个路由器怎么进行
- 下一篇: android n 发布时间,Andro