ContentProvider + SQLite的使用详解

ContentProvider 对象绑定一个Uri对象,通过getContentResolver获得一个 ContentResolver对象,通过这个对象可以对所有的ContentProvier进行操作,具体的操作的ContentProvider对象由Uri获得,例如我们想在ContentProvider对象中插入一条数据,首先获取这个对象的Uri,然后通过这个对象的Uri去访问这个ContentProvider中的数据。

 

可就是说我们访问ContentProvider中的数据都是由Uri指定的数据,而ContentProvider只提供接口,这些接口中都存在一个Uri的形式参数。

 

一般我们在使用ContentProvider的时候,是通过继承 ContentProvider对象,并重定义里边的几个关键函数:

 

Cursor query(Uri uri,String[] proection,String selection,String[] selectionArgs,String sortOrder);

String getType(Uri uri);

Uri insert(Uri uri,ContentValues values);

int delete(Uri uri,String where,String[] whereArgs);

int update(Uri uri,ContentValues values,String where,String[] whereArgs);

 

从函数的形参可见,每个函数都存在一个Uri类型的形参,也就是说Uri是指定ContentProvider的唯一标示。通过Uri,我们可以访问到这其中的所有数据。

 

那么Uri是如何与ContentProvider产生关联的呢???!!!

 

Uri查查有道词典,我们可以看到,Uri的本意就是统一资源标示符,全写为Uniform Resource Identifier,也就是说每一个Uri都是唯一的,先抛开Uri不提,ContentProvider到底是如何与Uri产生联系呢?

 

产生联系要分为三个步骤,

 

第一步:要定义一个Uri对象,Uri对象的产生是通过Uri.parse(String s);这个函数产生,其中字符串S是有一定规则的,也就是Uri的三部分。所以String 必须是 s = “content://” + 数据的路径/文件名 + 标识(ID),标识是可选的,数据路径类似于文件的路径,/string1/string2/string2/….,文件名我们可以将他看做是ContentProvier存储数据文件。

 

通常数据路径都定义成一个字符串长量,这个长量不能被改变。

 

例如 final String AUTHORITY = “com.android.MyProvider.PeopleInfo”

