下面首先要定义出表示mldn数据库的元数据类。
import android.net.Uri; import android.provider.BaseColumns; public interface MLDNDatabaseMetaData { /* 这个是外部访问的Authority,Content地址为: content//org.lxh.demo.membercontentprovider */ public static final String AUTHORITY = "org.lxh.demo.membercontentprovider" ; // 数据库的名字 ("mldn"操作的数据库的名字) public static final String DATABASE_NAME = "mldn" ;
此时就表示出了MLDN数据库之中的所有元数据,下面肯定要在一个数据库中有多张表,那么现在使用的是member表,所以继续在这个数据库里面建立一个member表的元数据。
对于所有表而言,肯定都有一个"_id"的属性,所以为了简化定义,在Android中专门提供了一个BaseColumn接口。
import android.net.Uri; import android.provider.BaseColumns; public interface MLDNDatabaseMetaData { /* 这个是外部访问的Authority,Content地址为: content//org.lxh.demo.membercontentprovider */ public static final String AUTHORITY = "org.lxh.demo.membercontentprovider" ; // 数据库的名字 ("mldn"操作的数据库的名字) public static final String DATABASE_NAME = "mldn" ; // 数据库的版本 public static final int VERSION = 1 ; /** 表示member表的元数据定义,直接继承_ID和_COUNT静态常量 */ public static interface MemberTableMetaData extends BaseColumns{ // 表名称 public static final String TABLE_NAME = "member" ; // 外部程序访问本表的Uri地址,而且名称都统一设置为CONTENT_URI public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + TABLE_NAME); // 得到member表中的全部记录 public static final String CONTACT_LIST = "vnd.android.cursor.dir/vnd.mldncontentprovider.member"; // 取得一个member的信息,相当于就是按照ID查询 public static final String CONTACT_ITEM = "vnd.android.cursor.item/vnd.mldncontentprovider.member"; /** 一下表示member.name/age/birthday字段名称 */ public static final String MEMBER_NAME = "name" ; public static final String MEMBER_AGE = "age" ; public static final String MEMBER_BIRTHDAY = "birthday" ; // 排序操作 public static final String SORT_ORDER = "_id DESC" ; } }
既然要操作的是数据库,那么就首先需要定义一个SQLiteOpenHelper类的子类。
import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class MyDatabaseHelper extends SQLiteOpenHelper { public MyDatabaseHelper(Context context) { super(context, MLDNDatabaseMetaData.DATABASE_NAME, null, MLDNDatabaseMetaData.VERSION); } @Override public void onCreate(SQLiteDatabase db) { String sql = "CREATE TABLE " + MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME + " ( " + MLDNDatabaseMetaData.MemberTableMetaData._ID + " INTEGER PRIMARY KEY ," + MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_NAME + " VARCHAR(50) NOT NULL ," + MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_AGE + " INTEGER NOT NULL ," + MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_BIRTHDAY + " DATE NOT NULL" + " )"; db.execSQL(sql) ; } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { String sql = "DROP TABLE IF EXISTS " + MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME ; db.execSQL(sql) ; this.onCreate(db) ; } }
以后就通过这个类取得数据库的连接对象,一切都准备完成之后,那么下面就必须动手编写ContentProvider程序 ----- MemberContentProvider.java。(分段讲解)
// 地址转换 private static UriMatcher uriMatcher = null ; // 得到全部的数据 private static final int GET_MEMBER_LIST = 1 ; // 取得一个数据 private static final int GET_MEMBER_ITEM = 2 ; // 数据库操作类对象 private MyDatabaseHelper helper = null ; static { // 静态代码块 // 实例化对象 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH) ; // 取得全部数据的匹配地址 uriMatcher.addURI(MLDNDatabaseMetaData.AUTHORITY, MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, GET_MEMBER_LIST); // 取得一个数据的匹配地址 uriMatcher.addURI(MLDNDatabaseMetaData.AUTHORITY, MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME+"/#", GET_MEMBER_ITEM); }
这个部分就相当于为用户准备好了一个所有地址的匹配集合,以后只要有地址传入,与这种地址一匹配,就知道执行的是何种查询操作。
在ContentProvider程序之中,也存在一个onCreate(),很明显,这个是进行初始化操作的。
// 数据库操作类对象 private MyDatabaseHelper helper = null ; @Override public boolean onCreate() { this.helper = new MyDatabaseHelper(super.getContext()) ; return true; // 操作成功了 }
上段程序中,onCreate()为回调方法,在创建此类对象时调用,所以在此方法中的主要功能是实例化MyDatabaseHelper数据库的辅助操作类的对象。
@Override // 取得数据的类型的 public String getType(Uri uri) { // 匹配传入进来的Uri的类型 switch (uriMatcher.match(uri)) { case GET_MEMBER_LIST: return MLDNDatabaseMetaData.MemberTableMetaData.CONTACT_LIST; case GET_MEMBER_ITEM: return MLDNDatabaseMetaData.MemberTableMetaData.CONTACT_ITEM; default: throw new UnsupportedOperationException("Not Support Operation :" + uri); } }
getType()主要作用是返回操作地址的相应的MIME数据类型,这些数据类型都是通过MemberTableMetaData接口指定的常量,当传入Uri之后,首先通过match()找到指定Uri的位置,如果找到了,则返回之前通过addUri()设置的CODE:如果没找到,返回-1。此时程序将手工抛出一个UnsupportedOperationException的异常。
@Override // content://org.lxh.demo.membercontentprovider/member public Uri insert(Uri uri, ContentValues values) { // 以写方式打开数据库 SQLiteDatabase db = this.helper.getWritableDatabase() ; // 取得增长后的数据ID long id = 0 ; // 匹配传入的Uri switch(uriMatcher.match(uri)) { case GET_MEMBER_LIST : id = db.insert(MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, MLDNDatabaseMetaData.MemberTableMetaData._ID, values); // 取出地址 String uriPath = uri.toString() ; // 建立新的Uri地址 String path = uriPath + "/" + id ; // 返回一个member信息 return Uri.parse(path) ; case GET_MEMBER_ITEM : return null ; default: throw new UnsupportedOperationException( "Not Support Operation :" + uri); } }
insert()为增加数据的标准方法,此方法返回的是一个Uri地址,在此Uri上要将用户插入后的ID以Uri的形式返回给客户端,在此方法中,使用UriMatcher类中的match()对传入的Uri进行判断,取出传入Uri对应的CODE。
@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // 以写方式打开数据库 SQLiteDatabase db = this.helper.getWritableDatabase() ; int result = 0 ; // 表示结果 switch (uriMatcher.match(uri)) { // 更新全部数据 case GET_MEMBER_LIST: result = db.update( MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, values, null, null); break ; // 根据ID更新记录 case GET_MEMBER_ITEM: // 找到里面的id long id = ContentUris.parseId(uri) ; String where = "_id=" + id ; result = db.update( MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, values, where, selectionArgs); break ; default: throw new UnsupportedOperationException( "Not Support Operation :" + uri); } return result ; } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { // 以写方式打开数据库 SQLiteDatabase db = this.helper.getWritableDatabase() ; // 操作结果 int result = 0 ; switch (uriMatcher.match(uri)) { // 删除全部 case GET_MEMBER_LIST: result = db.delete( MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, selection, selectionArgs); break ; // 找到一个数据的ID case GET_MEMBER_ITEM: long id = ContentUris.parseId(uri) ; String where = "_id=" + id ; result = db.delete( MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, where,selectionArgs); break ; default: throw new UnsupportedOperationException(" Not Support Operation :" + uri); } return result; } @Override public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) { // 以写方式打开数据库 SQLiteDatabase db = this.helper.getWritableDatabase() ; switch (uriMatcher.match(uri)) { case GET_MEMBER_LIST: return db.query( MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder); case GET_MEMBER_ITEM: // 找到ID long id = ContentUris.parseId(uri) ; String where = "_id=" + id ; return db.query( MLDNDatabaseMetaData.MemberTableMetaData.TABLE_NAME, projection, where, selectionArgs, null, null,sortOrder); default: throw new UnsupportedOperationException( "Not Support Operation :" + uri); } }
定义访问ContentProvider应用程序的布局文件 --- main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:id="@+id/insertBut" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="增加" /> <Button android:id="@+id/updateBut" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="更新" /> <Button android:id="@+id/deleteBut" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="删除" /> <Button android:id="@+id/queryBut" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="查询" /> </LinearLayout> <TextView android:id="@+id/mainInfo" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <ListView android:id="@+id/memberList" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout>
定义数据列表显示的布局文件 --- member.xml
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TableRow> <TextView android:id="@+id/_id" android:layout_height="wrap_content" android:layout_width="30px" /> <TextView android:id="@+id/name" android:layout_height="wrap_content" android:layout_width="100px" /> <TextView android:id="@+id/age" android:layout_height="wrap_content" android:layout_width="30px" /> <TextView android:id="@+id/birthday" android:layout_height="wrap_content" android:layout_width="100px" /> </TableRow> </TableLayout>
下面开始完成Activity程序的开发,分别调用ContentProvider类中定义的insert()、update()、delete()、query()方法。 MyContentProviderDemo.java
package org.lxh.demo; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.TextView; import android.widget.Toast; public class MyContentProviderDemo extends Activity { private Button insertBut = null ; // 操作按钮 private Button updateBut = null ; private Button deleteBut = null ; private Button queryBut = null ; private TextView mainInfo = null ; // 操作提示 private ListView memberList = null ; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.setContentView(R.layout.main); this.mainInfo = (TextView) super.findViewById(R.id.mainInfo) ; this.insertBut = (Button) super.findViewById(R.id.insertBut) ; this.updateBut = (Button) super.findViewById(R.id.updateBut) ; this.deleteBut = (Button) super.findViewById(R.id.deleteBut) ; this.queryBut = (Button) super.findViewById(R.id.queryBut) ; this.memberList = (ListView) super.findViewById(R.id.memberList) ; this.insertBut.setOnClickListener( new InsertOnClickListener()) ; this.updateBut.setOnClickListener( new UpdateOnClickListener()) ; this.deleteBut.setOnClickListener( new DeleteOnClickListener()) ; this.queryBut.setOnClickListener( new QueryOnClickListener()) ; } private long testInsert(String name,int age,String birthday) { // 取得ContentResolver对象 ContentResolver contentResolver = super.getContentResolver() ; ContentValues values = new ContentValues() ; values.put( MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_NAME, name) ; values.put( MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_AGE, age) ; values.put( MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_BIRTHDAY, birthday) ; Uri resultUri = contentResolver.insert( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, values); // 解析出返回的id数据 return ContentUris.parseId(resultUri) ; } private long testDelete(String _id) { // 取得ContentResolver对象 ContentResolver contentResolver = super.getContentResolver() ; long result = 0 ; if (_id == null || "".equals(_id)) { result = contentResolver.delete( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, null,null); } else { result = contentResolver.delete(Uri.withAppendedPath( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, _id),null, null); } return result ; } private long testUpdate(String _id, String name, int age, String birthday) { long result = 0 ; // 返回结果 // 取得ContentResolver对象 ContentResolver contentResolver = super.getContentResolver() ; ContentValues values = new ContentValues() ; values.put(MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_NAME, name) ; values.put(MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_AGE, age) ; values.put(MLDNDatabaseMetaData.MemberTableMetaData.MEMBER_BIRTHDAY, birthday) ; if(_id == null || "".equals(_id)) { // 更新全部 result = contentResolver.update( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, values, null, null) ; } else { // 按照id更新 result = contentResolver.update( Uri.withAppendedPath( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, _id), values, null, null); } return result ; // 解析出返回的id数据 } private Cursor testQuery(String id) { if(id == null || "".equals(id)) { // 查询全部 return super.getContentResolver().query( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, null,null, null, MLDNDatabaseMetaData.MemberTableMetaData.SORT_ORDER); } else { return super .getContentResolver() .query(Uri.withAppendedPath( MLDNDatabaseMetaData.MemberTableMetaData.CONTENT_URI, id), null, null, null, MLDNDatabaseMetaData.MemberTableMetaData.SORT_ORDER); } }
由于客户端访问ContentProvider程序时都必须依靠ContentResolver类完成,所以先使用super.getContentResolver()取得了一个ContentResolver对象。
private class InsertOnClickListener implements OnClickListener { @Override public void onClick(View v) { MyContentProviderDemo.this.mainInfo.setText( "执行的是增加操作...") ; // 接收返回的id数据 long id = 0 ; id = MyContentProviderDemo.this.testInsert("李兴华", 30, // 增加数据 new SimpleDateFormat("yyyy-MM-dd") .format(new Date())); Toast.makeText(MyContentProviderDemo.this, "数据增加成功,ID为:" + id, Toast.LENGTH_LONG).show(); } } private class DeleteOnClickListener implements OnClickListener { @Override public void onClick(View v) { MyContentProviderDemo.this.mainInfo.setText( "执行的是删除操作...") ; long result = 0 ; // 接收返回的id数据 // 更新数据 result = MyContentProviderDemo. this.testDelete(String.valueOf(4)); Toast.makeText(MyContentProviderDemo.this, "删除了" + result + "条记录", Toast.LENGTH_LONG).show(); } } private class UpdateOnClickListener implements OnClickListener { @Override public void onClick(View v) { MyContentProviderDemo.this.mainInfo.setText( "执行的是更新操作...") ; long result = 0 ; // 接收返回的id数据 // 更新数据 result = MyContentProviderDemo.this.testUpdate( "", "MLDN", 18,"1989-09-19"); Toast.makeText(MyContentProviderDemo.this, "更新了" + result + "条记录", Toast.LENGTH_LONG).show(); } } private class QueryOnClickListener implements OnClickListener { @Override public void onClick(View v) { MyContentProviderDemo.this.mainInfo.setText( "执行的是查询操作...") ; // 查询全部 Cursor result = MyContentProviderDemo.this.testQuery(null) ; // 结果集交给系统管理 MyContentProviderDemo.this.startManagingCursor(result) ; List<Map<String,Object>> members = new ArrayList<Map<String,Object>>() ; for (result.moveToFirst(); !result.isAfterLast(); result .moveToNext()) { Map<String,Object> member = new HashMap<String,Object>() ; member.put("_id", result.getInt(0)) ; member.put("name", result.getString(1)) ; member.put("age", result.getInt(2)) ; member.put("birthday", result.getString(3)) ; members.add(member) ; } MyContentProviderDemo.this.memberList .setAdapter(new SimpleAdapter( MyContentProviderDemo.this, members, R.layout.member, new String[] { "_id", "name", "age", "birthday" }, new int[] { R.id._id, R.id.name, R.id.age, R.id.birthday })); Toast.makeText(MyContentProviderDemo.this, "数据查询成功!", Toast.LENGTH_LONG).show(); } }
修改AndroidManifest.xml文件,配置ContentProvider应用
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.lxh.demo" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <provider android:name=".MemberContentProvider" android:authorities="org.lxh.demo.membercontentprovider" /> <activity android:name=".MyContentProviderDemo" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>