Android中的ContentProvider是一种多应用数据共享的机制,任何时候同一Provider只会创建一次,是由系统进行初始化和管理的。本文中将通过实现一个简单通讯录的插入、删除、查询操作来让你了解ContentProvider机制极其自定义过程。读过本系列第二篇(读取手机中通讯录)和第三篇(sqlite数据库操作)的读者可以发现,本文中实现的应用以这两篇内容为基础的。虽然,本文的MyContentProvider使用sqlite数据库进行持久化存储操作,包装后以ContentProvider机制供各app调用。但是,为理解ContentProvider,你必须有这样两个概念:一、它是一种可以跨应用共享数据的机制,正如本文开头所说。二、底层的存储在实现你的ContentProvider的时候可以自定义,即可以为数据库、也可以为文件,持久化或非持久化存储的其他形式。

程序截图如下:

类AcMain.java,为主Activity,用来实现应用的主界面控件和流程,代码:

//AcMain.java package jtapp.contentproviders; import android.app.Activity; import android.content.ContentValues; import android.database.Cursor; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class AcMain extends Activity { private Button btInsertData = null; private Button btViewData = null; private Button btDelOne = null; private Button btClearAll = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btInsertData = (Button) findViewById(R.id.Button02); btInsertData.setOnClickListener(new ClickViewHandler()); btViewData = (Button) findViewById(R.id.Button03); btViewData.setOnClickListener(new ClickViewHandler()); btDelOne = (Button) findViewById(R.id.Button04); btDelOne.setOnClickListener(new ClickViewHandler()); btClearAll = (Button) findViewById(R.id.Button05); btClearAll.setOnClickListener(new ClickViewHandler()); } public class ClickViewHandler implements OnClickListener { @Override public void onClick(View v) { if (v == btInsertData) { InsertSomeRecords(); } else if (v == btViewData) { ViewRecords(); } else if (v == btDelOne) { DelOne(); } else if (v == btClearAll) { DelAllPeople(); } } private void DelAllPeople() { getContentResolver().delete(MyContacts.CONTENT_URI, null, null); } private void DelOne() { int id; Cursor c = getContentResolver().query( MyContacts.CONTENT_URI, null, null, null, MyContacts.NAME + " ASC"); if (c.moveToFirst()) { int idxID = c.getColumnIndex(MyContacts._ID); id = c.getInt(idxID); getContentResolver().delete(MyContacts.CONTENT_URI, MyContacts._ID + " = " + id, null); } } private void ViewRecords() { // Make the query Cursor c = managedQuery(MyContacts.CONTENT_URI, null, null, null, MyContacts._ID); StringBuilder sbRecords = new StringBuilder(""); if (c.moveToFirst()) { int idxID = c.getColumnIndex(MyContacts._ID); int idxName = c.getColumnIndex(MyContacts.NAME); int idxNumber = c.getColumnIndex(MyContacts.NUMBER1); int idxEmail = c.getColumnIndex(MyContacts.EMAIL); // Iterator the records do { sbRecords.append(c.getInt(idxID)); sbRecords.append(". "); sbRecords.append(c.getString(idxName)); sbRecords.append(", "); sbRecords.append(c.getString(idxNumber)); sbRecords.append(", "); sbRecords.append(c.getString(idxEmail)); sbRecords.append("/n"); } while (c.moveToNext()); } c.close(); // Refresh the content of TextView ((TextView)(findViewById( R.id.TextView01))).setText(sbRecords); } private void InsertSomeRecords() { ContentValues values = new ContentValues(); values.put(MyContacts.NAME, "朱元璋"); values.put(MyContacts.NUMBER1, "13965625585"); getContentResolver().insert(MyContacts.CONTENT_URI, values); values.clear(); values.put(MyContacts.NAME, "玄烨"); values.put(MyContacts.EMAIL, "[email protected]"); getContentResolver().insert(MyContacts.CONTENT_URI, values); } } }

代码中通过getContentResolver()调用contentprovider的delete、insert等操作,由系统根据uri决定调用哪个provider。

query查询除了用getContentResolver().query以外,还可以用activity.managedQuery调用,后者的Cursor的生命周期是由activity来自动管理,本文中的query就是属于这种情况。

主界面ui定义,main.xml,代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:text="insert some records" android:id="@+id/Button02" android:height="30px" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </TableRow> <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:text="delete one" android:id="@+id/Button04" android:height="30px" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <Button android:text="clear all" android:id="@+id/Button05" android:height="30px" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </TableRow> <Button android:text="view records" android:id="@+id/Button03" android:height="30px" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> <TextView android:text="..." android:id="@+id/TextView01" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>

MyContentProvider.java,代码:

