zoukankan      html  css  js  c++  java
  • 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();
        }
    }
  • 相关阅读:
    spring aop 之链式调用
    Java中的java.lang.Class API 详解
    Java 内省(Introspector)和 BeanUtils
    Small Spring系列一:BeanFactory(一)
    (C#) 多线程访问探讨,如果保证线程安全?
    (C#) 多线程访问int, bool 等值类型变量
    (WCF) 利用WCF实现两个Process之间的通讯。
    (PowerShell) 重命名文件
    JavaScript : Array assignment creates reference not copy
    (C#) 表达式树
  • 原文地址:https://www.cnblogs.com/grooovvve/p/12484886.html
Copyright © 2011-2022 走看看