ContentProvider数据库共享之——实例讲解

 

版权声明:本文为博主原创文章,未经博主容许不得转载。 https://blog.csdn.net/harvic880925/article/details/44591631

前言:如今这段时间没这么忙了,要抓紧时间把要总结的知识沉淀下来,今年从新分了项目组,在新项目中应该不会那么忙了,看来有时间来学一些本身的东西了。如今而言,我须要的是时间。只要不断的努力,总有一天,你会与从不一样。加油。html

 

相关文章:
一、《ContentProvider数据库共享之——概述》
二、《ContentProvider数据库共享之——实例讲解》
三、《ContentProvider数据库共享之——MIME类型与getType()》
四、《ContentProvider数据库共享之——读写权限与数据监听》java

 

在上篇文章中,已经给你们初步讲解了有关ContentProvder的总体流程及设计方式,在这篇文章中将经过实例来说述ContentProvider的操做过程;android

1、ContentProvider提供数据库查询接口

在上篇中,咱们提到过,两个应用间是经过Content URI来媒介传递消息的,咱们的应用在收到URI之后,经过匹配完成对应的数据库操做功能。听的有点迷糊?不要紧,下面会细讲,我这里要说的是,匹配成功后要完成的数据库操做!!!那好,咱们的第一步:建数据库,数据表数据库

一、利用SQLiteOpenHelper建立数据库、数据表

在这里,咱们在一个数据库(“harvic.db”)中建立两个数据表”first”与”second”;每一个表都有多出一个字段“table_name”,来保存当前数据表的名称
代码以下:数组

 

  1.  
    public class DatabaseHelper extends SQLiteOpenHelper {
  2.  
    public static final String DATABASE_NAME = "harvic.db";
  3.  
    public static final int DATABASE_VERSION = 1;
  4.  
    public static final String TABLE_FIRST_NAME = "first";
  5.  
    public static final String TABLE_SECOND_NAME = "second";
  6.  
    public static final String SQL_CREATE_TABLE_FIRST = "CREATE TABLE " +TABLE_FIRST_NAME +"("
  7.  
    + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  8.  
    + "table_name" +" VARCHAR(50) default 'first',"
  9.  
    + "name" + " VARCHAR(50),"
  10.  
    + "detail" + " TEXT"
  11.  
    + ");" ;
  12.  
    public static final String SQL_CREATE_TABLE_SECOND = "CREATE TABLE "+TABLE_SECOND_NAME+" ("
  13.  
    + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
  14.  
    + "table_name" +" VARCHAR(50) default 'second',"
  15.  
    + "name" + " VARCHAR(50),"
  16.  
    + "detail" + " TEXT"
  17.  
    + ");" ;
  18.  
     
  19.  
    public DatabaseHelper(Context context) {
  20.  
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
  21.  
    }
  22.  
     
  23.  
    @Override
  24.  
    public void onCreate(SQLiteDatabase db) {
  25.  
    Log.e( "harvic", "create table: " + SQL_CREATE_TABLE_FIRST);
  26.  
    db.execSQL(SQL_CREATE_TABLE_FIRST);
  27.  
    db.execSQL(SQL_CREATE_TABLE_SECOND);
  28.  
    }
  29.  
     
  30.  
    @Override
  31.  
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  32.  
    db.execSQL( "DROP TABLE IF EXISTS first");
  33.  
    db.execSQL( "DROP TABLE IF EXISTS second");
  34.  
    onCreate(db);
  35.  
    }
  36.  
    }

二、利用ContentProvider提供数据库操做接口

新建一个类PeopleContentProvider,派生自ContentProvider基类,写好以后,就会自动生成query(),insert(),update(),delete()和getType()方法;这些方法就是根据传过来的URI来操做数据库的接口。此时的PeopleContentProvider是这样的:

 

 

  1.  
    public class PeopleContentProvider extends ContentProvider {
  2.  
    @Override
  3.  
    public boolean onCreate() {
  4.  
    return false;
  5.  
    }
  6.  
     
  7.  
    @Override
  8.  
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  9.  
    return null;
  10.  
    }
  11.  
     
  12.  
    @Override
  13.  
    public String getType(Uri uri) {
  14.  
    return null;
  15.  
    }
  16.  
     
  17.  
    @Override
  18.  
    public Uri insert(Uri uri, ContentValues values) {
  19.  
    return null;
  20.  
    }
  21.  
     
  22.  
    @Override
  23.  
    public int delete(Uri uri, String selection, String[] selectionArgs) {
  24.  
    return 0;
  25.  
    }
  26.  
     
  27.  
    @Override
  28.  
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  29.  
    return 0;
  30.  
    }
  31.  
    }

三、使用UriMatcher匹配URI

咱们先无论这几个函数的具体操做,先想一想在上节中我提到的当一个URI逐级匹配到了ContentProvider类里之后,会怎么作——利用UriMatcher进行再次匹配!!!UriMatcher匹配成功之后,才会执行对应的操做。因此上面的那些操做是在UriMatcher匹配以后。
好,咱们就先看看UriMatcher是怎么匹配的。

 

  1.  
    public class PeopleContentProvider extends ContentProvider {
  2.  
    private static final UriMatcher sUriMatcher;
  3.  
    private static final int MATCH_FIRST = 1;
  4.  
    private static final int MATCH_SECOND = 2;
  5.  
    public static final String AUTHORITY = "com.harvic.provider.PeopleContentProvider";
  6.  
    public static final Uri CONTENT_URI_FIRST = Uri.parse("content://" + AUTHORITY + "/frist");
  7.  
    public static final Uri CONTENT_URI_SECOND = Uri.parse("content://" + AUTHORITY + "/second");
  8.  
     
  9.  
    static {
  10.  
    sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  11.  
    sUriMatcher.addURI(AUTHORITY, "first", MATCH_FIRST);
  12.  
    sUriMatcher.addURI(AUTHORITY, "second", MATCH_SECOND);
  13.  
    }
  14.  
     
  15.  
    private DatabaseHelper mDbHelper;
  16.  
     
  17.  
    @Override
  18.  
    public boolean onCreate() {
  19.  
    mDbHelper = new DatabaseHelper(getContext());
  20.  
    return false;
  21.  
    }
  22.  
    …………
  23.  
    }
上面的代码是最重要的一句话:

 

 

sUriMatcher.addURI(AUTHORITY, "first", MATCH_FIRST);
addUri的官方声明为:
public void addURI (String authority, String path, int code)
  • authority:这个参数就是ContentProvider的authority参数,这个参数必须与AndroidManifest.xml中的对应provider的authorities值同样;
  • path:就匹配在URI中authority后的那一坨,在这个例子中,咱们构造了两个URI
    (1)、content://com.harvic.provider.PeopleContentProvider/frist
    (2)、content://com.harvic.provider.PeopleContentProvider/second
    而path匹配的就是authority后面的/first或者/second
  • code:这个值就是在匹配path后,返回的对应的数字匹配值;

 

 

sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
句话的意思是,若是匹配不成功,返回UriMatcher.NO_MATCH
咱们要作一个应用:外部可使用两个URI传来给咱们,当传来content://com.harvic.provider.PeopleContentProvider/frist时,就操做first数据库;若是传来content://com.harvic.provider.PeopleContentProvider/second时,就操做second数据库

四、insert方法

 

