Content Provider 屬於Android應用程式的組件之一,作為應用程式之間唯一的共用資料的途徑,Content Provider 主要的功能就是儲存並檢索資料以及向其他應用程式提供訪問資料的借口。
Android 系統為一些常見的資料類型(如音樂、視頻、映像、手機通訊錄連絡人資訊等)內建了一系列的 Content Provider, 這些都位於android.provider包下。持有特定的許可,可以在自己開發的應用程式中訪問這些Content Provider。
讓自己的資料和其他應用程式共用有兩種方式:建立自己的Content Provier(即繼承自ContentProvider的子類) 或者是將自己的資料添加到已有的Content Provider中去,後者需要保證現有的Content Provider和自己的資料類型相同且具有該 Content Provider的寫入許可權。對於Content Provider,最重要的就是資料模型(data model) 和 URI。
1.資料模型
Content Provider 將其儲存的資料以資料表的形式提供給訪問者,在資料表中每一行為一條記錄,每一列為具有特定類型和意義的資料。每一條資料記錄都包括一個 "_ID" 數值欄位,改欄位唯一標識一條資料。
2.URI
URI,每一個Content Provider 都對外提供一個能夠唯一標識自己資料集(data set)的公開URI, 如果一個Content Provider管理多個資料集,其將會為每個資料集分配一個獨立的URI。所有的Content Provider 的URI 都以"content://" 開頭,其中"content:"是用來標識資料是由Content Provider管理的 schema。
下面通過繼承Content Provier來寫一個執行個體。
首先建立一個sqlite執行個體,具體細節見上一節sqlite執行個體,這裡就只給出代碼:
第一步建立一個ContentProviderDemo:
第二步建立DBOpenHelper類:
public class DBOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = "person.db"; //資料庫名稱private static final int DATABASE_VERSION = 1;//資料庫版本public DBOpenHelper(Context context) {super(context, DATABASE_NAME, null, DATABASE_VERSION);// TODO Auto-generated constructor stub}@Overridepublic void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE person (_id integer primary key autoincrement, name varchar(20), age varchar(10))");}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stubdb.execSQL("DROP TABLE IF EXISTS person");onCreate(db);}}
在上面建立了一個person表,
public class PersonService { private DBOpenHelper dbOpenHelper; public PersonService(Context context) {// TODO Auto-generated constructor stub dbOpenHelper=new DBOpenHelper(context);} public void save(Person person){ SQLiteDatabase db=dbOpenHelper.getWritableDatabase(); db.execSQL("insert into person(name,age) values(?,?)",new Object[]{person.getName(),person.getAge()}); } public void delete(Integer _id){ SQLiteDatabase db=dbOpenHelper.getWritableDatabase(); db.execSQL("delete from person where _id=?",new Object[]{_id}); } public Person find(Integer _id){ SQLiteDatabase db=dbOpenHelper.getReadableDatabase(); Cursor cursor=db.rawQuery("select * from person where _id=?", new String[]{_id.toString()}); if(cursor.moveToFirst()){ int id = cursor.getInt(cursor.getColumnIndex("_id"));String name = cursor.getString(cursor.getColumnIndex("name"));String age = cursor.getString(cursor.getColumnIndex("age"));Person person = new Person();person.set_id(id);person.setName(name);person.setAge(age);return person; } return null; } public List<Person> findAll(){ SQLiteDatabase db=dbOpenHelper.getReadableDatabase(); List<Person> persons = new ArrayList<Person>(); Cursor cursor=db.rawQuery("select * from person", null); while(cursor.moveToNext()){ Person person=new Person();int id=cursor.getInt(cursor.getColumnIndex("_id"));String name=cursor.getString(cursor.getColumnIndex("name"));String age=cursor.getString(cursor.getColumnIndex("age"));person.set_id(id);person.setName(name);person.setAge(age);persons.add(person); } return persons; }}
實現person的增刪改查,
public class Person {private Integer _id;private String name;private String age;public Integer get_id() {return _id;}public void set_id(Integer _id) {this._id = _id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}}
OK!資料庫已建好,接下來就是要實現ContentProvider來提供統一的提供者:
public class PersonProvider extends ContentProvider {private DBOpenHelper dbOpenHelper;private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);private static final int PERSONS = 1;private static final int PERSON = 2;static {MATCHER.addURI("cn.com.karl.personProvider", "person", PERSONS);MATCHER.addURI("cn.com.karl.personProvider", "person/#", PERSON);}@Overridepublic boolean onCreate() {// TODO Auto-generated method stubthis.dbOpenHelper = new DBOpenHelper(this.getContext());return false;}@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {// TODO Auto-generated method stubSQLiteDatabase db = dbOpenHelper.getReadableDatabase();switch (MATCHER.match(uri)) {case PERSONS:return db.query("person", projection, selection, selectionArgs,null, null, sortOrder);case PERSON:long id = ContentUris.parseId(uri);String where = "_id=" + id;if (selection != null && !"".equals(selection)) {where = selection + " and " + where;}return db.query("person", projection, where, selectionArgs, null,null, sortOrder);default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}} //返回資料的MIME類型。@Overridepublic String getType(Uri uri) {// TODO Auto-generated method stubswitch (MATCHER.match(uri)) {case PERSONS:return "vnd.android.cursor.dir/person";case PERSON:return "vnd.android.cursor.item/person";default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}}// 插入person表中的所有記錄 /person// 插入person表中指定id的記錄 /person/10@Overridepublic Uri insert(Uri uri, ContentValues values) {// TODO Auto-generated method stubSQLiteDatabase db = dbOpenHelper.getWritableDatabase();switch (MATCHER.match(uri)) {case PERSONS:// 特別說一下第二個參數是當name欄位為空白時,將自動插入一個NULL。long rowid = db.insert("person", "name", values);Uri insertUri = ContentUris.withAppendedId(uri, rowid);// 得到代表新增記錄的Urithis.getContext().getContentResolver().notifyChange(uri, null);return insertUri;default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}}@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {// TODO Auto-generated method stubSQLiteDatabase db = dbOpenHelper.getWritableDatabase();int count = 0;switch (MATCHER.match(uri)) {case PERSONS:count = db.delete("person", selection, selectionArgs);return count;case PERSON:long id = ContentUris.parseId(uri);String where = "_id=" + id;if (selection != null && !"".equals(selection)) {where = selection + " and " + where;}count = db.delete("person", where, selectionArgs);return count;default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}}@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {// TODO Auto-generated method stubSQLiteDatabase db = dbOpenHelper.getWritableDatabase();int count = 0;switch (MATCHER.match(uri)) {case PERSONS:count = db.update("person", values, selection, selectionArgs);return count;case PERSON:long id = ContentUris.parseId(uri);String where = "_id=" + id;if (selection != null && !"".equals(selection)) {where = selection + " and " + where;}count = db.update("person", values, where, selectionArgs);return count;default:throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());}}}
最後不要忘記在manifest裡註冊
<provider android:name=".PersonProvider" android:authorities="cn.com.karl.personProvider"/>
這樣基本上就已經完成,讓我們再寫個項目訪問一下,建立ResolverDemo項目:
為了展現效果,我們用了ListView,在res下建立item.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:layout_width="80dip" android:layout_height="wrap_content" android:text="435" android:id="@+id/id" /> <TextView android:layout_width="100dip" android:layout_height="wrap_content" android:text="liming" android:id="@+id/name" /> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="45" android:id="@+id/age" /> </LinearLayout>
public class ResolverDemoActivity extends Activity { /** Called when the activity is first created. */private SimpleCursorAdapter adapter;private ListView listView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); listView=(ListView) this.findViewById(R.id.listView); ContentResolver contentResolver = getContentResolver();Uri selectUri = Uri.parse("content://cn.com.karl.personProvider/person");Cursor cursor=contentResolver.query(selectUri, null, null, null, null); adapter = new SimpleCursorAdapter(this, R.layout.item, cursor, new String[]{"_id", "name", "age"}, new int[]{R.id.id, R.id.name, R.id.age}); listView.setAdapter(adapter); listView.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {ListView lView = (ListView)parent;Cursor data = (Cursor)lView.getItemAtPosition(position);int _id = data.getInt(data.getColumnIndex("_id"));Toast.makeText(ResolverDemoActivity.this, _id+"", 1).show();}}); Button button = (Button) this.findViewById(R.id.insertbutton); button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {ContentResolver contentResolver = getContentResolver();Uri insertUri = Uri.parse("content://cn.com.karl.personProvider/person");ContentValues values = new ContentValues();values.put("name", "wangkuifeng");values.put("age", 23);Uri uri = contentResolver.insert(insertUri, values);Toast.makeText(ResolverDemoActivity.this, "添加完成", 1).show();}}); }}
用ContentResolver來訪問,其實在使用Content Provider得到連絡人資訊這一節就已經用過這個類了,只是那一節是訪問系統提供的ContentProvider,這一節是我們自己實現的ContentProvider。
最後讓我們看一下運行效果吧!