再探Android多应用间数据共享机制,自定义ContentProvider

25
回复
916233
查看
[复制链接]

328

主题

383

帖子

4629

安币

码皇(巴士元老)

Rank: 8Rank: 8

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


类AcMain.java,为主Activity,用来实现应用的主界面控件和流程,代码:
  1. //AcMain.java
  2. package jtapp.contentproviders;

  3. import android.app.Activity;
  4. import android.content.ContentValues;
  5. import android.database.Cursor;
  6. import android.os.Bundle;
  7. import android.view.View;
  8. import android.view.View.OnClickListener;
  9. import android.widget.Button;
  10. import android.widget.TextView;

  11. public class AcMain extends Activity {
  12.         private Button btInsertData = null;
  13.         private Button btViewData = null;
  14.         private Button btDelOne = null;
  15.         private Button btClearAll = null;

  16.         /** Called when the activity is first created. */
  17.         @Override
  18.         public void onCreate(Bundle savedInstanceState) {
  19.                 super.onCreate(savedInstanceState);
  20.                 setContentView(R.layout.main);

  21.                 btInsertData = (Button) findViewById(R.id.Button02);
  22.                 btInsertData.setOnClickListener(new ClickViewHandler());
  23.                 btViewData = (Button) findViewById(R.id.Button03);
  24.                 btViewData.setOnClickListener(new ClickViewHandler());
  25.                 btDelOne = (Button) findViewById(R.id.Button04);
  26.                 btDelOne.setOnClickListener(new ClickViewHandler());
  27.                 btClearAll = (Button) findViewById(R.id.Button05);
  28.                 btClearAll.setOnClickListener(new ClickViewHandler());
  29.         }

  30.         public class ClickViewHandler implements OnClickListener {
  31.                 @Override
  32.                 public void onClick(View v) {
  33.                         if (v == btInsertData) {
  34.                                 InsertSomeRecords();
  35.                         } else if (v == btViewData) {
  36.                                 ViewRecords();
  37.                         } else if (v == btDelOne) {
  38.                                 DelOne();
  39.                         } else if (v == btClearAll) {
  40.                                 DelAllPeople();
  41.                         }
  42.                 }

  43.                 private void DelAllPeople() {
  44.                         getContentResolver().delete(MyContacts.CONTENT_URI, null, null);
  45.                 }

  46.                 private void DelOne() {
  47.                         int id;
  48.                         Cursor c = getContentResolver().query(
  49.                                         MyContacts.CONTENT_URI, null,
  50.                                         null, null, MyContacts.NAME + " ASC");
  51.                         if (c.moveToFirst()) {
  52.                                 int idxID = c.getColumnIndex(MyContacts._ID);
  53.                                 id = c.getInt(idxID);
  54.                                 getContentResolver().delete(MyContacts.CONTENT_URI,
  55.                                                 MyContacts._ID + " = " + id, null);
  56.                         }
  57.                 }

  58.                 private void ViewRecords() {
  59.                         // Make the query
  60.                         Cursor c = managedQuery(MyContacts.CONTENT_URI, null, null, null,
  61.                                         MyContacts._ID);
  62.                         StringBuilder sbRecords = new StringBuilder("");
  63.                         if (c.moveToFirst()) {
  64.                                 int idxID = c.getColumnIndex(MyContacts._ID);
  65.                                 int idxName = c.getColumnIndex(MyContacts.NAME);
  66.                                 int idxNumber = c.getColumnIndex(MyContacts.NUMBER1);
  67.                                 int idxEmail = c.getColumnIndex(MyContacts.EMAIL);
  68.                                 // Iterator the records
  69.                                 do {
  70.                                         sbRecords.append(c.getInt(idxID));
  71.                                         sbRecords.append(". ");
  72.                                         sbRecords.append(c.getString(idxName));
  73.                                         sbRecords.append(", ");
  74.                                         sbRecords.append(c.getString(idxNumber));
  75.                                         sbRecords.append(", ");
  76.                                         sbRecords.append(c.getString(idxEmail));
  77.                                         sbRecords.append("/n");
  78.                                 } while (c.moveToNext());
  79.                         }
  80.                         c.close();
  81.                         // Refresh the content of TextView
  82.                         ((TextView)(findViewById(
  83.                                         R.id.TextView01))).setText(sbRecords);
  84.                 }

  85.                 private void InsertSomeRecords() {
  86.                         ContentValues values = new ContentValues();
  87.                         values.put(MyContacts.NAME, "朱元璋");
  88.                         values.put(MyContacts.NUMBER1, "13965625585");
  89.                         getContentResolver().insert(MyContacts.CONTENT_URI, values);
  90.                         values.clear();
  91.                         values.put(MyContacts.NAME, "玄烨");
  92.                         values.put(MyContacts.EMAIL, "xueye1772@gmail.com");
  93.                         getContentResolver().insert(MyContacts.CONTENT_URI, values);
  94.                 }
  95.         }
  96. }