下面先看看insert方法,主要功能为:当URI匹配content://com.harvic.provider.PeopleContentProvider/frist时,将数据插入first数据库
当URI匹配content://com.harvic.provider.PeopleContentProvider/second时,将数据插入second数据库ide

 

  1.  
    @Override
  2.  
    public Uri insert(Uri uri, ContentValues values) {
  3.  
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
  4.  
    switch (sUriMatcher.match(uri)){
  5.  
    case MATCH_FIRST:{
  6.  
    long rowID = db.insert(DatabaseHelper.TABLE_FIRST_NAME, null, values);
  7.  
    if(rowID > 0) {
  8.  
    Uri retUri = ContentUris.withAppendedId(CONTENT_URI_FIRST, rowID);
  9.  
    return retUri;
  10.  
    }
  11.  
    }
  12.  
    break;
  13.  
    case MATCH_SECOND:{
  14.  
    long rowID = db.insert(DatabaseHelper.TABLE_SECOND_NAME, null, values);
  15.  
    if(rowID > 0) {
  16.  
    Uri retUri = ContentUris.withAppendedId(CONTENT_URI_SECOND, rowID);
  17.  
    return retUri;
  18.  
    }
  19.  
    }
  20.  
    break;
  21.  
    default:
  22.  
    throw new IllegalArgumentException("Unknown URI " + uri);
  23.  
    }
  24.  
    return null;
  25.  
    }
下面对上面这段代码进行讲解:
首先,利用UriMatcher.match(uri)来匹配到来的URI,若是这个URI与content://com.harvic.provider.PeopleContentProvider/frist匹配,就会返回1即MATCH_FIRST;
即:当与"/first"匹配时,就将数据键值对(values)插入到first表中:
long rowID = db.insert(DatabaseHelper.TABLE_FIRST_NAME, null, values);
插入以后,会返回新插入记录的当前所在行号,而后将行号添加到URI的末尾,作为结果返回
Uri retUri = ContentUris.withAppendedId(CONTENT_URI_FIRST, rowID);
当匹配content://com.harvic.provider.PeopleContentProvider/second时,同理,再也不赘述。

五、update()方法

 

在看了insert方法以后,update方法难度也不大,也是根据UriMatcher.match(uri)的返回值来判断当前与哪一个URI匹配,根据匹配的URI来操做对应的数据库,代码以下:函数

 

  1.  
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  2.  
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
  3.  
    int count = 0;
  4.  
    switch(sUriMatcher.match(uri)) {
  5.  
    case MATCH_FIRST:
  6.  
    count = db.update(DatabaseHelper.TABLE_FIRST_NAME, values, selection, selectionArgs);
  7.  
    break;
  8.  
    case MATCH_SECOND:
  9.  
    count = db.update(DatabaseHelper.TABLE_SECOND_NAME, values, selection, selectionArgs);
  10.  
    break;
  11.  
     
  12.  
    default:
  13.  
    throw new IllegalArgumentException("Unknow URI : " + uri);
  14.  
    }
  15.  
    this.getContext().getContentResolver().notifyChange(uri, null);
  16.  
    return count;
  17.  
    }
在最后调用getContentResolver().notifyChange(uri, null);来通知当前的数据库有改变,让监听这个数据库的全部应用执行对应的操做,有关共享数据库的变量监听与响应的问题,咱们会在最后一篇中讲述。这里就先不提,这里不加这一句也是没问题的。我这里只是一个引子,你们知道这个事就好了。

六、query() 方法

 

至于query()方法就再也不细讲了,跟上面的同样,根据不一样的URI来操做不一样的查询操做而已,代码以下:post

 

  1.  
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  2.  
    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
  3.  
    switch (sUriMatcher.match(uri)) {
  4.  
    case MATCH_FIRST:
  5.  
    // 设置查询的表
  6.  
    queryBuilder.setTables(DatabaseHelper.TABLE_FIRST_NAME);
  7.  
    break;
  8.  
     
  9.  
    case MATCH_SECOND:
  10.  
    queryBuilder.setTables(DatabaseHelper.TABLE_SECOND_NAME);
  11.  
    break;
  12.  
     
  13.  
    default:
  14.  
    throw new IllegalArgumentException("Unknow URI: " + uri);
  15.  
    }
  16.  
     
  17.  
    SQLiteDatabase db = mDbHelper.getReadableDatabase();
  18.  
    Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, null);
  19.  
    return cursor;
  20.  
    }

七、delete()方法

