Android开发之ContentProvider的简单使用

ContentProvider,内容提供者

官网结构图:

作为四大组件之一的ContentProvider,主要是用于应用间数据共享使用的。

ContentProvider把应用的数据封装起来,然后提供一个对外访问的ContentResolver接口。

假如只是本应用使用的数据,直接通过SQLiteDatabase操作数据库。

主要原理:一个Uri对象通过ContentResolver请求该应用的数据,ContentProvider解析该Uri并返回给需要的数据。

实现自定义的ContentProvider,需要继承抽象类android.content.ContentProvider,并实现5个方法:

onCreate()    初始化provider,返回一个布尔值,创建成功返回一个true

query(Uri,String[],String,String[],String)   从ContentProvider中查询数据  返回一个Cursor

insert(Uri,ContentValues)  通过ContentProvider插入新的数据   返回一个Uri

update(Uri,ContentValues,String,String[])   通过ContentProvider更新数据   返回一个int

delete(Uri,String,String[])   通过ContentProvider删除数据       返回一个int

getType(Uri)   根据传入的Uri,返回相应的MIME类型。  返回一个String

Uri类

一个Uri有三部分组成:Scheme+Authority+Path

1.scheme, contentprovider为content://

2.Authority,一般使用应用的包名,如com.example.appone或者也可以这样com.example.appone.provider

3.Path,即提供对外访问的table,如访问表table,写成/table

上面的Uri可以写成这样:content://com.example.appone.provider/table

一个字符串通过Uri类中的parse()方法可以转换为Uri对象,如下:

1 Uri uri=Uri.parse("content://com.example.appone.provider/table");

UriMatcher类,ContentUris类contentResolver类

UriMather类用于匹配uri,用法如下:

 1     private static final int PEOPLE = 1;
 2     private static final int PEOPLE_ID = 2;
 3     private static final int PEOPLE_PHONES = 3;
 4     private static final int PEOPLE_PHONES_ID = 4;
 5     private static final int PEOPLE_CONTACTMETHODS = 7;
 6     private static final int PEOPLE_CONTACTMETHODS_ID = 8;
 7 
 8     private static final int DELETED_PEOPLE = 20;
 9 
10     private static final int PHONES = 9;
11     private static final int PHONES_ID = 10;
12     private static final int PHONES_FILTER = 14;
13 
14     private static final int CONTACTMETHODS = 18;
15     private static final int CONTACTMETHODS_ID = 19;
16 
17     private static final int CALLS = 11;
18     private static final int CALLS_ID = 12;
19     private static final int CALLS_FILTER = 15;
20 
21     private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)
22 
23     static
24     {
25         sURIMatcher.addURI("contacts", "people", PEOPLE); //如果match()方法匹配,返回匹配码为1
26         sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);    //如果match()方法匹配,返回匹配码为2
27         sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES);
28         sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);
29         sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);
30         sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);
31         sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE);
32         sURIMatcher.addURI("contacts", "phones", PHONES);
33         sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER);
34         sURIMatcher.addURI("contacts", "phones/#", PHONES_ID);
35         sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS);
36         sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID);
37         sURIMatcher.addURI("call_log", "calls", CALLS);
38         sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER);
39         sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);
40     }

从API:18开始,路径可以用一个斜线开始。 例如:

1 sURIMatcher.addURI("contacts", "/people", PEOPLE);

注册完需要匹配的Uri后,在getType()方法中可以使用sURIMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配成功就返回匹配码,匹配码是调用addURI()方法传入的第三个参数。

 1     public String getType(Uri url)
 2     {
 3         int match = sURIMatcher.match(url);
 4         switch (match)
 5         {
 6             case PEOPLE:
 7                 return "vnd.android.cursor.dir/person";
 8             case PEOPLE_ID:
 9                 return "vnd.android.cursor.item/person";
10 ... snip ...
11                 return "vnd.android.cursor.dir/snail-mail";
12             case PEOPLE_ADDRESS_ID:
13                 return "vnd.android.cursor.item/snail-mail";
14             default:
15                 return null;
16         }
17     }

ContentUris类,用于获取Uri路径后面的ID部分,它有两个比较实用的方法:

    withAppendedId(uri, id)用于为路径加上ID部分

1 Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person")
2 Uri resultUri = ContentUris.withAppendedId(uri, 10); 
3 //生成后的Uri为:content://com.ljq.provider.personprovider/person/10

    parseId(uri)方法用于从路径中获取ID部分

1 Uri uri = Uri.parse("content://com.ljq.provider.personprovider/person/10")
2 long personid = ContentUris.parseId(uri);//获取的结果为:10

ContentResolver类,当外部应用需要对ContentProvider的数据库进行CRUD时,可以使用ContentResolver类来完成。获取ContentResolver对象,可以通过Content的getContentResolver()方法获取到。ContentResolver使用insert()、delete()、update()、query()方法,来操作数据。

实现了一个Demo,代码如下:

