Demo:ContentProvider 内容提供者

Demo:ContentProvider 内容提供者

Android 系统提供了三种方式来实现数据持久化(数据存储),即文件存储、SharedPreference 存储、数据库存储,而这三种方式只是程序内部共享与存储数据,要实现跨程序共享数据,就要使用 ContentProvider(内容提供者),将自己的数据共享给其它应用程序,但 ContentProvider 存储数据的方式还是基于前面提到的三种数据持久化技术,本文就使用数据库存储数据。

关于如何使用 SQLite 存储数据,请阅读另一篇文章:Android 数据持久化(SQLite数据存储)

本文源代码下载:http://download.csdn.net/download/xwdoor/9435978

1 创建自己的 Content Provider

1.1 创建类 BookInfoProvider 继承自 ContentProvider


    public class BookInfoProvider extends ContentProvider {
        public BookInfoProvider() {
        }

        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            throw new UnsupportedOperationException("Not yet implemented");
        }

        @Override
        public String getType(Uri uri) {
            throw new UnsupportedOperationException("Not yet implemented");
        }

        @Override
        public Uri insert(Uri uri, ContentValues values) {
            return null;
        }

        @Override
        public boolean onCreate() {
            return false;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                            String[] selectionArgs, String sortOrder) {
            return null;
        }

        @Override
        public int update(Uri uri, ContentValues values, String selection,
                          String[] selectionArgs) {
            return 0;
        }
    }

1.2 认识 Uri

一个标准的 Uri 的写法是这样的:
content://com.example.app.provider/table1
以路径结尾,表示期望访问 com.example.app 这个应用中的 table1 表中的所有数据。当然,我们也可以访问其中某一条数据:
content://com.example.app.provider/table1/1
以 id 结尾,表示期望访问 com.example.app 这个应用中的 table1 表中的 id 为1的数据。

当然,也可以使用通配符:

  • *:表示匹配任意长度的任意字符,对应 Uri 格式:content://com.example.app.provider/
  • #:表示匹配任意长度的数字,对应 Uri 格式:content://com.example.app.provider/table1/#

1.3 认识 UriMatcher

UriMatcher 这个类就可以轻松地实现匹配内容 URI 的功能,UriMatcher
中提供了一个 addURI() 方法,这个方法接收三个参数,可以分别把权限、路径和一个自定义代码传进去。当 UriMatcher 匹配成功时,会返回相应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。
在 BookInfoProvider 类中添加以下代码:


    public static final String AUTHORITY = "net.xwdoor.provider.bookinfo";

    //表示访问 Book 表中的所有数据
    public static final int TABLE_BOOK_DIR = 0;
    //表示访问 Book 表中的单条数据
    public static final int TABLE_BOOK_ITEM = 1;

    private static UriMatcher mUriMatcher;
    static {
        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        mUriMatcher.addURI(AUTHORITY, BookDbHelper.TABLE_BOOK,TABLE_BOOK_DIR);
        mUriMatcher.addURI(AUTHORITY, BookDbHelper.TABLE_BOOK+"/#",TABLE_BOOK_ITEM);
    }

1.4 Uri 的 MIME 类型

ContentProvider 中还有一个 getType() 方法,用于获取 Uri 对象所对应的 MIME 类型,一个内容 URI 所对应的 MIME 字符串主要由三部分组成,Android 对这三个部分有如下规定:

  1. 必须以 vnd. 开头
  2. 如果 Uri 对象以路径结尾,则后接 android.cursor.dir/,如果 Uri 对象以 id 结尾,则后接 android.cursor.item/
  3. 最后接上 vnd..

所以,对于 content://com.example.app.provider/table1 这个 Uri,它所对应的 MIME 类型就是:

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

对于 content://com.example.app.provider/table1/1 这个 Uri,对应的 MIME 类型就是:

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

实现 getType() 方法的逻辑后,代码如下:


    @Override
    public String getType(Uri uri) {
        switch (mUriMatcher.match(uri)) {
            case TABLE_BOOK_ITEM:
                return "vnd.android.cursor.item/" + AUTHORITY + "." + BookDbHelper.TABLE_BOOK;
            case TABLE_BOOK_DIR:
                return "vnd.android.cursor.dir/" + AUTHORITY + "." + BookDbHelper.TABLE_BOOK;
        }
        return null;
    }

2 实现 Content Provider

