內容提供者(Content Provider)是android的四大組件之一,重要性可想而知,一個進程的數據可以被另外一個進程訪問(在不同的apk之間可以訪問),內容提供者可以跨應用,數據庫跨應用的使用場景:一個應用中提供數據給其他應用;允許用戶從一個應用中拷貝數據到另一個應用;在整個框架中提供一種自定義的查詢建議。如果只在一個應用中使用數據的話使用SQLite,不需要使用Content Provider。
整體思路:創建一個繼承SQLiteOpenHelper的DbHelper類,在這個類中聲明數據庫名稱和版本號碼,在onCreate方法中寫創建表的sql語句並執行,onUpgrade方法中暫時不做任何操作(目前不涉及升級數據庫的操作)。創建一個繼承ContentProvider的StudentProvider類,在這個類中定義一個默認不匹配的UriMatcher對象,聲明兩個標誌位,聲明一個靜態代碼塊,在這個代碼塊中定義兩個匹配規則,定義一個getType方法,在這個方法中根據不同的標記返回不同的類型,在這個類中定義增刪改查操作對應的方法,在這些方法中根據不同的標記來執行單條記錄和多條記錄的操作。創建一個繼承AndroidTestCase的MyTest單元測試類,在這個類中定義增刪改查方法,在這些方法中定義一個內容解析者,使用內容解析者調用操作數據庫的方法。注意:在清單文件AndroidManifest.xml文件中註冊內容提供者和註冊測試單元。創建另一個工程,在這個工程中將MyTest類複製過來,運行裏面的各個方式進行測試。這樣就完成了從一個工程向另一個工程中訪問數據的操作。
DbHelper.java文件:
public class DbHelper extends SQLiteOpenHelper {
private static String name="mydb.db";
private static int version=1;//初始的版本號是1
public DbHelper(Context context) {
super(context, name, null, version);
// TODO Auto-generated constructor stub
}
@Override
public void onCreate(SQLiteDatabase database) {
// TODO Auto-generated method stub
String sql="create table student (id integer primary key autoincrement ,name varchar(64),address varchar(64))";
database.execSQL(sql);//對數據庫表的創建
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
// TODO Auto-generated method stub
}
}
StudentProvider.java文件:
//ContentProvider是一個抽象類,需要聲明一個類去繼承它,分別去重寫增刪改查的方法
public class StudentProvider extends ContentProvider {
private final String TAG = "StudentProvider";
private DbHelper helper = null;
// 默認是不匹配
private static final UriMatcher URI_MATCHER = new UriMatcher(
UriMatcher.NO_MATCH);
// 聲明兩個標誌位
private static final int STUDENT = 1;// 表示操作單條記錄
private static final int STUDENTS = 2;// 表示操作多條記錄
// 聲明一個靜態的代碼模塊
static {
// 定義了兩個匹配規則
URI_MATCHER.addURI(
"com.example.android_contentprovider.StudentProvider",
"student", STUDENTS);
URI_MATCHER.addURI(
"com.example.android_contentprovider.StudentProvider",
"student/#", STUDENT);
}
public StudentProvider() {
// TODO Auto-generated constructor stub
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
int count = -1;// 表示影響數據庫的行數
try {
int flag = URI_MATCHER.match(uri);
SQLiteDatabase database = helper.getWritableDatabase();
switch (flag) {
case STUDENT:// 單條記錄
// delete from student where id=? id是通過客戶端傳遞過來的
long id = ContentUris.parseId(uri);
String where_value = "id=" + id;
if (selection != null && !selection.equals("")) {
where_value += " and " + selection;
}
count = database.delete("student", where_value, selectionArgs);
break;
case STUDENTS:// 多條記錄
count = database.delete("student", selection, selectionArgs);
break;
}
} catch (Exception e) {
// TODO: handle exception
}
return count;
}
@Override
public String getType(Uri uri) {
// TODO Auto-generated method stub
int flag = URI_MATCHER.match(uri);
switch (flag) {
case STUDENT:
return "vnd.android.cursor.item/student";
case STUDENTS:
return "vnd.android.cursor.dir/students";
}
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// TODO Auto-generated method stub
// insert into student() (?,?);
Uri resultUri = null;
int flag = URI_MATCHER.match(uri);// 外部傳遞進來的uri來匹配內部的規則
switch (flag) {
case STUDENTS:
SQLiteDatabase database = helper.getWritableDatabase();
// 返回插入當前行的行號
long id = database.insert("student", null, values);
resultUri = ContentUris.withAppendedId(uri, id);
break;
}
Log.i(TAG, "-->>" + resultUri.toString());
return resultUri;
}
@Override
public boolean onCreate() {
// TODO Auto-generated method stub
helper = new DbHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] arg1, String selection,
String[] selectionArgs, String arg4) {
// TODO Auto-generated method stub
Cursor cursor = null;
try {
SQLiteDatabase database = helper.getReadableDatabase();
int flag = URI_MATCHER.match(uri);// 匹配路徑
switch (flag) {
case STUDENT:// 查詢返回單條記錄
long id = ContentUris.parseId(uri);
String where_value = " id = " + id;
if (selection != null && !selection.equals("")) {
where_value += " and " + selection;
}
cursor = database.query("student", null, where_value,
selectionArgs, null, null, null, null);
break;
case STUDENTS:// 查詢返回多條記錄
cursor = database.query("student", null, selection,
selectionArgs, null, null, null, null);
break;
}
} catch (Exception e) {
// TODO: handle exception
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
int count = -1;
try {
// update table set name= ?,address= ? where id = ?
SQLiteDatabase database = helper.getWritableDatabase();
long id = ContentUris.parseId(uri);
int flag = URI_MATCHER.match(uri);
switch (flag) {
case STUDENT:
String where_value = " id= " + id;
if (selection != null && !selection.equals("")) {
where_value += " and " + selection;
}
count = database.update("student", values, where_value,
selectionArgs);
break;
}
} catch (Exception e) {
// TODO: handle exception
}
return count;
}
}
MyTest.java文件:public class MyTest extends AndroidTestCase {
public MyTest() {
// TODO Auto-generated constructor stub
}
public void insert(){
// 訪問內容提供者的步驟:
// 1.需要一個內容解析者
ContentResolver contentResolver=getContext().getContentResolver();
// 使用content://+授權路徑 來訪問一個內容提供者
Uri url=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student");
ContentValues values=new ContentValues();
values.put("name", "吳孟達");
values.put("address", "香港");
contentResolver.insert(url, values);
}
public void delete(){
// 內容解析者
ContentResolver contentResolver=getContext().getContentResolver();
// 刪除第一條記錄,在後面需要加/1
// 刪除多條記錄,後面不加任何東西
Uri url=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student/1");
contentResolver.delete(url, null, null);
}
public void update(){
// 得到一個內容解析者
ContentResolver contentResolver=getContext().getContentResolver();
Uri uri=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student/2");
ContentValues values=new ContentValues();
values.put("name", "美人魚");
values.put("address", "香港");
contentResolver.update(uri, values, null, null);
}
public void query(){
ContentResolver contentResolver=getContext().getContentResolver();
// 查詢單條記錄(查詢id爲2的那條記錄):content://com.example.android_contentprovider.StudentProvider/student/2
// 查詢多條記錄:content://com.example.android_contentprovider.StudentProvider/student
// Uri uri=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student/2");
Uri uri=Uri.parse("content://com.example.android_contentprovider.StudentProvider/student");
// 相當於這樣的sql語句:select * from student where id =2;
Cursor cursor=contentResolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
System.out.println("-->>"+cursor.getString(cursor.getColumnIndex("name"))+" "+cursor.getString(cursor.getColumnIndex("address")));
}
}
}
AndroidManifest.xml文件:
<instrumentation android:targetPackage="com.example.android_contentprovider" android:name="android.test.InstrumentationTestRunner"></instrumentation>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<uses-library android:name="android.test.runner"/>
<activity
android:name="com.example.android_contentprovider.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 定義了一個內容提供者 authorities是授權:包名加類名 android:exported="true"-->
<provider
android:exported="true"
android:name=".StudentProvider" android:authorities="com.example.android_contentprovider.StudentProvider"
></provider>
</application>