幸运星空

Lucker的程序人生

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
Android中的Content Provider可以实现在权限许可的情况下,在多个应用程序之间共享数据。Android还提供了一些主要数据类型如音频、视频、图片和私人通讯录等现成的Content provider类。当然,如果我们想让我们应用程序的数据公有化,使其它应用也可以访问,那么,我们可以实现一个自己的ContentProvider类。
一种类型的ContentProvider只允许有一个实例,但它可以和多个不同的应用程序或进程的ContentResolver进行通信。进程间的交互就是由ContentResolver和ContentProvider一起完成的。我们可以通过getContentResolver()方法来获得 ContentResolver对象。 
数据模型: 
ContentProvider以数据表的形式对外暴露,其中每一行数据都有一个唯一的_ID值。每次查询数据时都会返回一个Cursor 对象。 不过使用Cursor对象获取数据前一定要先知道数据的类型。 
Android中通过URI来定位各种资源,每一个可以调用的资源都有一个唯一的URI,如图片,视频等。同样,ContentProvider中的每一个表也各有一个唯一的URI。ContentProvider提供的URI都是以content://开头的。在所有ContentProvider交互中都要用到URI,而且,每个ContentResolver方法的第一个参数就是URI,它告诉ContentResolver方法要访问的ContentProvider对象,以及操作的目标表。 因此,为了方便,给自定义ContentProvider中的URI指定一个专门的CONTENT_URI常量是很有必要的。
通过Content Provider查询数据前要准备的: 
1,要查询数据的Provider的URI; 
2,要查询的数据的列名以及它们的数据类型;其中_ID和_COUNT列唯一某行数据以及总数据行数。 
3,如果是某一行数据,还需要知道它的ID值;如果_ID=23 则为“content://. . . ./23” 
查询数据: 
可以用ContentResolver.query()方法或Activity.managedQuery()方法来获取结果Cursor。后者得到的Cursor的生命周期由Activity来管理,而不需要我们再手动关闭游标,我们还可以方便的精确控制它的加载与释放。Activity.startManagingCursor()方法可以将未受管理的游标加入到管理列表中(注:2.3版以后推荐使用getLoaderManager()得到LoaderManger对象来管理游标)stopManagingCursor(Cursor)可以停止自动管理功能。 
1,获取URI: 
ContentUris.withAppendedId() 
Uri.withAppendedPath() 
以上两个方法都可以实现将参数(ID)添加到查询URI当中去。 
而ContentUris.parseId(uri)方法可以获取URI中的ID部分。
示例: 
import android.provider.Contacts.People; 
import android.content.ContentUris; 
import android.net.Uri; 
import android.database.Cursor; 
Uri myPerson = ContentUris.withAppendedId(People.CONTENT_URI, 23); 
Uri myPerson = Uri.withAppendedPath(People.CONTENT_URI, "23"); 
Cursor cur = managedQuery(myPerson, null, null, null, null); 
2,读取数据: 
private void getColumnData(Cursor cur){ 
    if (cur.moveToFirst()) { 
        String name; 
        String phoneNumber; 
        int nameColumn = cur.getColumnIndex(People.NAME); 
        int phoneColumn = cur.getColumnIndex(People.NUMBER); 
        String imagePath; 
    
        do { 
            // Get the field values 
            name = cur.getString(nameColumn); 
            phoneNumber = cur.getString(phoneColumn); 
            
            // Do something with the values. 
            ... 
        } while (cur.moveToNext()); 
    } 
如果是较小的二进制数据,可以直接像普通数据一样保存到表中去,但如果二进制数据量较大,且表的URI是content:URI形式的,则我们需要采用ContentResolver.openInputStream()方法来获得数据流,以便读取数据。 
所有数据的更改都需要调用ContentResolver的方法来完成。 
首先,将要更改的数据保存到ContentValues对象中,然后调用ContentResolver的相应方法面完成更新操作,示例: 
增加新记录: 
ContentValues values = new ContentValues(); 
values.put(People.NAME, "Abraham Lincoln"); 
values.put(People.STARRED, 1); 
Uri uri = getContentResolver().insert(People.CONTENT_URI, values); 
在原有记录上增加新值: 
Uri phoneUri = null; 
phoneUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); 
values.clear(); 
values.put(People.Phones.TYPE, People.Phones.TYPE_MOBILE); 
values.put(People.Phones.NUMBER, "1233214567"); 
getContentResolver().insert(phoneUri, values); 
其中的CONTENT_DIRECTORY是一个常量,表明这是追加的数据。 
如果数据是content:URI形式的二进制大对象,调用ContentResolver.openOutputStream()来保存。 
大二进制数据(多媒体数据)处理示例: 
import android.provider.MediaStore.Images.Media; 
import android.content.ContentValues; 
import java.io.OutputStream; 
// Save the name and description of an image in a ContentValues map.   
ContentValues values = new ContentValues(3); 
values.put(Media.DISPLAY_NAME, "road_trip_1"); 
values.put(Media.DESCRIPTION, "Day 1, trip to Los Angeles"); 
values.put(Media.MIME_TYPE, "image/jpeg"); 
// Add a new record without the bitmap, but with the values just set. 
// insert() returns the URI of the new record. 
Uri uri = getContentResolver().insert(Media.EXTERNAL_CONTENT_URI, values); 
// Now get a handle to the file for that record, and save the data into it. 
// Here, sourceBitmap is a Bitmap object representing the file to save to the database. 
try { 
    OutputStream outStream = getContentResolver().openOutputStream(uri); 
    sourceBitmap.compress(Bitmap.CompressFormat.JPEG, 50, outStream); 
    outStream.close(); 
} catch (Exception e) { 
    Log.e(TAG, "exception while writing image", e); 
实现我们自己的Content Provider: 
1,需要创建一个类并且继承ContentProvider类,并实现这个抽象类中的六个方法。 
public int delete(Uri uri, String selection, String[] selectionArgs){} 
public Uri insert(Uri uri, ContentValues values) {} 
public Cursor query(Uri uri, String[] projection, String selection, 
String[] selectionArgs, String sortOrder) {}  //SQLiteCursor,MatrixCursor 
public int update(Uri uri, ContentValues values, String selection, 
String[] selectionArgs) {} 
public boolean onCreate() {} 
public String getType(Uri uri) {} 
2,定义URI常量: 
public static final Uri CONTENT_URI; 
CONTENT_URI=Uri.parse("content://com.example.codelab.transportationprovider"); 
3,定义列名,不要忘记_ID列。 
public static String ColumnName 
4,如果我们的数据在是新的类型,必须在getType ()中返回这个定义好的MIME 类型,自定义类型的名称格式为: 
vnd.android.cursor.item/vnd.yourcompanyname.contenttype 
vnd.android.cursor.dir/vnd.yourcompanyname.contenttype 
5,当保存大二进制数据时,列名下实际存储的是content:URI,另声明一个“_data”列,保存文件的真实路径,以供ContentResolver.openInputStream()时访问。 
6,当数据发生改变时,最好还要调用ContentResolver.notifyChange()方法,来通知调用程序。 
7,在AndroidManifest.xml中声明ContentProvider。 
示例: 
<provider android:name=".AutoInfoProvider" 
          android:authorities="com.example.autos.autoinfoprovider" 
          . . . /> 
</provider> 
<provider>标签的属性中还可以设置ContentProvider的更多参数。 
一个完整的自定义ContentProvider及共享调用与事件侦听的例子:
数据结构User.java:
Java代码 
1. package com.yaku.pojo;  
2.   
3. public class User {  
4.     private int id;  
5.     private String name;  
6.     private int age;  
7.       
8.     public User(int id, String name, int age) {  
9.         super();  
10.         this.id = id;  
11.         this.name = name;  
12.         this.age = age;  
13.     }  
14.     public int getId() {  
15.         return id;  
16.     }  
17.     public void setId(int id) {  
18.         this.id = id;  
19.     }  
20.     public String getName() {  
21.         return name;  
22.     }  
23.     public void setName(String name) {  
24.         this.name = name;  
25.     }  
26.     public int getAge() {  
27.         return age;  
28.     }  
29.     public void setAge(int age) {  
30.         this.age = age;  
31.     }  
32.     @Override  
33.     public String toString() {  
34.         return "User [age=" + age + ", id=" + id + ", name=" + name + "]";  
35.     }  
36. }  
 
数据库操作DBOpenHelper.java:
Java代码
1. package com.yaku.db;  
2.   
3. import android.content.Context;  
4. import android.database.sqlite.SQLiteDatabase;  
5. import android.database.sqlite.SQLiteOpenHelper;  
6.   
7. public class DBOpenHelper extends SQLiteOpenHelper {  
8.     private static final String DBNAME = "yaku.db"; //数据库名称  
9.     private static final int DBVER = 1;//数据库版本  
10.       
11.     public DBOpenHelper(Context context) {  
12.         super(context, DBNAME, null, DBVER);  
13.     }  
14.   
15.     @Override  
16.     public void onCreate(SQLiteDatabase db) {  
17.         String sql = "CREATE TABLE user (userid integer primary key autoincrement, name varchar(20), age integer)";  
18.         db.execSQL(sql);//执行有更改的sql语句  
19.     }  
20.   
21.     @Override  
22.     public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {  
23.         db.execSQL("DROP TABLE IF EXISTS user");  
24.         onCreate(db);  
25.     }  
26.   
27. }  
 
对外共享处理类ContentProviderUser.java:
Java代码 
1. package com.yaku.ContentProvider;  
2.   
3. import com.yaku.db.DBOpenHelper;  
4.   
5. import android.content.ContentProvider;  
6. import android.content.ContentUris;  
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.   
13. public class ContentProviderUser extends ContentProvider {  
14.     private DBOpenHelper dbOpenHelper;  
15.     //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码  
16.     private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);  
17.     private static final int USERS = 1;  
18.     private static final int USER = 2;  
19.     static{  
20.         //如果match()方法匹配content://com.yaku.ContentProvider.userprovider/user路径,返回匹配码为1  
21.         MATCHER.addURI("com.yaku.ContentProvider.userprovider", "user", USERS);  
22.         //如果match()方法匹配content://com.yaku.ContentProvider.userprovider/user/123路径,返回匹配码为2  
23.         MATCHER.addURI("com.yaku.ContentProvider.userprovider", "user/#", USER);//#号为通配符  
24.     }     
25.     @Override  
26.     public int delete(Uri uri, String selection, String[] selectionArgs) {  
27.         SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
28.         int count = 0;  
29.         switch (MATCHER.match(uri)) {  
30.         case USERS:  
31.             count = db.delete("user", selection, selectionArgs);  
32.             return count;  
33.         case USER:  
34.             //ContentUris类用于获取Uri路径后面的ID部分  
35.             long id = ContentUris.parseId(uri);  
36.             String where = "userid = "+ id;  
37.             if(selection!=null && !"".equals(selection)){  
38.                 where = selection + " and " + where;  
39.             }  
40.             count = db.delete("user", where, selectionArgs);  
41.             return count;  
42.         default:  
43.             throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());  
44.         }  
45.     }  
46.   
47.     /** 
48.      * 该方法用于返回当前Url所代表数据的MIME类型。 
49.      * 如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头 
50.      * 如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头 
51.      */  
52.     @Override  
53.     public String getType(Uri uri) {  
54.         switch (MATCHER.match(uri)) {  
55.         case USERS:           
56.             return "vnd.android.cursor.dir/user";  
57.               
58.         case USER:            
59.             return "vnd.android.cursor.item/user";  
60.               
61.         default:  
62.             throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());  
63.         }  
64.     }  
65.   
66.     @Override  
67.     public Uri insert(Uri uri, ContentValues values) {  
68.         SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
69.         switch (MATCHER.match(uri)) {  
70.         case USERS:  
71.             long rowid = db.insert("user", "name", values);   
72.             Uri insertUri = ContentUris.withAppendedId(uri, rowid);//得到代表新增记录的Uri  
73.             this.getContext().getContentResolver().notifyChange(uri, null);  
74.             return insertUri;  
75.   
76.         default:  
77.             throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());  
78.         }  
79.     }  
80.   
81.     @Override  
82.     public boolean onCreate() {  
83.         this.dbOpenHelper = new DBOpenHelper(this.getContext());  
84.         return false;  
85.     }  
86.   
87.     @Override  
88.     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,  
89.             String sortOrder) {  
90.         SQLiteDatabase db = dbOpenHelper.getReadableDatabase();  
91.         switch (MATCHER.match(uri)) {  
92.         case USERS:  
93.             return db.query("user", projection, selection, selectionArgs, null, null, sortOrder);  
94.         case USER:  
95.             long id = ContentUris.parseId(uri);  
96.             String where = "userid = "+ id;  
97.             if(selection!=null && !"".equals(selection)){  
98.                 where = selection + " and " + where;  
99.             }  
100.             return db.query("user", projection, where, selectionArgs, null, null, sortOrder);  
101.         default:  
102.             throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());  
103.         }  
104.     }  
105.   
106.     @Override  
107.     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {  
108.         SQLiteDatabase db = dbOpenHelper.getWritableDatabase();  
109.         int count = 0;  
110.         switch (MATCHER.match(uri)) {  
111.         case USERS:  
112.             count = db.update("person", values, selection, selectionArgs);  
113.             return count;  
114.         case USER:  
115.             long id = ContentUris.parseId(uri);  
116.             String where = "userid = "+ id;  
117.             if(selection!=null && !"".equals(selection)){  
118.                 where = selection + " and " + where;  
119.             }  
120.             count = db.update("user", values, where, selectionArgs);  
121.             return count;  
122.         default:  
123.             throw new IllegalArgumentException("Unkwon Uri:"+ uri.toString());  
124.         }  
125.     }  
126. }  
 