复制代码

代码中通过getContentResolver()调用contentprovider的delete、insert等操作,由系统根据uri决定调用哪个provider。
query查询除了用getContentResolver().query以外,还可以用activity.managedQuery调用,后者的Cursor的生命周期是由activity来自动管理,本文中的query就是属于这种情况。
主界面ui定义,main.xml,代码:
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.         android:orientation="vertical" android:layout_width="fill_parent"
  3.         android:layout_height="fill_parent">
  4.         <TextView android:layout_width="fill_parent"
  5.                 android:layout_height="wrap_content" android:text="@string/hello" />
  6.         <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"
  7.                 android:layout_height="wrap_content">
  8.                 <Button android:text="insert some records" android:id="@+id/Button02"
  9.                         android:height="30px" android:layout_width="wrap_content"
  10.                         android:layout_height="wrap_content" />
  11.         </TableRow>
  12.         <TableRow android:id="@+id/TableRow01" android:layout_width="wrap_content"
  13.                 android:layout_height="wrap_content">
  14.                 <Button android:text="delete one" android:id="@+id/Button04"
  15.                         android:height="30px" android:layout_width="wrap_content"
  16.                         android:layout_height="wrap_content" />
  17.                 <Button android:text="clear all" android:id="@+id/Button05"
  18.                         android:height="30px" android:layout_width="wrap_content"
  19.                         android:layout_height="wrap_content" />
  20.         </TableRow>
  21.         <Button android:text="view records" android:id="@+id/Button03"
  22.                 android:height="30px" android:layout_width="wrap_content"
  23.                 android:layout_height="wrap_content" android:layout_gravity="center" />
  24.         <TextView android:text="..." android:id="@+id/TextView01"
  25.                 android:layout_width="wrap_content" android:layout_height="wrap_content" />
  26. </LinearLayout>
复制代码

