Android笔记(ContentProvider)

一、ContentProvider的数据模型和URI

数据模型

ContentProvider 使用基于数据库模型的简单表格来提供需要共享的数据,在该表格中,每一行表示一条记录,而每一列代表特定类型和含义的数据,并且其中每一条数据记录都包含一个名为“_ID”的字段类标识每条数据。

Uri

    如果B应用程序想操纵A应用程序的数据,那么B应用程序一般通过ContentResolver类操纵A应用程序的数据,在ContentResolver类中,通过URI标识B程序要操纵A程序中的哪个数据。Uri为内容提供者中的数据建立了唯一标识符。它主要由三部分组成,scheme、authorities和path。

 

其中,authority部分指定了B程序要操纵的目标应用程序(即A程序),通常用目标应用程序的包名进行命名。path部分主要是对目标应用程序中不同的表做区分。

uri做补充

   譬如现在A程序中有两张表table1和table2,A的包名为cn.itcast.mycontentprovider,B程序想要操纵table1这张表,uri则为:

content:// cn.itcast.mycontentprovider/table1

想要操纵table2这张表,uri则为:

content:// cn.itcast.mycontentprovider/table2

如果B程序希望访问A程序table1表中id为1的数据,那么还可以在URI的最后加/id号,例如content:// cn.itcast.mycontentprovider/table1/1

 

二、访问其他程序中的数据方法

通过ContentProvider查询其他程序数据的具体步骤如下:

   1. 通过parse()方法解析Uri

   例如:Uri uri = Uri.parse("content://cn.itcast.mycontentprovider/person");

   2. 通过query()方法查询数据

    //获取ContentResolver对象

   ContentResolver resolver = context.getContentResolver();

   Cursor cursor = resolver.query(Uri uri, String[] projection, String selection,                                                                  String[] selectionArgs, String sortOrder);

   3. 通过while()循环语句遍历查询到的数据

       while (cursor.moveToNext()) {

         String address = cursor.getString(0);

         long date = cursor.getLong(1);

         int type = cursor.getInt(2);

    }

cursor.close(); //关闭cursor

对目标应用程序中的数据进行增添数据,删除数据,修改数据的方法与查询数据类似,主要是2,3两步有所区别,但无一例外,都是要先获得uri对象,再获取ContentResolver对象,最后通过ContentResolver对象中的insert,update, delete等方法进行操作。

 

三、创建自己的内容提供器

   考虑这样一个场景,仍然是B程序想操纵A程序中的数据,A程序现在由我们自己编写,那么A程序就需要用内容提供器来将自己的数据暴露。那么如何创建自己的内容提供器呢?创建步骤见书6.2或者ppt,ppt上写的很详细。

创建好的内容提供者的默认代码如下:

import android.content.ContentProvider;

import android.content.ContentValues;

import android.database.Cursor;

import android.net.Uri;

 

public class MyContentProvider2 extends ContentProvider {

    public MyContentProvider2() {

    }

 

    @Override

    public int delete(Uri uri, String selection, String[] selectionArgs) {

        // Implement this to handle requests to delete one or more rows.

        throw new UnsupportedOperationException("Not yet implemented");

    }

 

    @Override

    public String getType(Uri uri) {

        // TODO: Implement this to handle requests for the MIME type of the data

        // at the given URI.

        throw new UnsupportedOperationException("Not yet implemented");

    }

 

    @Override

    public Uri insert(Uri uri, ContentValues values) {

        // TODO: Implement this to handle requests to insert a new row.

        throw new UnsupportedOperationException("Not yet implemented");

    }

 

    @Override

    public boolean onCreate() {

        // TODO: Implement this to initialize your content provider on startup.

        return false;

    }

 

    @Override

    public Cursor query(Uri uri, String[] projection, String selection,

                        String[] selectionArgs, String sortOrder) {

        // TODO: Implement this to handle query requests from clients.

        throw new UnsupportedOperationException("Not yet implemented");

    }

 

    @Override

    public int update(Uri uri, ContentValues values, String selection,

                      String[] selectionArgs) {

        // TODO: Implement this to handle requests to update one or more rows.

        throw new UnsupportedOperationException("Not yet implemented");

    }

}

  其中,创建出来的内容提供器继承自ContentProvider这个类,ContentProvider这个类有6个抽象方法。创建出来的内容提供器需要重写这6个方法。6个方法的简介如下:

onCreate(): 初始化内容提供器时调用,在这里通常完成数据库的创建和升级。只有当ContentResolver尝试访问程序中的数据时,内容提供器才会被初始化。

query(): 从内容提供器中查询数据

insert(): 向内容提供器中添加数据

update(): 更新内容提供器中已有的数据

delete(): 从内容提供器中删除数据

getType(): 根据传入的内容URI返回相应的MIME类型

  有关ContentProvider在AndroidManifest.xml中的注册以及相关属性,见教材p129-130。那么如何具体地重写内容提供器?

 