单元测试类(在另一个应用中):
 
Java代码
1. package com.yaku.ContentProvider;  
2.   
3. import android.content.ContentResolver;  
4. import android.content.ContentValues;  
5. import android.database.Cursor;  
6. import android.net.Uri;  
7. import android.test.AndroidTestCase;  
8. import android.util.Log;  
9.   
10. /** 
11.  * 对ContentProvider工程中的ContentProviderActivity进行单元测试 
12.  */  
13. public class ContentProviderActivityTest extends AndroidTestCase {  
14.     private static final String TAG = "ContentProvider";  
15.     //往内容提供者添加数据  
16.     public void testInsert() throws Throwable{  
17.         ContentResolver contentResolver = this.getContext().getContentResolver();  
18.         Uri insertUri = Uri.parse("content://com.yaku.ContentProvider.userprovider/user");  
19.         ContentValues values = new ContentValues();  
20.         values.put("name", "道长");  
21.         values.put("age", 86);  
22.         Uri uri = contentResolver.insert(insertUri, values);  
23.         Log.i(TAG, uri.toString());  
24.     }  
25.       
26.     //更新内容提供者中的数据  
27.     public void testUpdate() throws Throwable{  
28.         ContentResolver contentResolver = this.getContext().getContentResolver();  
29.         Uri updateUri = Uri.parse("content://com.yaku.ContentProvider.userprovider/user/1");  
30.         ContentValues values = new ContentValues();  
31.         values.put("name", "青眉道长");  
32.         contentResolver.update(updateUri, values, null, null);  
33.     }  
34.       
35.     //从内容提供者中删除数据  
36.     public void testDelete() throws Throwable{  
37.         ContentResolver contentResolver = this.getContext().getContentResolver();  
38.         Uri deleteUri = Uri.parse("content://com.yaku.ContentProvider.userprovider/user/1");  
39.         contentResolver.delete(deleteUri, null, null);  
40.     }  
41.       
42.     //获取内容提供者中的数据  
43.     public void testFind() throws Throwable{  
44.         ContentResolver contentResolver = this.getContext().getContentResolver();  
45.         Uri selectUri = Uri.parse("content://com.yaku.ContentProvider.userprovider/user");  
46.         Cursor cursor = contentResolver.query(selectUri, null, null, null, "userid desc");  
47.         while(cursor.moveToNext()){  
48.             int id = cursor.getInt(cursor.getColumnIndex("userid"));  
49.             String name = cursor.getString(cursor.getColumnIndex("name"));  
50.             int age = cursor.getInt(cursor.getColumnIndex("age"));  
51.             Log.i(TAG, "id="+ id + ",name="+ name+ ",age="+ age);  
52.         }  
53.     }  
54.       
55. }  
 
监听数据的变化:
Java代码
1. <span style="font-size: medium;">package com.yaku.ContentProvider;  
2.   
3. import android.content.ContentResolver;  
4. import android.content.ContentValues;  
5. import android.database.Cursor;  
6. import android.net.Uri;  
7. import android.test.AndroidTestCase;  
8. import android.util.Log;  
9.   
10. /** 
11.  * 监听数据变化 
12.  */  
13. public class OtherContentProviderTest extends AndroidTestCase {  
14.     private static final String TAG = "OtherContentProvider";  
15.       
16.     @Override  
17.     public void onCreate(Bundle savedInstanceState) {  
18.         super.onCreate(savedInstanceState);  
19.         setContentView(R.layout.main);  
20.           
21.         Uri insertUri = Uri.parse("content://com.yaku.ContentProvider.userprovider/user");  
22.         ContentResolver contentResolver = this.getContentResolver();  
23.         //对指定uri进行监听,如果该uri代表的数据发生变化,就会调用PersonObserver中的onChange()  
24.         contentResolver.registerContentObserver(insertUri, true, new PersonObserver(new Handler()));  
25.     }  
26.       
27.     private final class PersonObserver extends ContentObserver{  
28.         public PersonObserver(Handler handler) {  
29.             super(handler);  
30.         }  
31.   
32.         @Override  
33.         public void onChange(boolean selfChange) {  
34.             ContentResolver contentResolver = getContentResolver();  
35.             Uri selectUri = Uri.parse("content://com.yaku.ContentProvider.userprovider/user");  
36.             Cursor cursor = contentResolver.query(selectUri, null, null, null, "userid desc");  
37.             while(cursor.moveToNext()){  
38.                 int id = cursor.getInt(cursor.getColumnIndex("userid"));  
39.                 String name = cursor.getString(cursor.getColumnIndex("name"));  
40.                 int age = cursor.getInt(cursor.getColumnIndex("age"));  
41.                 Log.i(TAG, "id="+ id + ",name="+ name+ ",age="+ age);  
42.             }  
43.         }  
44.     }  
45. }  
《完》
posted on 2011-12-31 15:34  Lucker  阅读(1318)  评论(0编辑  收藏  举报