MyContentProvider.java,代码:
  1. package jtapp.contentproviders;
  2. import android.content.ContentProvider;
  3. import android.content.ContentUris;
  4. import android.content.ContentValues;
  5. import android.content.Context;
  6. import android.database.Cursor;
  7. import android.database.SQLException;
  8. import android.database.sqlite.SQLiteDatabase;
  9. import android.database.sqlite.SQLiteQueryBuilder;
  10. import android.database.sqlite.SQLiteStatement;
  11. import android.net.Uri;
  12. import android.text.TextUtils;
  13. import android.util.Log;

  14. public class MyContactsProvider extends ContentProvider {
  15.         private static final String TAG = "MyContactsProvider";
  16.         private static SQLiteDatabase mDB;

  17.         private static void createTablesIfNotExists() {
  18.                 mDB.execSQL("CREATE TABLE IF NOT EXISTS "   
  19.                 + MyContacts.TB_NAME + " ("   
  20.                 + MyContacts._ID + " INTEGER PRIMARY KEY,"   
  21.                 + MyContacts.NAME + " VARCHAR,"  
  22.                 + MyContacts.NUMBER1 + " VARCHAR,"
  23.                 + MyContacts.EMAIL + " VARCHAR)");
  24.         }

  25.         @Override
  26.         public int delete(Uri uri, String selection, String[] selectionArgs) {
  27.                 int count;
  28.                 switch (MyContacts.uriMatcher.match(uri)) {
  29.                         case MyContacts.CONTACTS:
  30.                                 count = mDB.delete(MyContacts.TB_NAME,
  31.                                                 selection, selectionArgs);
  32.                                 break;
  33.                         case MyContacts.CONTACT_ID:
  34.                                 String contactID = uri.getPathSegments().get(1);
  35.                                 count = mDB.delete(MyContacts.TB_NAME,
  36.                                                 MyContacts._ID + "=" + contactID, selectionArgs);
  37.                                 break;
  38.                         default: throw new IllegalArgumentException(
  39.                                         "Unsupported URI: " + uri);
  40.                 }
  41.                 return count;
  42.         }

  43.         @Override
  44.         public String getType(Uri uri) {
  45.                 switch (MyContacts.uriMatcher.match(uri)) {
  46.                         case MyContacts.CONTACTS:
  47.                         return "vnd.android.cursor.dir/vnd.jtapp.contacts";
  48.                         case MyContacts.CONTACT_ID:
  49.                         return "vnd.android.cursor.item/vnd.ambow.contacts";
  50.                         default:
  51.                         throw new IllegalArgumentException("Unsupported URI: " + uri);
  52.                 }
  53.         }

  54.         @Override
  55.         public Uri insert(Uri uri, ContentValues contentValues) {
  56.                 long rowId = mDB.insert(MyContacts.TB_NAME, null, contentValues);
  57.                 if (rowId > 0) {
  58.                         Uri noteUri =
  59.                                 ContentUris.withAppendedId(MyContacts.CONTENT_URI,rowId);
  60.                         getContext().getContentResolver().notifyChange(noteUri, null);
  61.                         Log.d(TAG+"insert",noteUri.toString());
  62.                         return noteUri;
  63.                 } else {
  64.                     throw new SQLException("Failed to insert row into " + uri);
  65.                 }
  66.         }

  67.         @Override
  68.         public boolean onCreate() {
  69.                 if (mDB == null) {
  70.                         mDB = this.getContext().openOrCreateDatabase(MyContacts.TB_NAME,
  71.                                         Context.MODE_PRIVATE, null);
  72.                         createTablesIfNotExists();
  73.                 }
  74.                 return mDB != null;
  75.         }

  76.         @Override
  77.         public Cursor query(Uri uri, String[] projection, String selection,
  78.                         String[] selectionArgs, String sortOrder) {
  79.                 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
  80.                 qb.setTables(MyContacts.TB_NAME);
  81.                
  82.                 switch (MyContacts.uriMatcher.match(uri)) {
  83.                         case MyContacts.CONTACT_ID:
  84.                                 qb.appendWhere(
  85.                                                 MyContacts._ID + "=" + uri.getPathSegments().get(1));
  86.                                 break;
  87.                 }
  88.                 String orderBy;
  89.                 if (TextUtils.isEmpty(sortOrder)) {
  90.                         orderBy = MyContacts._ID;
  91.                 } else {
  92.                         orderBy = sortOrder;
  93.                 }
  94.                 Cursor c = qb.query(mDB, projection, selection,
  95.                                 selectionArgs,null, null,orderBy);
  96.                 return c;       
  97.         }

  98.         @Override
  99.         public int update(Uri uri, ContentValues contentValues, String selection,
  100.                         String[] selectionArgs) {

  101.                 Log.d(TAG+"update",contentValues.toString());
  102.                 Log.d(TAG+"update",uri.toString());
  103.                
  104.                 int count;               
  105.                 switch (MyContacts.uriMatcher.match(uri)) {
  106.                         case MyContacts.CONTACTS:
  107.                                 Log.d(TAG+"update",MyContacts.CONTACTS+"");
  108.                                 count = mDB.update(
  109.                                                 MyContacts.TB_NAME, contentValues,
  110.                                                 selection, selectionArgs);
  111.                                 break;
  112.                         case MyContacts.CONTACT_ID:
  113.                                 String contactID = uri.getPathSegments().get(1);
  114.                                 Log.d(TAG+"update",contactID+"");
  115.                                 count = mDB.update(MyContacts.TB_NAME,contentValues,
  116.                                                 MyContacts._ID + "=" + contactID,
  117.                                                 selectionArgs);
  118.                                 break;
  119.                         default: throw new IllegalArgumentException(
  120.                                         "Unsupported URI: " + uri);
  121.                 }
  122.                 return count;
  123.         }
  124. }