package jtapp.contentproviders; import android.content.ContentProvider; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteStatement; import android.net.Uri; import android.text.TextUtils; import android.util.Log; public class MyContactsProvider extends ContentProvider { private static final String TAG = "MyContactsProvider"; private static SQLiteDatabase mDB; private static void createTablesIfNotExists() { mDB.execSQL("CREATE TABLE IF NOT EXISTS " + MyContacts.TB_NAME + " (" + MyContacts._ID + " INTEGER PRIMARY KEY," + MyContacts.NAME + " VARCHAR," + MyContacts.NUMBER1 + " VARCHAR," + MyContacts.EMAIL + " VARCHAR)"); } @Override public int delete(Uri uri, String selection, String[] selectionArgs) { int count; switch (MyContacts.uriMatcher.match(uri)) { case MyContacts.CONTACTS: count = mDB.delete(MyContacts.TB_NAME, selection, selectionArgs); break; case MyContacts.CONTACT_ID: String contactID = uri.getPathSegments().get(1); count = mDB.delete(MyContacts.TB_NAME, MyContacts._ID + "=" + contactID, selectionArgs); break; default: throw new IllegalArgumentException( "Unsupported URI: " + uri); } return count; } @Override public String getType(Uri uri) { switch (MyContacts.uriMatcher.match(uri)) { case MyContacts.CONTACTS: return "vnd.android.cursor.dir/vnd.jtapp.contacts"; case MyContacts.CONTACT_ID: return "vnd.android.cursor.item/vnd.ambow.contacts"; default: throw new IllegalArgumentException("Unsupported URI: " + uri); } } @Override public Uri insert(Uri uri, ContentValues contentValues) { long rowId = mDB.insert(MyContacts.TB_NAME, null, contentValues); if (rowId > 0) { Uri noteUri = ContentUris.withAppendedId(MyContacts.CONTENT_URI,rowId); getContext().getContentResolver().notifyChange(noteUri, null); Log.d(TAG+"insert",noteUri.toString()); return noteUri; } else { throw new SQLException("Failed to insert row into " + uri); } } @Override public boolean onCreate() { if (mDB == null) { mDB = this.getContext().openOrCreateDatabase(MyContacts.TB_NAME, Context.MODE_PRIVATE, null); createTablesIfNotExists(); } return mDB != null; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(MyContacts.TB_NAME); switch (MyContacts.uriMatcher.match(uri)) { case MyContacts.CONTACT_ID: qb.appendWhere( MyContacts._ID + "=" + uri.getPathSegments().get(1)); break; } String orderBy; if (TextUtils.isEmpty(sortOrder)) { orderBy = MyContacts._ID; } else { orderBy = sortOrder; } Cursor c = qb.query(mDB, projection, selection, selectionArgs,null, null,orderBy); return c; } @Override public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) { Log.d(TAG+"update",contentValues.toString()); Log.d(TAG+"update",uri.toString()); int count; switch (MyContacts.uriMatcher.match(uri)) { case MyContacts.CONTACTS: Log.d(TAG+"update",MyContacts.CONTACTS+""); count = mDB.update( MyContacts.TB_NAME, contentValues, selection, selectionArgs); break; case MyContacts.CONTACT_ID: String contactID = uri.getPathSegments().get(1); Log.d(TAG+"update",contactID+""); count = mDB.update(MyContacts.TB_NAME,contentValues, MyContacts._ID + "=" + contactID, selectionArgs); break; default: throw new IllegalArgumentException( "Unsupported URI: " + uri); } return count; } }

MyContentProvider扩展了android.content.ContentProvider类,数据层的操作就在该类中完成。sqlite、文件形式、内存对象,持久化或者非持久化数据存储都可以包装在此类中,本文中使用了sqlite数据库进行持久化存储。

getContext().getContentResolver().notifyChange可以通知观察者数据发生改变,这是处理多应用调用时数据同步的关键,本文并没有完整的展现。自定义的MyContentProvider.java中还实现了update方法,在AcMain中没有调用到,你可尝试一下如何实现。

与MyContentProvider有关的表mycontacts相对应类MyContacts.java,其中定义了唯一资源标示URI,表结构字段名等。任何contentprovider的调用都是通过系统来进行,因此,URI起到了定位资源和特定provider类的作用。

//MyContacts.java package jtapp.contentproviders; import android.content.UriMatcher; import android.net.Uri; import android.provider.BaseColumns; public class MyContacts implements BaseColumns { public MyContacts(){ } public static final String AUTHORITY = "jtapp.contentproviders.contacts"; public static final String TB_NAME = "mycontacts"; public static final Uri CONTENT_URI = Uri.parse( "content://" + AUTHORITY + "/" + TB_NAME); public static final int CONTACTS = 1; public static final int CONTACT_ID = 2; public static final UriMatcher uriMatcher; static{ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY,"mycontacts",CONTACTS); uriMatcher.addURI(AUTHORITY,"mycontacts/#",CONTACT_ID); } public static final String _ID = "id"; public static final String NAME = "name"; public static final String NUMBER1 = "number1"; public static final String EMAIL = "email"; }

应用配置文件AndroidManifest.xml 代码:

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="jtapp.contentproviders" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".AcMain" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <provider android:authorities="jtapp.contentproviders.contacts" android:name="MyContactsProvider"></provider> </application> </manifest>

主要是里边插入了provider标签,向系统声明了自定义Provider的实现。

参考:http://aijiawang-126-com.javaeye.com/blog/655268等。

更多相关文章

  1. Android(安卓)换肤方案(2种)
  2. 我在Mac OS X 操作系统上搭建Android开发环境的经历
  3. Android中AIDL的使用(一) 之 AIDL经典示例
  4. Android调用天气接口(和风天气)
  5. 动手撸一个Android路由框架LuRouter
  6. 如何确定Android中刚修改后的c/c++是否编译成功
  7. 关于Android(安卓)EditText图文混排的总结
  8. Gradle Kotlin DSL , 你知道它吗?
  9. Android:调用系统图库/裁剪图片

随机推荐

  1. android 播放视频保存的一些网页
  2. android manifest.xml中元素含义android
  3. android默认字体大小、高度、宽度
  4. windowSoftInputMode属性设置值
  5. android权限
  6. Android(安卓)获取当前设备的IP地址
  7. android画统计图的chart engine
  8. android页面间传递对象
  9. Android电池管理
  10. Android定制出厂默认输入法