实现跨程序数据共享,完成 ContentProvider 的 CRUD 操作,代码如下:


    public class BookInfoProvider extends ContentProvider {
        public static final String AUTHORITY = "net.xwdoor.provider.bookinfo";

        //表示访问 Book 表中的所有数据
        public static final int TABLE_BOOK_DIR = 0;
        //表示访问 Book 表中的单条数据
        public static final int TABLE_BOOK_ITEM = 1;

        private static UriMatcher mUriMatcher;

        static {
            mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            mUriMatcher.addURI(AUTHORITY, BookDbHelper.TABLE_BOOK, TABLE_BOOK_DIR);
            mUriMatcher.addURI(AUTHORITY, BookDbHelper.TABLE_BOOK + "/#", TABLE_BOOK_ITEM);
        }

        private BookDbHelper mBookDb;

        public BookInfoProvider() {
        }

        @Override
        public boolean onCreate() {
            mBookDb = new BookDbHelper(getContext(), "BookStore.db", null, 1);
            return true;
        }

        //删除数据
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            SQLiteDatabase writeDb = mBookDb.getWritableDatabase();
            int deleteRows = 0;
            switch (mUriMatcher.match(uri)) {
                case TABLE_BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    deleteRows = writeDb.delete(BookDbHelper.TABLE_BOOK, "id=?", new String[]{bookId});
                    break;
                case TABLE_BOOK_DIR:
                    deleteRows = writeDb.delete(BookDbHelper.TABLE_BOOK,selection,selectionArgs);
                    break;
            }
            return deleteRows;
        }

        //获取 Uri 类型
        @Override
        public String getType(Uri uri) {
            switch (mUriMatcher.match(uri)) {
                case TABLE_BOOK_ITEM:
                    return "vnd.android.cursor.item/" + AUTHORITY + "." + BookDbHelper.TABLE_BOOK;
                case TABLE_BOOK_DIR:
                    return "vnd.android.cursor.dir/" + AUTHORITY + "." + BookDbHelper.TABLE_BOOK;
            }
            return null;
        }

        //插入数据
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            SQLiteDatabase writeDb = mBookDb.getWritableDatabase();
            Uri newUri = null;
            switch (mUriMatcher.match(uri)) {
                case TABLE_BOOK_ITEM:
                case TABLE_BOOK_DIR:
                    long newBookId = writeDb.insert(BookDbHelper.TABLE_BOOK,null,values);
                    newUri = Uri.parse("content://"+AUTHORITY+"/"+BookDbHelper.TABLE_BOOK+"/"+newBookId);
                    break;
            }
            return newUri;
        }

        //查询数据
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                            String[] selectionArgs, String sortOrder) {
            SQLiteDatabase writeDb = mBookDb.getWritableDatabase();
            Cursor cursor = null;
            switch (mUriMatcher.match(uri)) {
                case TABLE_BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    cursor = writeDb.query(BookDbHelper.TABLE_BOOK,null,"id=?",new String[]{bookId},null,null,null);
                    break;
                case TABLE_BOOK_DIR:
                    cursor = writeDb.query(BookDbHelper.TABLE_BOOK,projection,selection,selectionArgs,null,null,sortOrder);
                    break;
            }
            return cursor;
        }

        //更新数据
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                          String[] selectionArgs) {
            SQLiteDatabase writeDb = mBookDb.getWritableDatabase();
            int updateRows = 0;
            switch (mUriMatcher.match(uri)) {
                case TABLE_BOOK_ITEM:
                    String bookId = uri.getPathSegments().get(1);
                    updateRows = writeDb.update(BookDbHelper.TABLE_BOOK,values,"id=?",new String[]{bookId});
                    break;
                case TABLE_BOOK_DIR:
                    updateRows = writeDb.update(BookDbHelper.TABLE_BOOK,values,selection,selectionArgs);
                    break;
            }
            return updateRows;
        }
    }

3 访问 ContentProvider 数据

好了,ContentProvider 中的代码全部编写完了,不过离实现跨程序数据共享的功能还差了一小步,接下来就是新建一个 Module:ProviderTest,我们就将通过这个程序去访问 ContentProviderTest 中的数据。

3.1 布局文件

很简单,布局文件中放置四个按钮,分别对应 CRUD 操作,即用于添加、查询、修改和删除数据的,代码如下:


    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="net.xwdoor.contentprovidertest.MainActivity">

        <Button
            android:id="@+id/btn_add_book"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Add Book"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/btn_update_book"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Update Book's Price By Name"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/btn_delete_book"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Delete Book By Name"
            android:textAllCaps="false" />

        <Button
            android:id="@+id/btn_query_book"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Query Book"
            android:textAllCaps="false" />

        <TextView
            android:id="@+id/tv_books"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

3.2 访问 ContentProvider

在 MainActivity 中实现代码逻辑,这样就能够正常访问 ContentProvider 了。


    private String newsId;
    @Override
    public void onClick(View view) {
        Uri uriDir = Uri.parse("content://net.xwdoor.provider.bookinfo/Book");
        switch (view.getId()) {
            case R.id.btn_add_book:
                //添加书籍
                for (Book book : mBooks) {
                    ContentValues values = new ContentValues();
                    values.put(Book.BOOK_AUTHOR, book.author);
                    values.put(Book.BOOK_PRICE, book.price);
                    values.put(Book.BOOK_PAGES, book.pages);
                    values.put(Book.BOOK_NAME, book.name);
                    Uri r = getContentResolver().insert(uriDir, values);
                    if (r != null) {
                        newsId = r.getPathSegments().get(1);
                    }
                    values.clear();
                }
                break;
            case R.id.btn_update_book:
                //更新书籍价格
                ContentValues values = new ContentValues();
                values.put(Book.BOOK_PRICE, 33.3);
                getContentResolver().update(uriDir,values,"name=?",new String[]{mBooks.get(1).name});
                break;
            case R.id.btn_delete_book:
                //删除书籍
                getContentResolver().delete(uriDir,"name=?",new String[]{mBooks.get(1).name});
                break;
            case R.id.btn_query_book:
                Uri uri = Uri.parse("content://net.xwdoor.provider.bookinfo/Book");
                Cursor cursor = getContentResolver().query(uri, null, null, null, null);
                if (cursor != null && cursor.moveToFirst()) {
                    do {
                        Book book = new Book();
                        book.author = cursor.getString(cursor.getColumnIndex(Book.BOOK_AUTHOR));
                        book.name = cursor.getString(cursor.getColumnIndex(Book.BOOK_NAME));
                        book.price = cursor.getFloat(cursor.getColumnIndex(Book.BOOK_PRICE));
                        book.pages = cursor.getInt(cursor.getColumnIndex(Book.BOOK_PAGES));
                        tvBooks.append(book + "\n");
                    } while (cursor.moveToNext());
                    //关键:一定要关闭cursor
                    cursor.close();
                }
                break;
        }
    }

4 总结

这次算是把知识复习了一遍,一切还算顺利。

源代码下载:http://download.csdn.net/download/xwdoor/9435978

你可能感兴趣的:(android,内容提供者,Provider,demo)