复制代码
MyContentProvider扩展了android.content.ContentProvider类,数据层的操作就在该类中完成。sqlite、文件形式、内存对象,持久化或者非持久化数据存储都可以包装在此类中,本文中使用了sqlite数据库进行持久化存储。
getContext().getContentResolver().notifyChange可以通知观察者数据发生改变,这是处理多应用调用时数据同步的关键,本文并没有完整的展现。自定义的MyContentProvider.java中还实现了update方法,在AcMain中没有调用到,你可尝试一下如何实现。

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

  3. import android.content.UriMatcher;
  4. import android.net.Uri;
  5. import android.provider.BaseColumns;

  6. public class MyContacts implements BaseColumns {
  7.         public MyContacts(){
  8.         }
  9.         public static final String AUTHORITY =
  10.                 "jtapp.contentproviders.contacts";
  11.         public static final String TB_NAME = "mycontacts";
  12.         public static final Uri CONTENT_URI = Uri.parse(
  13.                 "content://" + AUTHORITY + "/" + TB_NAME);
  14.        
  15.         public static final int CONTACTS = 1;
  16.         public static final int CONTACT_ID = 2;
  17.         public static final UriMatcher uriMatcher;
  18.         static{
  19.                 uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  20.                 uriMatcher.addURI(AUTHORITY,"mycontacts",CONTACTS);
  21.                 uriMatcher.addURI(AUTHORITY,"mycontacts/#",CONTACT_ID);
  22.         }
  23.        
  24.         public static final String _ID = "id";
  25.         public static final String NAME = "name";
  26.         public static final String NUMBER1 = "number1";
  27.         public static final String EMAIL = "email";
  28. }
复制代码

应用配置文件AndroidManifest.xml 代码:
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3.         package="jtapp.contentproviders" android:versionCode="1"
  4.         android:versionName="1.0">
  5.         <application android:icon="@drawable/icon" android:label="@string/app_name">
  6.                 <activity android:name=".AcMain" android:label="@string/app_name">
  7.                         <intent-filter>
  8.                                 <action android:name="android.intent.action.MAIN" />
  9.                                 <category android:name="android.intent.category.LAUNCHER" />
  10.                         </intent-filter>
  11.                 </activity>
  12.                 <provider android:authorities="jtapp.contentproviders.contacts"
  13.                         android:name="MyContactsProvider"></provider>
  14.         </application>
  15. </manifest>
复制代码
主要是里边插入了provider标签,向系统声明了自定义Provider的实现。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

2

主题

187

帖子

17

安币

初级码农

IT男

Rank: 1

QQ达人

QQ
发表于 2011-11-14 15:58:08 | 显示全部楼层
恩!还不错!
努力!!!

0

主题

9

帖子

44

安币

初级码农

Rank: 1

发表于 2011-12-27 11:04:04 | 显示全部楼层
终于有了哈哈

0

主题

97

帖子

78

安币

程序猿

Rank: 2

发表于 2012-1-8 13:21:02 | 显示全部楼层
向上向上继续向上。。。

98

主题

1077

帖子

4132

安币

码皇(巴士元老)

Android奋斗者

Rank: 8Rank: 8

QQ达人

QQ
发表于 2012-4-12 20:03:32 | 显示全部楼层
不错不错,学习了
加油!!

0

主题

22

帖子

9

安币

初级码农

Rank: 1

发表于 2012-4-17 17:57:15 | 显示全部楼层
不错,拿走了。

0

主题

9

帖子

-2

安币

初级码农

Rank: 1

发表于 2012-5-23 14:11:34 | 显示全部楼层
{:Skateboard:}{:Skateboard:}{:Skateboard:}{:Skateboard:}{:Skateboard:}

4

主题

369

帖子

206

安币

攻城狮

Rank: 3Rank: 3

QQ达人

发表于 2012-7-4 11:24:13 | 显示全部楼层
{:Skateboard:}{:Board:}
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )