为了在应用程序之间交换数据,Android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他应用程序时,该应用程序就可通过提供Contentprovider来实现;其他应用程序就可通过ContentResolver来操作ContentProvider暴露的数据。
ContentProvider是以某种Uri的形式对外提供数据,允许其他应用访问或修改数据;其他应用程序使用ContentResolver根据Uri去访问操作指定数据。使用ContentProvider的步骤如下(假设B应用程序要使用A应用程序中的数据):
1、在A应用程序中的AndroidManifest.xml文件里的application节点里添加以下代码:
1 <provider 2 android:name="com.gnnuit.provider.PersonProvider" 3 android:authorities="com.gnnuit.provider.PersonProvider" > 4 </provider>
其中,android:name是自己编写的provider类的全名;android:authorities是外界访问的名字,就相当于为该ContentProvider指定域名。
2、在A应用程序里新建一个PersonProvider类使其继承ContentProvider基类。
为了确定ContentProvider实际能处理的Uri,以及确定每个方法中Uri参数所操作的数据,Android系统提供了UriMatcher工具类。UriMatcher工具类主要提供了以下两个方法:
(1)void arrURI(String authority,String path,int code):该方法用于向UriMatcher对象注册Uri。其中authority和path组合成一个Uri,而code则代表Uri对应的标识码。
(2)int match(Uri uri):根据前面注册的Uri来判断指定Uri对应的标识码。如果找不到匹配的标识码,该方法将会返回-1。源码如下:
1 package com.gnnuit.provider; 2 3 import com.gnnuit.dao.PersonDao; 4 import com.gnnuit.db.MyDbHelper; 5 6 import android.content.ContentProvider; 7 import android.content.ContentValues; 8 import android.content.UriMatcher; 9 import android.database.Cursor; 10 import android.database.sqlite.SQLiteDatabase; 11 import android.net.Uri; 12 import android.util.Log; 13 14 public class PersonProvider extends ContentProvider { 15 private static final int ALL_PERSONS = 1; 16 private static final int PERSON = 2; 17 private static final int HAHA = 3; 18 private static final int INSERT = 4; 19 private static final int DELETE = 5; 20 private static final int UPDATE = 6; 21 private static final String TAG = "PersonProvider"; 22 private MyDbHelper dbHelper; 23 // 创建了一个路径的识别器 uriMatcher 默认的返回值,如果没有找到匹配的类型 返回 -1; 24 private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); 25 static { 26 // 指定一个路径的匹配规则 27 // 如果路径 满足 content://com.gnnuit.provider.PersonProvider/persons 返回值就是( 28 // ALL_PERSONS) 1 29 matcher.addURI("com.gnnuit.provider.PersonProvider", "persons", 30 ALL_PERSONS); 31 // 如果路径 满足 content://com.gnnuit.provider.PersonProvider/person/10 返回值就是( 32 // PERSON) 2 33 matcher.addURI("com.gnnuit.provider.PersonProvider", "person/#", PERSON); 34 matcher.addURI("com.gnnuit.provider.PersonProvider", "haha", HAHA); 35 matcher.addURI("com.gnnuit.provider.PersonProvider", "insert", INSERT); 36 matcher.addURI("com.gnnuit.provider.PersonProvider", "delete", DELETE); 37 matcher.addURI("com.gnnuit.provider.PersonProvider", "update", UPDATE); 38 } 39 40 /** 41 * PeronProvder 内容提供者第一次被创建的时候 调用的方法 42 */ 43 @Override 44 public boolean onCreate() { 45 dbHelper = new MyDbHelper(getContext()); 46 return false; 47 } 48 49 @Override 50 public Cursor query(Uri uri, String[] projection, String selection, 51 String[] selectionArgs, String sortOrder) { 52 int result = matcher.match(uri); 53 switch (result) { 54 case ALL_PERSONS: 55 PersonDao dao = new PersonDao(getContext()); 56 return dao.getAllByCursor(); 57 case PERSON: 58 SQLiteDatabase db = dbHelper.getReadableDatabase(); 59 if (db.isOpen()) { 60 Cursor cursor = db.query("person", projection, selection, 61 selectionArgs, null, null, null); 62 return cursor; 63 } 64 case HAHA: 65 Log.i(TAG, "我是哈哈"); 66 return null; 67 default: 68 throw new IllegalArgumentException("URI不合法"); 69 } 70 } 71 72 /** 73 * 有的时候 我们需要知道内容提供者返回的数据类型 知道返回的数据 是一个集合呀 还是一个单独的条目 74 * 75 * 有的时候 告诉调用者 返回的数据是什么样的类型 MIME的数据类型 76 */ 77 @Override 78 public String getType(Uri uri) { 79 int result = matcher.match(uri); 80 switch (result) { 81 // 符合 content://com.gnnuit.provider.PersonProvider/persons 代表的返回所有的数据 82 case ALL_PERSONS: 83 return "vnd.android.cursor.dir/people"; 84 // content://com.gnnuit.provider.PersonProvider/person/10 85 case PERSON: 86 return "vnd.android.cursor.item/people"; 87 default: 88 return null; 89 } 90 } 91 92 @Override 93 public Uri insert(Uri uri, ContentValues values) { 94 int result = matcher.match(uri); 95 if (result == INSERT) { 96 SQLiteDatabase db = dbHelper.getWritableDatabase(); 97 db.insert("person", null, values); 98 // 当数据发生改变的时候 99 getContext().getContentResolver().notifyChange(uri, null); 100 return uri; 101 } else { 102 throw new IllegalArgumentException("URI不能被识别"); 103 } 104 } 105 106 @Override 107 public int delete(Uri uri, String selection, String[] selectionArgs) { 108 int result = matcher.match(uri); 109 if (result == DELETE) { 110 SQLiteDatabase db = dbHelper.getWritableDatabase(); 111 // 当数据发生改变的时候 112 getContext().getContentResolver().notifyChange(uri, null); 113 return db.delete("person", selection, selectionArgs); 114 } else { 115 throw new IllegalArgumentException("URI不能被识别"); 116 } 117 } 118 119 @Override 120 public int update(Uri uri, ContentValues values, String selection, 121 String[] selectionArgs) { 122 int result = matcher.match(uri); 123 if (result == UPDATE) { 124 SQLiteDatabase db = dbHelper.getWritableDatabase(); 125 // 当数据发生改变的时候 126 getContext().getContentResolver().notifyChange(uri, null); 127 return db.update("person", values, selection, selectionArgs); 128 } else { 129 throw new IllegalArgumentException("URI不能被识别"); 130 } 131 } 132 133 }
public String getType(Uri uri):该方法用于返回当前Uri所代表的MIME类型。如果该Uri对应数据可能包括多条记录,那么MIME类型字符串应该以vnd.android.cursor.dir/开头;如果该Uri对应的数据只包含一条记录,那么返回MIME类型字符串应该以vnd.android.cursor.item/开头。
3、在B应用程序中使用,首先我们要得到一个ContentResolver对象,Context提供了getContentResolver()方法来获取ContentResolver对象。源码如下:
1 package com.gnnuit.other; 2 3 import android.net.Uri; 4 import android.os.Bundle; 5 import android.app.Activity; 6 import android.content.ContentResolver; 7 import android.database.Cursor; 8 import android.view.Menu; 9 10 public class MainActivity extends Activity { 11 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_main); 16 ContentResolver resolver = getContentResolver(); 17 Uri uri = Uri.parse("content://com.gnnuit.provider.PersonProvider/persons"); 18 Cursor cursor = resolver.query(uri, null, null, null, null); 19 if (cursor != null) { 20 while (cursor.moveToNext()) { 21 String name = cursor.getString(cursor.getColumnIndex("name")); 22 String age = cursor.getString(cursor.getColumnIndex("age")); 23 System.out.println("姓名:" + name + "年命:" + age); 24 } 25 } else { 26 System.out.println("cursor为空"); 27 } 28 } 29 30 @Override 31 public boolean onCreateOptionsMenu(Menu menu) { 32 // Inflate the menu; this adds items to the action bar if it is present. 33 getMenuInflater().inflate(R.menu.main, menu); 34 return true; 35 } 36 37 }
4、ContentProvider的Uri简介
ContentProvider的Uri类似于HTTP的Uri,例如以下的Uri:
content://com.gnnuit.provider.personprovider/persons
它可以分为以下三个部分:
(1)content://:这个部分是Android的ContentProvider规定的,就像http://一样。暴露ContentProvider、访问ContentProvider的协议默认是content://。
(2)com.gnnuit.provider.personprovider:这个部分是ContentProvider的authority。系统就是由这个部分来找到操作哪个ContentProvider。只要访问指定的ContentProvider,这个部分总是固定的。
(3)persons:资源部分,当访问者需要访问不同资源时,这个部分是动态改变的。
5、几种典型的Uri含义:
(1)content://com.gnnuit.provider.personprovider/persons
此时它要访问的资源为persons,这意味着访问perosn数据中的所有记录。
(2)content://com.gnnuit.provider.personprovider/person/2
此时它要访问的资源为person/2,这意味着访问person数据中ID为2的记录。
(3)content://com.gnnuit.provider.personprovider/person/2/name
此时它要访问的资源为person/2/name,这意味着访问perosn数据中ID为2的记录的name字段。
(4)大部分ContentProvider所操作的数据都来自于数据库,但有时这些数据也可来自于文件、XML或网络等其他存储方式,此时的Uri可改为如下形式:
content://com.gnnuit.provider.personprovider/person/name/
上面的Uri表示操作person节点下的name节点。
6、将一个字符串转化成Uri的方法:
Uri uri=Uri.parse("content://com.gnnuit.provider.personprovider/persons");