實(shí)例講解Android中ContentProvider組件的使用方法
ContentProvider基本使用
為了在應(yīng)用程序之間交換數(shù)據(jù),android提供了ContentProvider,ContentProvider是不同應(yīng)用程序之間進(jìn)行數(shù)據(jù)交換的標(biāo)準(zhǔn)API,當(dāng)一個(gè)應(yīng)用程序需要把自己的數(shù)據(jù)暴露給其他程序使用時(shí),該應(yīng)用程序就可以通過提供ContentPRovider來實(shí)現(xiàn),其他應(yīng)用程序就可以通過ContentResolver來操作ContentProvider暴露的數(shù)據(jù)。
實(shí)現(xiàn)ContentProvider的步驟:
1)編寫一個(gè)類,繼承ContentProvider,并且重寫里面的CRUD方法。
2)在androidmanifest.xml文件中注冊provider。
在androidmanifest.xml中注冊provider需要以下3個(gè)屬性:
android:name provider的實(shí)現(xiàn)類。
android:authorities provider的uri。
android:exported provider是否暴露給其他程序。
ContentResovler操作ContentProvider:
1)獲取ContentResolver,getContentResovler()方法來自于ContextWrapper,所以activity和service中都可以使用。
2)調(diào)用CURD方法,通過參數(shù)url,調(diào)用指定的ContentProvider的方法。
下面是一個(gè)demo,向contentProvider中插入一條數(shù)據(jù),并且返回到listview中。
main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main" >
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</RelativeLayout>
MySQLiteOpenHelper類
package com.app.dao;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public MySQLiteOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
String create_sql = "create table tb_test(_id integer primary key autoincrement,name,gender,age)";
db.execSQL(create_sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
MyContentProvider類
package com.app.dao;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class MyContentProvider extends ContentProvider{
MySQLiteOpenHelper helper=null;
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
return 0;
}
@Override
public String getType(Uri arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public Uri insert(Uri arg0, ContentValues values) {
String insert_sql="insert into tb_test values(null,'wx','boy',17)";
helper.getReadableDatabase().execSQL(insert_sql);
return null;
}
@Override
public boolean onCreate() {
helper=new MySQLiteOpenHelper(this.getContext(),"test.db3",null,1);
return true;
}
@Override
public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3,
String arg4) {
String query_sql="select * from tb_test";
Cursor cursor=helper.getReadableDatabase().rawQuery(query_sql, null);
return cursor;
}
@Override
public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {
// TODO Auto-generated method stub
return 0;
}
}
listview的顯示界面show.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/gender"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="60dp" />
<TextView
android:id="@+id/age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="60dp" />
</LinearLayout>
Main.java
package com.app.main;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
public class Main extends Activity {
ContentResolver resolver = null;
ListView lv = null;
@SuppressLint("NewApi")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
lv = (ListView) this.findViewById(R.id.listview);
resolver = this.getContentResolver();
String str = "content://com.app.test.db/";
Uri uri = Uri.parse(str);
resolver.insert(uri, null);
Cursor cursor = resolver.query(uri, null, null, null, null);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.show, cursor,
new String[] { "name", "gender", "age" }, new int[] {
R.id.name, R.id.gender, R.id.age },
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
}
}
實(shí)現(xiàn)效果:(執(zhí)行了3次插入后的效果)