delete()方法以下:

 

 

  1.  
    public int delete(Uri uri, String selection, String[] selectionArgs) {
  2.  
    SQLiteDatabase db = mDbHelper.getWritableDatabase();
  3.  
    int count = 0;
  4.  
    switch(sUriMatcher.match(uri)) {
  5.  
    case MATCH_FIRST:
  6.  
    count = db.delete(DatabaseHelper.TABLE_FIRST_NAME, selection, selectionArgs);
  7.  
    break;
  8.  
     
  9.  
    case MATCH_SECOND:
  10.  
    count = db.delete(DatabaseHelper.TABLE_SECOND_NAME, selection, selectionArgs);
  11.  
    break;
  12.  
    default:
  13.  
    throw new IllegalArgumentException("Unknow URI :" + uri);
  14.  
     
  15.  
    }
  16.  
    return count;
  17.  
    }

八、getType()

这个函数,咱们这里暂时用不到,直接返回NULL,下篇咱们会专门来说这个函数的做用与意义。

 

 

  1.  
    public String getType(Uri uri) {
  2.  
    return null;
  3.  
    }

九、AndroidManifest.xml中声明provider

在AndroidManifest.xml中要声明咱们建立的Provider:

 

 

  1.  
    <provider
  2.  
    android:authorities= "com.harvic.provider.PeopleContentProvider"
  3.  
    android:name= ".PeopleContentProvider"
  4.  
    android:exported= "true"/>

2、第三方应用经过URI操做共享数据库

 

一、ContentResolver操做URI

在第三方应用中,咱们要如何利用URI来执行共享数据数的操做呢,这是利用ContentResolver这个类来完成的。
获取ContentResolver实例的方法为:ui

 

ContentResolver cr = this.getContentResolver();
ContentResolver有下面几个数据库操做:查询、插入、更新、删除

 

 

  1.  
    public final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
  2.  
    public final Uri insert (Uri url, ContentValues values)
  3.  
    public final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)
  4.  
    public final int delete (Uri url, String where, String[] selectionArgs)
第一个参数都是传入要指定的URI,而后再后面的几个参数指定数据库条件——where语句和对应的参数;下面咱们就用户实例来看看这几个函数究竟是怎么用的。

二、全局操做

 

新建一个工程,命名为“UseProvider”,界面长这个样子:this

最上头有两个按钮,用来切换当前使用哪一个URI来增、删、改、查操做;因为不一样的URI会操做不一样的数据表,因此咱们使用不一样的URI,会在不一样的数据表中操做;
先列出来那两个要匹配的URI,以及全局当前要使用的URI(mCurrentURI ),mCurrentURI 默认是/first对应的URI,若是要切换,使用界面上最上头的那两个按钮来切换当前所使用的URI。

 

  1.  
    public static final String AUTHORITY = "com.harvic.provider.PeopleContentProvider";
  2.  
    public static final Uri CONTENT_URI_FIRST = Uri.parse("content://" + AUTHORITY + "/first");
  3.  
    public static final Uri CONTENT_URI_SECOND = Uri.parse("content://" + AUTHORITY + "/second");
  4.  
    public static Uri mCurrentURI = CONTENT_URI_FIRST;

三、query()——查询操做

下面先来看看查询操做的过程:

 

 

  1.  
    private void query() {
  2.  
    Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);
  3.  
    Log.e( "test ", "count=" + cursor.getCount());
  4.  
    cursor.moveToFirst();
  5.  
    while (!cursor.isAfterLast()) {
  6.  
    String table = cursor.getString(cursor.getColumnIndex( "table_name"));
  7.  
    String name = cursor.getString(cursor.getColumnIndex( "name"));
  8.  
    String detail = cursor.getString(cursor.getColumnIndex( "detail"));
  9.  
    Log.e( "test", "table_name:" + table);
  10.  
    Log.e( "test ", "name: " + name);
  11.  
    Log.e( "test ", "detail: " + detail);
  12.  
    cursor.moveToNext();
  13.  
    }
  14.  
    cursor.close();
  15.  
    }