1. UriMatcher类

譬如A程序中有3个表table1,table2,table3,B程序想操纵A程序中的数据,就需要对不同的表做区分,之前讲过是用uri标识数据,那么就需要用不同的uri做区分,此时就可以用UriMatcher类对Uri进行匹配。具体步骤见书131页或者ppt。

2. addURI方法

addURI方法将需要的Uri注册到UriMatcher中,希望注册的uri的格式主要有以下几种。

匹配一张表:content:// cn.itcast.mycontentprovider/table1

匹配一条数据:content:// cn.itcast.mycontentprovider/table1/1

还可以使用通配符*和#

*表示匹配任意长度的字符,#表示匹配任意长度的数字

匹配任意表:content:// cn.itcast.mycontentprovider/*

匹配任意一行数据:content:// cn.itcast.mycontentprovider/table1/#

addURI主要有三个参数,分别是authority,path和自定义的代码,其中,authoriy和path就指定了要匹配的uri样式,自定义的代码就是匹配成功时的返回值。根据这个代码,就可以判断出调用方期望访问的是哪张表中的数据了。

3. getType()方法

该方法是所有的内容提供器必须提供的一个方法,用于获取uri对象对应的MIME类型。MIME字符串由3部分组成

-  必须vnd开头

-  如果uri以路径结尾(即表示匹配的是一张表),后接android.cursor.dir/,如果以id结尾(即匹配的是一条记录),后接android.cursor.item/

-  最后接vnd.<authority>.<path>

在A应用程序中写完ContentProvider后,便可新建应用程序B,从而访问A应用程序中的数据

 

完整示范代码

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;

 

public class MyContentProvider extends ContentProvider {

 

    public static final int BOOK_DIR = 0;

    public static final int BOOK_ITEM = 1;

    public static final int CATEGORY_DIR = 2;

    public static final int CATEGORY_ITEM = 3;

    public static final String AUTHORITY = "com.example.a30228.dct2application";

    //定义一个uriMatcher,这个uriMatcher用来匹配其他应用程序请求的uri

    private static UriMatcher uriMatcher;

    private MyOpenHelper dbhelper;

 

    static {

        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

        //注册需要的uri(本质上来讲就是将数据库当中特定数据暴露出去)

        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 int delete(Uri uri, String selection, String[] selectionArgs) {

        // Implement this to handle requests to delete one or more rows.

        SQLiteDatabase db = dbhelper.getReadableDatabase();

        int deleteRows = 0;

        switch(uriMatcher.match(uri)){

            case BOOK_DIR:  //表示其他应用程序的uri和注册的uri当中Book表匹配成功

                deleteRows = db.delete("Book",selection, selectionArgs);

                break;

            case BOOK_ITEM: //表示其他应用程序的uri和注册的uri当中Book表中某条记录匹配成功

                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;

        }

        //db.close();

        return deleteRows;

    }

 

    @Override

    public String getType(Uri uri) {

        // TODO: Implement this to handle requests for the MIME type of the data

        // at the given URI.

        switch (uriMatcher.match(uri)){

            case BOOK_DIR:

                return "vnd.android.cursor.dir/vnd.com.example.a30228.dct2application.Book";

            case BOOK_ITEM:

                return "vnd.android.cursor.item/vnd.com.example.a30228.dct2application.Book";

            case CATEGORY_DIR:

                return "vnd.android.cursor.dir/vnd.com.example.a30228.dct2application.Category";

            case CATEGORY_ITEM:

                return "vnd.android.cursor.item/vnd.com.example.a30228.dct2application.Category";

        }

        return null;

    }

 

    @Override

    public Uri insert(Uri uri, ContentValues values) {

        // TODO: Implement this to handle requests to insert a new row.

        SQLiteDatabase db = dbhelper.getReadableDatabase();

        Uri uriReturn = null;

        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;

        }

        //db.close();

        return uriReturn;

    }

 

    @Override

    public boolean onCreate() {

        // TODO: Implement this to initialize your content provider on startup.

        dbhelper = new MyOpenHelper(getContext());

        return true;

    }

 

    @Override

    public Cursor query(Uri uri, String[] projection, String selection,

                        String[] selectionArgs, String sortOrder) {

        // TODO: Implement this to handle query requests from clients.

        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;

        }

        //db.close();

        return cursor;

    }

 

    @Override

    public int update(Uri uri, ContentValues values, String selection,

                      String[] selectionArgs) {

        // TODO: Implement this to handle requests to update one or more rows.

        SQLiteDatabase db = dbhelper.getReadableDatabase();

        int updateRows = 0;

        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;

        }

        //db.close();

        return updateRows;

    }

}

 

posted @ 2022-04-27 23:10  Atomyzd  阅读(276)  评论(0编辑  收藏  举报