Android13_IPC方式之ContentProvider

ContentProvider是安卓提供的专门用于不同应用间进行数据共享的方式;它天生适合进程间通信;

和Messenger一样,ContentProvider的底层实现同样也是Binder;

ContentProvider还是四大组件之一;

其实ContentProvider的使用涉及的细节还是很多的;

一般来讲ContentProvider用于对应用的数据库进行增删改查;

我们可以访问跨应用地其他应用提供的ContentProvider,也可以自定义一个ContentProvider;

自己实现ContentProvider要自定义一个类继承自ContentProvider并实现六个抽象方法:onCreate、query、update、insert、delete、getType;

 

 

1、首先在Manifest中注册ContentProvider组件:

android:autorities  是作为标识,一般用完整包名加类名

android:permission 表示权限,其他应用想要用这个ContentProvider时,继续声明该权限才可以,否则外界应用会异常终止;

android:process    这里为了演示方便,直接在同一个应用中开启多进程模式,MainActivity一个进程,ContentProvider一个进程;

至于process如何设置在 Android8_安卓的IPC机制 中 的开启多进程模式有介绍到,这里就不展开讨论;https://www.cnblogs.com/grooovvve/p/12462286.html

 

2、编写DbOpenHelper类

这个类用于管理数据的创建、升级、降级

package com.example.learncontentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

//利用SQLiteHelper来管理数据库的创建、升级、降级
public class DbOpenHelper extends SQLiteOpenHelper {
    private static final String TAG = "DbOpenHelper";
    private static final String DB_NAME = "book_provider.db";
    public static final String BOOK_TABLE_NAME="book";
    public static final String USER_TABLE_NAME="user";
    private static final int DB_VERSION = 1;
    //建表语句 图书和用户信息表
    private String CREATE_BOOK_TABLE = "CREATE TABLE IF NOT EXISTS "
            +BOOK_TABLE_NAME
            +"(_id INTEGER PRIMARY KEY,"
            +"name TEXT)";

    private String CREATE_USER_TABLE="CREATE TABLE IF NOT EXISTS "
            +USER_TABLE_NAME
            +"(_id INTEGER PRIMARY KEY,"
            +"name TEXT,"
            +"sex INT)";

    public DbOpenHelper(Context context){
        super(context,DB_NAME,null,DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG,"onCreate");
        db.execSQL(CREATE_BOOK_TABLE);
        db.execSQL(CREATE_USER_TABLE);
    }

    //用于对数据库进行升级的,是否执行该方法要看DbOpenHelper构造函数传入的version是否比之前更大。
    //可以尝试第一次运行该程序version为1,第二次运行该程序version为2
    //每次运行后用adb工具查看数据库文件创建情况
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        Log.d(TAG,"onUpgrade");
        db.execSQL("drop table if exists Book");
        db.execSQL("drop table if exists Category");
        onCreate(db);
    }

}

 

 

3、编写BookProvider组件

 

package com.example.learncontentprovider;

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.util.Log;


//用BookeProvider向外界提供数据库中的信息
//ContentProvider通过Uri来分辨外界要访问的数据集合
//为了让外界知道要访问哪个表,需要单独为本例中的book表、user表定义单独的Uri和Uri_Code
//将Uri和Uri_Code进行关联
//外界通过Uri访问BookProvider,我们可以根据Uri和Uri_Code的关联,知道外界想要访问哪个表,然后可以进行相应的数据操作
public class BookProvider extends ContentProvider {

    private static final String TAG = "BookProvider";
    private static final String AUTHORITY = "com.example.learncontentprovider.BookProvider";

    private static final Uri BOOK_CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/book");
    private static final Uri USER_CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/user");

    private static final int BOOK_URI_CODE = 0;
    private static final int USER_URI_CODE = 1;

    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);


    //这个Uri和URICode的关联过程是由下面语句来完成的
    static{
        sUriMatcher.addURI(AUTHORITY,"book",BOOK_URI_CODE);
        sUriMatcher.addURI(AUTHORITY,"user",USER_URI_CODE);
    }

    private SQLiteDatabase mdb;

    //匹配函数,根据Uri获取要访问的表名
    private String getTableName(Uri uri){
        String tableName = null;
        switch (sUriMatcher.match(uri)){
            case BOOK_URI_CODE:
                tableName = DbOpenHelper.BOOK_TABLE_NAME;
                break;
            case USER_URI_CODE:
                tableName = DbOpenHelper.USER_TABLE_NAME;
                break;
            default:
                break;
        }
        return tableName;
    }



    //onCreate会运行在主线程中,也就是UI线程,所以不能在onCreate中做耗时操作
    @Override
    public boolean onCreate(){
        Log.d(TAG,"onCreate, current thread:"+Thread.currentThread().getName());
        mdb = new DbOpenHelper(getContext()).getWritableDatabase();
        //实际上不适合在主线程进行耗时的数据库操作
        initProviderData();
        return true;
    }

    private void initProviderData(){
        mdb.execSQL("delete from "+DbOpenHelper.BOOK_TABLE_NAME);
        mdb.execSQL("delete from "+DbOpenHelper.USER_TABLE_NAME);
        mdb.execSQL("insert into book values(3,'Android');");
        mdb.execSQL("insert into book values(2,'IOS');");
        mdb.execSQL("insert into book values(5,'HTML5');");
        mdb.execSQL("insert into user values(1,'jake',1);");
        mdb.execSQL("insert into user values(2,'jasmine',0);");
    }

    @Override
    public String getType(Uri uri) {
        Log.d(TAG,"getType");
        return null;
    }
    //增删改查四大方法支持多线程并发访问,因此方法内部要做好线程同步,但是本例中采用的是SQLite并且只有一个SQLiteDatabase连接;
    //所以可以正确应对多线程情况;原因是SQLiteDatabase内部对数据库的操作有同步处理;
    //但是对于多个SQLiteDatabase对象来操作数据库就无法保证数据库是一块内存的话,就必须进行线程同步;
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
        Log.d(TAG,"query, current thread:"+Thread.currentThread().getName());
        String table = getTableName(uri);
        if(table == null){
            throw new IllegalArgumentException("Unsupported URI:"+uri);
        }
        Cursor cursor = null;
        cursor =mdb.query(table,projection,selection,selectionArgs,null,sortOrder,null);
        return cursor;
    }



    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Log.d(TAG,"insert");
        String table = getTableName(uri);
        if(table == null){
            throw new IllegalArgumentException("Unsupported URI:"+uri);
        }
        mdb.insert(table,null,values);
        //getContext().getContentResolver().notifyChange(uri,null);
        return uri;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        Log.d(TAG,"delete");
        String table = getTableName(uri);
        if(table == null){
            throw new IllegalArgumentException("Unsupported URI:"+uri);
        }
        int count = mdb.delete(table,selection,selectionArgs);
        if(count>0){
            getContext().getContentResolver().notifyChange(uri,null);
        }
        return count;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        Log.d(TAG,"update");
        String table = getTableName(uri);
        if(table == null){
            throw new IllegalArgumentException("Unsupported URI:"+uri);
        }
        int row = mdb.update(table,values,selection,selectionArgs);
        if(row>0){
            getContext().getContentResolver().notifyChange(uri,null);
        }
        return row;
    }
}

 

 

4、编写MainActivity

 

package com.example.learncontentprovider;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;


public class MainActivity extends AppCompatActivity {
    private static final String TAG = "Activity";

    public class Book{
        int bookId;
        String bookName;
    }

    public class User{
        int userId;
        String usrName;
        boolean isMale;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Uri bookuri = Uri.parse("content://com.example.learncontentprovider.BookProvider/book");  //唯一标识了BookProvider
        //以下的三次调用,会运行在不同的线程中
        //getContentResolver().query(uri,null,null,null,null);
        //getContentResolver().query(uri,null,null,null,null);
        //getContentResolver().query(uri,null,null,null,null);

        ContentValues values = new ContentValues();
        values.put("_id",6);
        values.put("name","程序设计的艺术");
        getContentResolver().insert(bookuri,values);
        Cursor bookcursor = getContentResolver().query(bookuri,new String[]{"_id","name"},null,null,null);
        while(bookcursor.moveToNext()){
            Book book = new Book();
            book.bookId = bookcursor.getInt(0);
            book.bookName = bookcursor.getString(1);
            Log.d(TAG,"query book: "+ book.toString());
        }
        bookcursor.close();

        Uri useruri = Uri.parse("content://com.example.learncontentprovider.BookProvider/user");
        Cursor userCursor = getContentResolver().query(useruri,new String[]{"_id","name","sex"},null,null,null);
        while(userCursor.moveToNext()){
            User user = new User();
            user.userId = userCursor.getInt(0);
            user.usrName = userCursor.getString(1);
            user.isMale = userCursor.getInt(2)==1;
            Log.d(TAG,"query book: "+ user.toString());
        }
        userCursor.close();
    }
}

 

posted @ 2020-03-13 10:38  Grooovvve  阅读(178)  评论(0编辑  收藏  举报