ContentProvider的單元測試
ContentProvider是android的四大組件之一,在編寫代碼的時(shí)候最好是加上單元測試,這樣可以確定對(duì)數(shù)據(jù)的CRUD的正確。本篇文章主要介紹ContentProvider中兩個(gè)主要輔助類的使用還有單元測試的在ContentProvider中的使用。
需要用到的兩個(gè)輔助類:UriMatcher類和ContentUris類。
UriMatcher類:能夠?qū)斎氲膗ri參數(shù)就行匹配,以確定對(duì)什么表執(zhí)行什么樣的操作。
ContentUris類:有些方法需要返回uri,運(yùn)用此類可以方便的生成uri類。
對(duì)于單元測試,個(gè)人覺得非常有必要在今后寫代碼的時(shí)候使用,這樣可以非常準(zhǔn)確的確定代碼的正確性。
使用單元測試的步驟:
1)加入instrumentation,這個(gè)部分的代碼是固定,也可以完全在ADT提供的向?qū)е袑?dǎo)入。
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.example.android_contentprovider" >
</instrumentation>
2)添加<uses-library>,這個(gè)部分的代碼也是固定的寫法。
<uses-library android:name="android.test.runner" />
好了,必備的知識(shí)已經(jīng)講完了,現(xiàn)在上代碼:
1)生成一個(gè)SQLiteDatabase類,這個(gè)是必需的類MySQLiteOpenHelper類
package com.app.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
private static String DB_NAME = "test.db3";
private static int VERSION = 1;
public MySQLiteOpenHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//建表語句
String create_student = "create table student(_id integer primary key autoincrement,name varchar(10),age integer,gender vachar(10))";
db.execSQL(create_student);
//千萬不能執(zhí)行這句 // db.close();
}
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
}
}
然后添加我們需要的MyContentProvider類:
package com.app.contentprovider;
import com.app.db.MySQLiteOpenHelper;
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.util.Log;
public class MyContentProvider extends ContentProvider {
MySQLiteOpenHelper helper = null;
private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
// 匹配單條記錄
private static final int student = 1;
// 匹配多條記錄
private static final int students = 2;
static {
matcher.addURI("com.app.wx", "student/#", student);
matcher.addURI("com.app.wx", "student", students);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase db = helper.getWritableDatabase();
int action = matcher.match(uri);
switch (action) {
// 匹配單條記錄
case student:
long id = ContentUris.parseId(uri);
//獲取單條記錄的id號(hào)
String delete_id = "_id=" + id;
if (selection != null) {
delete_id += delete_id + " and " + selection;
}
db.delete("student", delete_id, selectionArgs);
break;
// 匹配多條記錄
case students:
db.delete("student", selection, selectionArgs);
break;
}
return 0;
}
//必需實(shí)現(xiàn)這個(gè)方法,這個(gè)方法與intent有關(guān)系,以后再講
@Override
public String getType(Uri uri) {
int code = matcher.match(uri);
switch (code) {
case student:
return "vnd.android.cursor.item/student_item";
case students:
return "vnd.android.cursor.dir/students";
default:
return null;
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase db = helper.getWritableDatabase();
int action = matcher.match(uri);
switch (action) {
case students:
long id1 = db.insert("student", "_id", values);
Log.i("--------", ContentUris.withAppendedId(uri, id1).toString());
return ContentUris.withAppendedId(uri, id1);
}
return null;
}
@Override
public boolean onCreate() {
helper = new MySQLiteOpenHelper(this.getContext());
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String orderBy) {
SQLiteDatabase db = helper.getWritableDatabase();
Cursor cursor = null;
int action = matcher.match(uri);
switch (action) {
case students:
cursor = db.query("student", projection, selection, selectionArgs,
null, null, orderBy);
break;
}
System.out.println("-----------count:" + cursor.getCount());
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] arg3) {
int count = -1;
SQLiteDatabase db = helper.getWritableDatabase();
int action = matcher.match(uri);
switch (action) {
case student:
// 以id來處理更新
long id = ContentUris.parseId(uri);
String id_selection = "_id=" + id;
if (selection != null && !selection.equals("")) {
id_selection = id_selection + " and " + values;
}
count = db.update("student", values, id_selection, arg3);
System.out.println("----------count:" + count);
break;
}
return count;
}
}
這個(gè)類很長,但是執(zhí)行的方法都是比較常見的CURD的方法,重要的是UriMatcher和ContentUris類的使用。
接著執(zhí)行單元測試類:Test
package com.app.contentprovider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.test.AndroidTestCase;
import android.util.Log;
public class Test extends AndroidTestCase {
public void insert() {
ContentResolver resolver = this.getContext().getContentResolver();
String str = "content://com.app.wx/student";
ContentValues values = new ContentValues();
values.put("name", "wzq");
values.put("age", 18);
values.put("gender", "boy");
resolver.insert(Uri.parse(str), values);
}
public void update() {
ContentResolver resolver = this.getContext().getContentResolver();
String str = "content://com.app.wx/student/2";
ContentValues values = new ContentValues();
values.put("name", "哈哈");
resolver.update(Uri.parse(str), values, null, null);
}
public void query() {
ContentResolver resolver = this.getContext().getContentResolver();
String str = "content://com.app.wx/student";
Uri uri = Uri.parse(str);
Cursor cursor = resolver.query(uri, new String[] { "_id",
"name,age,gender" }, null, null, "_id desc");
Log.d("------count",cursor.getCount()+"");
}
public void delete() {
ContentResolver resolver = this.getContext().getContentResolver();
String str = "content://com.app.wx/student/2";
Uri uri = Uri.parse(str);
long id=resolver.delete(uri, null, null);
}
}
執(zhí)行insert方法之后(執(zhí)行了三次):

執(zhí)行了update方法之后:

執(zhí)行了query方法之后:

執(zhí)行了delete方法之后:

- Android應(yīng)用中使用ContentProvider掃描本地圖片并顯示
- Android中自定義ContentProvider實(shí)例
- Android開發(fā)之ContentProvider的使用詳解
- Android 自定義ContentProvider簡單實(shí)例
- Android數(shù)據(jù)持久化之ContentProvider機(jī)制詳解
- Android ContentProvider的實(shí)現(xiàn)及簡單實(shí)例代碼
- Android開發(fā)教程之ContentProvider數(shù)據(jù)存儲(chǔ)
- android基礎(chǔ)總結(jié)篇之八:創(chuàng)建及調(diào)用自己的ContentProvider
- Android學(xué)習(xí)筆記之ContentProvider和Uri詳解
- 詳解Android ContentProvider的基本原理和使用
相關(guān)文章
Android 啟動(dòng)模式FLAG_ACTIVITY_CLEAR_TOP案例詳解
這篇文章主要介紹了Android 啟動(dòng)模式FLAG_ACTIVITY_CLEAR_TOP案例詳解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
android開發(fā)中ListView與Adapter使用要點(diǎn)介紹
項(xiàng)目用到ListView,由于要用到 ImageView ,圖片源不是在資源里面的,沒法使用資源 ID,因此無法直接使用SimpleAdapter,要自己寫一個(gè)Adapter。 在使用ListView和Adapter需要注意以下幾點(diǎn)2013-06-06
Android編程入門之HelloWorld項(xiàng)目目錄結(jié)構(gòu)分析
這篇文章主要介紹了Android編程入門之HelloWorld項(xiàng)目目錄結(jié)構(gòu)分析,較為詳細(xì)的分析了Android項(xiàng)目的目錄結(jié)構(gòu)與具體作用,需要的朋友可以參考下2015-12-12
Android ProgressBar實(shí)現(xiàn)進(jìn)度條效果
這篇文章主要為大家詳細(xì)介紹了Android ProgressBar實(shí)現(xiàn)進(jìn)度條效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
WAC啟動(dòng)Android模擬器 transfer error: Read-only file system錯(cuò)誤解決方法
這篇文章主要為大家分享下WAC啟動(dòng)Android模擬器時(shí)出現(xiàn)transfer error: Read-only file system 問題的解決方法2013-10-10