其实只有一句话,就完成的查询操做:(因为没有加任何的限定语句,因此是查询出此数据表中的全部记录)
Cursor cursor = this.getContentResolver().query(mCurrentURI, null, null, null, null);
而后将返回的数据库记录指针Cursor,逐个读出全部的记录;

四、insert()插入操做

 

 

public final Uri insert (Uri url, ContentValues values)
插入操做有点特殊,第二个函数要求传入要插入的ContentValues的键值对;其实也没什么难度,跟普通的数据库操做同样;
  1.  
    private void insert() {
  2.  
    ContentValues values = new ContentValues();
  3.  
    values.put( "name", "hello");
  4.  
    values.put( "detail", "my name is harvic");
  5.  
    Uri uri = this.getContentResolver().insert(mCurrentURI, values);
  6.  
    Log.e( "test ", uri.toString());
  7.  
    }

五、update()更新操做

public final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)
这个函数的意思就是,先用where语句找出要更新的记录,而后将values键值对更新到对应的记录中;
  • uri:即要匹配的URI
  • values:这是要更新的键值对
  • where:SQL中对应的where语句
  • selectionArgs:where语句中若是有可变参数,能够放在selectionArgs这个字符串数组中;这些与数据库中的用法同样,再也不细讲。
  1.  
    private void update() {
  2.  
    ContentValues values = new ContentValues();
  3.  
    values.put( "detail", "my name is harvic !!!!!!!!!!!!!!!!!!!!!!!!!!");
  4.  
    int count = this.getContentResolver().update(mCurrentURI, values, "_id = 1", null);
  5.  
    Log.e( "test ", "count=" + count);
  6.  
    query();
  7.  
    }
在这里,咱们将_id = 1的记录的detail字符更新,在后面多加了N个感叹号。

六、delete()删除操做

 

 

public final int delete (Uri url, String where, String[] selectionArgs)
删除操做的参数比较好理解,第二个参数是SQL中的WHERE语句的过滤条件,selectionArgs一样是Where语句中的可变参数;
  1.  
    private void delete() {
  2.  
    int count = this.getContentResolver().delete(mCurrentURI, "_id = 1", null);
  3.  
    Log.e( "test ", "count=" + count);
  4.  
    query();
  5.  
    }
删除_id = 1的记录;

3、结果

 

一、咱们先运行ContentProvider对应的APP:ContentProviderBlog,而后再运行UseProvider;
二、而后先用content://com.harvic.provider.PeopleContentProvider/frist 来操做ContentProviderBlog的数据库:
三、点两个insert操做,看返回的URI,在每一个URI后都添加上了当前新插入记录的行号

四、而后作下查询操做——query()
因为咱们的URI是针对first记录的,因此在这里的table_name,能够看到是“first”,即咱们操做的是first表,若是咱们把URI改为second对应的URI,那操做的就会变成second表

五、更新操做——update()

执行Update()操做,会将_id = 1的记录的detail字段更新为“my name is harvic !!!!!!!!!!!!!!!!!!!!!!!!!!”;其它记录的值不变,结果以下:

六、删除操做——delete()

一样,删除操做也会只删除_id = 1的记录,因此操做以后的query()结果以下:

总结:在这篇文章中,咱们写了两个应用ContentProviderBlog和UseProvider,其中ContentProviderBlog派生自ContentProvider,提供第三方操做它数据库的接口;而UseProvider就是所谓第三方应用,在UseProvider中经过URI来操做ContentProviderBlog的数据库;

好了,到这里,整个文章就结束了,你们在看完这篇文章之后再回过头来看第一篇,应该对应用间数据库共享的总体流程已经有清晰的了解了。

 

源码来了,源码包含两部份内容:

一、《ContentProviderBlog》:这个是提供共享数据库接口的APP;
二、《UseProvider》:第三方经过URI来操做数据库的APP;

 

若是本文有帮到你,记得关注哦

源码下载地址:http://download.csdn.net/detail/harvic880925/8528507

请你们尊重原创者版权,转载请标明出处: http://blog.csdn.net/harvic880925/article/details/44591631  谢谢!

相关文章
相关标签/搜索