利用这个我们可以生成一个Uri uri = Uri.parse(“content://” + AUTHORITY + /文件名);

 

文件名我们可以随便起,定义一个Uri之后,接下来看第二步。

 

第二步,在继承ContentProvider的类中定义一个 UriMatcher对象,

 UriMatcher matcher =new UriMatcher(UriMatcher.NO_MATCH);

这个类型的对象用来与指定的Uri匹配,如果匹配成功,说明指定的Uri与本对象的唯一标识,如果不匹配就不拒绝访问。

 

第三部,将Uri 对象加入匹配的对象中,即matcher.addURI(AUTHORITY , 文件名 ,Uri的键值);

 

当匹配的时候是调用。matcher.mathc(Uri uri),返回值就是 Uri的键值。

 

从绑定Uri到匹配Uri的伪代码如下:

从绑定Uri到匹配Uri的伪代码如下:

Uri uri = Uri.Parse(“content://” + 文件路径/文件名); //这里还可以指定某一行的Uri,即加上Uri的第三部分,标识(ID),

UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
Matcher.addURI(文件路径,文件名,Uri键值);
匹配时

If(Uir键值 != matcher.match(uri))
退出程序,拒绝访问。

 

详情看代码

PPeople.java,为了和数据库一起使用,就是用数据库保存ContentProvider的数据,这个类中定义了,文件路径,即String AUTHORITH, 且定义了Uri对象,CONTENT_URI,可见Uri的三部分,其中第三不存在,即

public static final Uri CONTENT_URI = Uri.parse("content://"+ AUTHORITY +"/ppinf");

其中/ppinf就是文件名,文件名与文件路径都是抽象的说法,类似于content是一个虚拟存在的系统符号,文件路径+文件名就是这个系统中我们创建的ContentProvider数据。

为了数据库使用,在内部继承了 BaseColums类,这个类中存在一个唯一标示的ID,就是主键,同时我们可以自定义我们数据库中的每一列的字符。

 

除此之外为了方便Uir访问每一条数据,我们定义了两中Uri的类型,一个是包含全部数据,一个是只有一条数据即:

        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.pdr.ppinf";
        
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.pdr.ppinf";
        

好了废话不多说,看完整的PPeople.java

public class PPeople 
{
    public static final String AUTHORITY = "com.provider.PPeople";
    private PPeople()
    {    
    }
    
    public static final class PPles implements BaseColumns
    {
        private PPles(){}
        
        public static final Uri CONTENT_URI = Uri.parse("content://"+ AUTHORITY +"/ppinf");
        
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.pdr.ppinf";
        
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.pdr.ppinf";
        
        public static final String DEFAULT_SORT_ORDER = "modified DESC";
        
        public static final String NAME = "name";
        public static final String SEX = "sex";
        public static final String AGE = "age";    
    }
}

 

 

接下来我们需要定义我们自己的ContentProvier对象,来看MyProvider.java

 

为了使用数据库存在我们的数据,需要声明一个数据库对象,并创建。同时创建数据表:

private static class DatabaseHelper extends SQLiteOpenHelper
    {

        public DatabaseHelper(Context context)//, String name,CursorFactory factory, int version) 
        {
            super(context,DATABASE_NAME,null,DATABASE_VERSION);
            // TODO Auto-generated constructor stub
        }

        @Override
        public void onCreate(SQLiteDatabase db) 
        {            
            db.execSQL(CREATE_TABLE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
            db.execSQL("DROP TABLE IF EXISTS pinf");
            onCreate(db);
        }
        
    }

在MyProvider类中,指定创建表的SQL语句,定义UriMathcher对象,并添加Uri的关联。

    static
    {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(PPeople.AUTHORITY,"ppinf",PPInf);
        sUriMatcher.addURI(PPeople.AUTHORITY,"ppinf/#",PPInf_ID);
        
        sPInfProjectionMap = new HashMap<String,String>();
        sPInfProjectionMap.put(PPles._ID, PPles._ID);
        sPInfProjectionMap.put(PPles.AGE,PPles.AGE);
        sPInfProjectionMap.put(PPles.SEX,PPles.SEX);
        sPInfProjectionMap.put(PPles.NAME, PPles.NAME);
    }

关键的是

        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(PPeople.AUTHORITY,"ppinf",PPInf);
        sUriMatcher.addURI(PPeople.AUTHORITY,"ppinf/#",PPInf_ID);

初始化UriMatcher的对象,并添加于Uri的关联。
其他还需要重定义

Cursor query(Uri uri,String[] proection,String selection,String[] selectionArgs,String sortOrder);

String getType(Uri uri);

Uri insert(Uri uri,ContentValues values);

int delete(Uri uri,String where,String[] whereArgs);

int update(Uri uri,ContentValues values,String where,String[] whereArgs);

 

这5个函数,目前我只重写了 insert与query的函数,这样可以简单的添加并测试是否成功。

 

完整的MyProvider.java如下:

 
package com.example.com.android.provider;

import java.util.HashMap;

import com.example.com.android.provider.PPeople.PPles;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;

public class MyProvider extends ContentProvider
{

    private static final String TAG = "MyProvider";
    private static final String DATABASE_NAME       = "Ppinf.db";
    private static final  int   DATABASE_VERSION    = 2;
    private static final String PP_TABLE_NAME = "pinf";
    
    private static final HashMap<String,String> sPInfProjectionMap;
    
    private static final int PPInf = 1;
    private static final int PPInf_ID = 2;
    private static final UriMatcher sUriMatcher;
    private DatabaseHelper    mOpenHelper;
    
    private static final String CREATE_TABLE = "CREATE TABLE "
                                               + PP_TABLE_NAME
                                               + " (" + PPles._ID
                                               + " INTEGER PRIMARY KEY,"
                                               + PPles.NAME
                                               + " TEXT,"
                                               + PPles.SEX
                                               + " TEXT,"
                                               + PPles.AGE
                                               + " INTEGER" + " );";
    static
    {
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(PPeople.AUTHORITY,"ppinf",PPInf);
        sUriMatcher.addURI(PPeople.AUTHORITY,"ppinf/#",PPInf_ID);
        
        sPInfProjectionMap = new HashMap<String,String>();
        sPInfProjectionMap.put(PPles._ID, PPles._ID);
        sPInfProjectionMap.put(PPles.AGE,PPles.AGE);
        sPInfProjectionMap.put(PPles.SEX,PPles.SEX);
        sPInfProjectionMap.put(PPles.NAME, PPles.NAME);
    }
    
    private static class DatabaseHelper extends SQLiteOpenHelper
    {

        public DatabaseHelper(Context context)//, String name,CursorFactory factory, int version) 
        {
            super(context,DATABASE_NAME,null,DATABASE_VERSION);
            // TODO Auto-generated constructor stub
        }

        @Override
        public void onCreate(SQLiteDatabase db) 
        {            
            db.execSQL(CREATE_TABLE);
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
            db.execSQL("DROP TABLE IF EXISTS pinf");
            onCreate(db);
        }
        
    }
    @Override
    public boolean onCreate() 
    {
        // TODO Auto-generated method stub
        mOpenHelper = new DatabaseHelper(getContext());
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) 
    {
        // TODO Auto-generated method stub
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
        switch(sUriMatcher.match(uri))
        {
        case PPInf:
            Log.d(TAG,"daaa1111");
            qb.setTables(PP_TABLE_NAME);
            qb.setProjectionMap(sPInfProjectionMap);
            break;
        case PPInf_ID:
            Log.d(TAG,"daaa2222");
            qb.setTables(PP_TABLE_NAME);
            qb.setProjectionMap(sPInfProjectionMap);
            qb.appendWhere(PPInf_ID + "=" + uri.getPathSegments().get(1));
            break;
        default:
            throw new IllegalArgumentException("Unknown URI" + uri);
        }
        
        
        Log.d(TAG,"adfasfsfsfsf");
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null,sortOrder);
        c.setNotificationUri(getContext().getContentResolver(),uri);
        return c;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        switch(sUriMatcher.match(uri))
        {
        case PPInf:
            return PPles.CONTENT_TYPE;
            
        case PPInf_ID:
            return PPles.CONTENT_ITEM_TYPE;
            
        default:
            throw new IllegalArgumentException("Unknown URI" + uri);    
        }
        
    }

    
    public Uri insert(Uri uri, ContentValues initialValues) 
    {
        // TODO Auto-generated method stub
        if(sUriMatcher.match(uri) != PPInf)
        {
            throw new IllegalArgumentException("Unknown URI " + uri);
        }
        
        SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 
        long rowId = db.insert(PP_TABLE_NAME,PPles._ID,initialValues);
        Log.d(TAG,"daaa33333");
        //rowId = db.insert(RuiXin.TNAME,RuiXin.TID,values); 
           if(rowId>0)
           { 
               Log.d(TAG,"daaa4444");
               Uri noteUri=ContentUris.withAppendedId(PPles.CONTENT_URI, rowId); 
               getContext().getContentResolver().notifyChange(noteUri, null); 
               return noteUri; 
           } 
           throw new IllegalArgumentException("Unknown URI"+uri); 

    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        // TODO Auto-generated method stub
        return 0;
    }
    

}

 

 

最后我们来看看测试:

测试首先是测试 插入数据:

        ContentValues values = new ContentValues();
        values.put(PPles.NAME, "NIUBEN");
        
        values.put(PPles.SEX,"MAN");
        values.put(PPles.AGE, 24);
        getContentResolver().insert(PPeople.PPles.CONTENT_URI,values);


 

来看显示数据:

  private void disp() 
    {
        // TODO Auto-generated method stub
        String columns [] = new String[] {PPeople.PPles._ID,
                                          PPeople.PPles.NAME,
                                          PPeople.PPles.SEX,
                                          PPeople.PPles.AGE};
        
        
        Cursor cur = getContentResolver().query(PPeople.PPles.CONTENT_URI, columns, null, null, null);
        if(cur.moveToFirst())
        {
            String id = null;
            String name = null;
            String sex = null;
            String age = null;
            do
            {
                id = cur.getString(cur.getColumnIndex(PPeople.PPles._ID));
                
                name = cur.getString(cur.getColumnIndex(PPeople.PPles.NAME));
                sex = cur.getString(cur.getColumnIndex(PPeople.PPles.SEX));
                age = cur.getString(cur.getColumnIndex(PPeople.PPles.AGE));
                Toast toast = Toast.makeText(this, id +" name" + name + "sex " + sex +" age "+ age , Toast.LENGTH_LONG);
                toast.setGravity(Gravity.TOP|Gravity.CENTER, 0, 40);
                toast.show();
            }
            while(cur.moveToNext());
            
        }
    }

 

通过查询,获得数据,并根据每一条数据的列参数,获取对应的值。

 

测试时候不要忘记在AndroidMainfest.xml中注册,我们的Provider类。

 

<provider android:name="MyProvider"
             android:authorities="com.provider.PPeople"/>
        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            
            <intent-filter>
                <data android:mimeType="vnd.android.cursor.dir/vnd.pdr.ppinf"/>
           </intent-filter>
           
           <intent-filter>
                   <data android:mimeType="vnd.android.cursor.item/vnd.pdr.ppinf"/>
           </intent-filter>

 

 

 

 

欢迎大家讨论,不懂得可以相互交流,以上写的有筒靴觉得不对或者不好的地方,欢迎拍砖,谢谢观看

posted on 2012-09-20 19:52  小白改bug  阅读(814)  评论(0编辑  收藏  举报

导航