1.工具类:Xin类

 1 package com.example.appone;
 2 
 3 public class Xin {
 4 
 5     public static final String DBNAME = "xinonlinedb";
 6     public static final String TNAME = "xinonline";
 7     public static final int VERSION = 3;
 8 
 9     public static String TID = "tid";
10     public static final String EMAIL = "email";
11     public static final String USERNAME = "username";
12     public static final String DATE = "date";
13     public static final String SEX = "sex";
14 
15     public static final String AUTOHORITY = "com.example.appone.provider";
16     public static final int ITEM = 1;
17     public static final int ITEM_ID = 2;
18 
19     public static final String CONTENT_TYPE = "vnd.android.cursor.dir";
20     public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item";
21 
22 }

2.创建数据库:DBlite类

 1 package com.example.appone;
 2 
 3 import android.content.Context;
 4 import android.database.sqlite.SQLiteDatabase;
 5 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 6 import android.database.sqlite.SQLiteOpenHelper;
 7 
 8 public class DBlite extends SQLiteOpenHelper {
 9 
10     public DBlite(Context context, String name, CursorFactory factory,
11             int version) {
12         super(context, name, factory, version);
13 
14     }
15 
16     @Override
17     public void onCreate(SQLiteDatabase db) {
18         db.execSQL("CREATE TABLE " + Xin.TNAME + "(" + Xin.TID
19                 + " integer primary key autoincrement not null," + Xin.EMAIL
20                 + " text not null, " + Xin.USERNAME + " text not null,"
21                 + Xin.DATE + " text not null, " + Xin.SEX + " text not null);");
22     }
23 
24     @Override
25     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
26 
27     }
28 
29 }

3.创建自定义的ContentProvider,对数据库进行包装:MyProvider类

  1 package com.example.appone;
  2 
  3 import android.content.ContentProvider;
  4 import android.content.ContentValues;
  5 import android.content.UriMatcher;
  6 import android.database.Cursor;
  7 import android.database.sqlite.SQLiteDatabase;
  8 import android.net.Uri;
  9 
 10 public class MyProvider extends ContentProvider {
 11 
 12     private DBlite dBlite;
 13     private SQLiteDatabase db;
 14     private Cursor cursor;
 15 
 16     private static final UriMatcher sMatcher;
 17     static {
 18         sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 19         sMatcher.addURI(Xin.AUTOHORITY, Xin.TNAME, Xin.ITEM);
 20         sMatcher.addURI(Xin.AUTOHORITY, Xin.TNAME + "/#", Xin.ITEM_ID);
 21 
 22     }
 23 
 24     @Override
 25     public boolean onCreate() {
 26         dBlite = new DBlite(getContext(), Xin.DBNAME, null, Xin.VERSION);
 27         return true;
 28 
 29     }
 30 
 31     @Override
 32     public Cursor query(Uri uri, String[] projection, String selection,
 33             String[] selectionArgs, String sortOrder) {
 34         db = dBlite.getWritableDatabase();
 35         switch (sMatcher.match(uri)) {
 36         case Xin.ITEM:
 37             cursor = db.query(Xin.TNAME, projection, selection, selectionArgs,
 38                     null, null, sortOrder);
 39             break;
 40         case Xin.ITEM_ID:
 41             String id = uri.getPathSegments().get(1);
 42             cursor = db.query(Xin.TNAME, projection, "tid=?",
 43                     new String[] { id }, null, null, sortOrder);
 44             break;
 45 
 46         default:
 47             break;
 48         }
 49         return cursor;
 50     }
 51 
 52     @Override
 53     public Uri insert(Uri uri, ContentValues values) {
 54         db = dBlite.getWritableDatabase();
 55         long returnId = db.insert(Xin.TNAME, null, values);
 56         Uri uriReturn = Uri.parse("content://" + Xin.AUTOHORITY + "/"
 57                 + Xin.TNAME + "/" + returnId);
 58 
 59         return uriReturn;
 60     }
 61 
 62     @Override
 63     public int delete(Uri uri, String selection, String[] selectionArgs) {
 64         db = dBlite.getWritableDatabase();
 65         int deleteId = 0;
 66         switch (sMatcher.match(uri)) {
 67         case Xin.ITEM:
 68             deleteId = db.delete(Xin.TNAME, selection, selectionArgs);
 69 
 70             break;
 71         case Xin.ITEM_ID:
 72             String id = uri.getPathSegments().get(1);
 73             deleteId = db.delete(Xin.TNAME, "tid=?", new String[] { id });
 74 
 75         default:
 76             break;
 77         }
 78         return deleteId;
 79     }
 80 
 81     @Override
 82     public int update(Uri uri, ContentValues values, String selection,
 83             String[] selectionArgs) {
 84         db = dBlite.getWritableDatabase();
 85         int updateId = 0;
 86         switch (sMatcher.match(uri)) {
 87         case Xin.ITEM:
 88             updateId = db.update(Xin.TNAME, values, selection, selectionArgs);
 89             break;
 90         case Xin.ITEM_ID:
 91             String id = uri.getPathSegments().get(1);
 92             updateId = db.update(Xin.TNAME, values, "tid= ?",
 93                     new String[] { id });
 94             break;
 95 
 96         default:
 97             break;
 98         }
 99         return updateId;
100     }
101 
102     @Override
103     public String getType(Uri uri) {
104         switch (sMatcher.match(uri)) {
105         case Xin.ITEM:
106             return Xin.CONTENT_TYPE + "/vnd." + Xin.AUTOHORITY + Xin.TNAME;
107         case Xin.ITEM_ID:
108             return Xin.CONTENT_ITEM_TYPE + "/vnd." + Xin.AUTOHORITY + Xin.TNAME;
109 
110         }
111         return null;
112     }
113 
114 }

