安卓学习之数据共享内容提供器Content Provider

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓学习之数据共享内容提供器Content Provider相关的知识,希望对你有一定的参考价值。

    内容提供器Content Provider 能够实现不同程序之间内容的共享。安卓提供了这样的一套机制,让一个程序访问另一个程序的数据,同时保证了安全性。

  一个程序可以通过内容提供器对其数据提供外部访问接口,这样其它程序就能通过接口来访问数据。

ContentResolver

    首先我们先介绍这个类。如果想要访问数据提供器中的数据,我们需要借助ContentResolver类。该对象实例可以在Context中调用getContentResolver()方法来获得。ContentResolver中提供了一系列对数据    操作的方法。ContentResolver中增删改方法不接收表名,而是使用Uri参数,称为内容URI。这个URI由2部分组成,权限authority和路径path组成。一般权限命名如:com.example.app.provider 。 路径则是对            同一个应用中不同表名的区分。 现在在一个程序中我们有2个数据库表叫table1,table2。 那么内容URI就是com.example.app.provider/table1和com.example.app.provider/table2 。我们还需要在这字符串头部加

  上协议声明。那么内容URI标准写法是 : "content://com.example.app.provider/table1" 和 "content://com.example.app.provider/table2" 。

     由于上述的还是字符串,我们要转化为Uri对象,可以调用Uri.parse解析。Uri uri = Uri.parse("content://com.example.app.provider/table1");

  • Uri查询table1中的数据

  注意ContentResolver中的query方法返回的是一个Cursor对象。 那么查询可以如下表示:

Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);

 

 

    query()方法参数       对应 SQL 部分             描述
     uri             from table_name            指定查询某个应用程序下的某一张表
     projection         select column1, column2       指定查询的列名
     selection          where column = value            指定 where 的约束条件
     selectionArgs          ---             为 where 中的占位符提供具体的值
     orderBy           order by column1, column2     指定查询结果的排序方式

  然后我们可以从cursor中取出每一行相应的数据:

if (cursor != null) {
    while (cursor.moveToNext()) {
    String column1 = cursor.getString(cursor.getColumnIndex("column1"));
    int column2 = cursor.getInt(cursor.getColumnIndex("column2"));
  }
  cursor.close();
}

 

  • 向table1中添加数据:

  和向数据库中添加一条数据一样,通过ContentValues来实现。

ContentValues values = new ContentValues();
values.put("column1", "text");
values.put("column2", 1);
getContentResolver().insert(uri, values);
  • 更新一条数据
ContentValues values = new ContentValues();
values.put("column1", "");
getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[] {"text", "1"});

 

  • 删除一条数据
getContentResolver().delete(uri, "column2 = ?", new String[] { "1" });

  

 ContentProvider

  继承ContentProvider创建一个自己的内容提供器,让其它程序能够访问到当前程序的数据。ContentProvider类中有6个抽象方法。

  • 在这里我们要在回顾一下URI写法和如何匹配。

  content://com.example.app.provider/table1 表示访问com.example.app 这个应用的 table1 表中的数据。我们还可以在后面添加id值 content://com.example.app.provider/table1/1,表示访问的是 com.example.app 这个应用的 table1 表中 id 为 1 的数据。

  内容 URI 的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以 id 结尾就表示期望访问该表中拥有相应 id 的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容 URI,规则如下。

      1. *:表示匹配任意长度的任意字符
      2. #:表示匹配任意长度的数字
  所以,一个能够匹配任意表的内容 URI 格式就可以写成:
  content://com.example.app.provider/*
  而一个能够匹配 table1 表中任意一行数据的内容 URI 格式就可以写成:
  content://com.example.app.provider/table1/#

这样,当调用 UriMatcher 的 match()方法时,就可以将一个 Uri 对象传入,返回值是某个能够匹配这个 Uri 对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。

  • getType()方法

它是所有的内容提供器都必须提供的一个方法,用于获取 Uri 对象所对应的 MIME 类型。

对应的MIME类型由3部分组成,android中对其进行了规定:

  1. 必须以 vnd 开头。

  2. 如果内容 URI 以路径结尾,则后接 android.cursor.dir/,如果内容 URI 以 id 结尾,则后接 android.cursor.item/。

  3. 最后接上 vnd.<authority>.<path>。

对于 content://com.example.app.provider/table1 这个内容 URI,它所对应的 MIME类型就可以写成:

  vnd.android.cursor.dir/vnd.com.example.provider.table1

对于 content://com.example.app.provider/table1/1 这个内容 URI,它所对应的 MIME 类型就可以写成:

  vnd.android.cursor.item/vnd. com.example.app.provider.table1

 

  • 实现一个内容提供器

 

 

package com.example.databasetest;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.widget.Toast;

public class DatabaseProvider extends ContentProvider {

    private static final int BOOK_DIR = 0;  //dir is end with path
    private static final int BOOK_ITEM = 1; //item is end with number
    private static final int CATEGORY_DIR = 2;
    private static final int CATEGORY_ITEM = 3;
    private static final String AUTHORITY = "com.example.databasetest.provider";
    private static UriMatcher uriMatcher;
    private MyDatabaseHelper dbHelper;
    
    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
        uriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);
        uriMatcher.addURI(AUTHORITY, "category", CATEGORY_DIR);
        uriMatcher.addURI(AUTHORITY, "category/#", CATEGORY_ITEM);
    }
    
    @Override
    public boolean onCreate() {
        //Toast.makeText(getContext(), "Provider create", Toast.LENGTH_SHORT).show();
        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        // TODO Auto-generated method stub
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        Cursor cursor = null;
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            cursor = db.query("book", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            cursor = db.query("book", projection, "id = ?", new String[]{bookId}, null, null, sortOrder);
            break;
        case CATEGORY_DIR:
            cursor = db.query("category", projection, selection, selectionArgs, null, null, sortOrder);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            cursor = db.query("category", projection, "id = ?", new String[] {categoryId}, null, null, sortOrder);
            break;
        default:
            break;
        }
        return cursor;
    }

    @Override
    public String getType(Uri uri) {
        // TODO Auto-generated method stub
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.book";
        case BOOK_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.book";
        case CATEGORY_DIR:
            return "vnd.android.cursor.dir/vnd.com.example.databasetest.provider.category";
        case CATEGORY_ITEM:
            return "vnd.android.cursor.item/vnd.com.example.databasetest.provider.category";
        default:
            return null;
        }
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO Auto-generated method stub
        
        Uri uriReturn = null;
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
        case BOOK_ITEM:
            //插入都是在一张表中
            long newBookId = db.insert("book", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);
            break;
        case CATEGORY_DIR:
        case CATEGORY_ITEM:
            long newCategoryId = db.insert("category", null, values);
            uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);
            break;
        default:
            break;
        }
        return uriReturn;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        int deleteRows = 0;
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            deleteRows = db.delete("book", selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            deleteRows = db.delete("book", "id = ?", new String[]{bookId});
            break;
        case CATEGORY_DIR:
            deleteRows = db.delete("category", selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            deleteRows = db.delete("category", "id = ?", new String[]{categoryId});
            break;
        default:
            break;
        }
        return deleteRows;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        // TODO Auto-generated method stub
        int updateRows = 0;
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        switch (uriMatcher.match(uri)) {
        case BOOK_DIR:
            updateRows = db.update("book", values, selection, selectionArgs);
            break;
        case BOOK_ITEM:
            String bookId = uri.getPathSegments().get(1);
            updateRows = db.update("book", values, "id = ?", new String[]{bookId});
            break;
        case CATEGORY_DIR:
            updateRows = db.update("category", values, selection, selectionArgs);
            break;
        case CATEGORY_ITEM:
            String categoryId = uri.getPathSegments().get(1);
            updateRows = db.update("category", values, "id = ?", new String[]{categoryId});
            break;
        default:
            break;
        }
        return updateRows;
    }

}

 

这是一个我写好的内容提供器,在每一个方法内,我们通过uriMacther.matcher()来匹配uri,根据匹配到的值来进行所需的操作。

之后我们要在这个程序的AndroidManifest.xml文件中注册:

        <!-- 
              :name  指定类的全名
              :authorities  指定内容提供器的权限
        -->
           <provider
            android:name="com.example.databasetest.DatabaseProvider"
            android:authorities="com.example.databasetest.provider" 
            android:exported="true">
        </provider>

 

注意这里要加 android:exported="true"           这个属性用于指示该服务是否能够被其他应用程序组件调用或跟它交互。

这样我们就完成了一个内容提供器,我们可以新建一个程序通过ContentReslover来访问这个内容提供器了。

 

 

到这里学习了安卓如何实现程序间数据的共享,内容提供器的创建。

 

以上是关于安卓学习之数据共享内容提供器Content Provider的主要内容,如果未能解决你的问题,请参考以下文章

内容提供器(Content Provider)

入职小白随笔之Android四大组件——内容提供器详解(Content Provider)

Android 跨程序共享数据,探究内容提供器

python学习之迭代器与生成器

JUC学习之共享模型工具之JUC并发工具包上

[Android Pro] 将你的安卓手机屏幕共享到PC或Mac上