4.在manifest文件中对MyProvider进行注册

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 3     package="com.example.appone"
 4     android:versionCode="1"
 5     android:versionName="1.0" >
 6 
 7     <uses-sdk
 8         android:minSdkVersion="14"
 9         android:targetSdkVersion="21" />
10 
11     <application
12         android:allowBackup="true"
13         android:icon="@drawable/ic_launcher"
14         android:label="@string/app_name"
15         android:theme="@style/AppTheme" >
16         <activity
17             android:name=".MainActivity"
18             android:label="@string/app_name" >
19             <intent-filter>
20                 <action android:name="android.intent.action.MAIN" />
21 
22                 <category android:name="android.intent.category.LAUNCHER" />
23             </intent-filter>
24         </activity>
25 
26         <provider
27             android:name="com.example.appone.MyProvider"
28             android:authorities="com.example.appone.provider"
29             android:exported="true" >
30         </provider>
31     </application>
32 
33 </manifest>

5.在MainActivity中使用ContentProvider进行CRUD

 1 package com.example.appone;
 2 
 3 import android.app.Activity;
 4 import android.content.ContentValues;
 5 import android.database.Cursor;
 6 import android.net.Uri;
 7 import android.os.Bundle;
 8 import android.util.Log;
 9 import android.view.View;
10 import android.view.View.OnClickListener;
11 import android.view.Window;
12 
13 public class MainActivity extends Activity implements OnClickListener {
14 
15     private String newid;
16 
17     @Override
18     protected void onCreate(Bundle savedInstanceState) {
19         super.onCreate(savedInstanceState);
20         requestWindowFeature(Window.FEATURE_NO_TITLE);
21         setContentView(R.layout.activity_contentprovider);
22 
23         findViewById(R.id.contentProvider_query).setOnClickListener(this);
24         findViewById(R.id.contentProvider_insert).setOnClickListener(this);
25         findViewById(R.id.contentProvider_update).setOnClickListener(this);
26         findViewById(R.id.contentProvider_delete).setOnClickListener(this);
27     }
28 
29     @Override
30     public void onClick(View v) {
31         Uri uriItem = Uri.parse("content://"+Xin.AUTOHORITY+"/"+Xin.TNAME);
32         Uri uriId = Uri.parse("content://"+Xin.AUTOHORITY+"/"+Xin.TNAME+"/"+newid);
33         switch (v.getId()) {
34         case R.id.contentProvider_query:
35             Cursor cursor=this.getContentResolver().query(uriItem, null, null, null, null);
36             if (cursor!=null) {
37                 while (cursor.moveToNext()) {
38                     String userName=cursor.getString(cursor.getColumnIndex(Xin.USERNAME));
39                     String sex = cursor.getString(cursor.getColumnIndex(Xin.SEX));
40                     String email = cursor.getString(cursor.getColumnIndex(Xin.EMAIL));
41                     String date = cursor.getString(cursor.getColumnIndex(Xin.DATE));
42                     Log.e("appone", "获取到的信息为:"+userName+email+date+sex);
43                 }
44                 cursor.close();
45             }
46             break;
47             
48         case R.id.contentProvider_insert:
49             ContentValues values = new ContentValues();
50             values.put(Xin.EMAIL, "1234@12.com");
51             values.put(Xin.USERNAME, "张三");
52             values.put(Xin.DATE, "2015");
53             values.put(Xin.SEX, "男");
54             Uri newUri = this.getContentResolver().insert(uriItem,values);
55             newid = newUri.getPathSegments().get(1);
56             break;
57             
58         case R.id.contentProvider_update:
59             ContentValues values2= new ContentValues();
60             values2.put(Xin.USERNAME, "王五");
61             values2.put(Xin.EMAIL, "xxx@ddd.com");
62             values2.put(Xin.SEX, "女");
63             this.getContentResolver().update(uriId, values2, null, null);
64             break;
65             
66         case R.id.contentProvider_delete:
67             this.getContentResolver().delete(uriId, null, null);
68             break;
69 
70         default:
71             break;
72         }
73     }
74 
75 }

注意:

首先需要插入消息,然后再查询或者更新或者删除,否则newId的值为空。

原文地址:https://www.cnblogs.com/liyiran/p/4953632.html