美文网首页
ContentProvider

ContentProvider

作者: _Rice_ | 来源:发表于2019-03-11 15:48 被阅读0次

讲ContentProvider之前,先介绍下SQLite以及SQListeOpenHelper

(1)SQLite介绍

SQLite是一个轻量级的数据库,不是一个C/S结构的数据库引擎,而是被集成到用户程序中。这个库也被动态链接,应用程序中直接调用相关API来使用SQLite功能,比跨进程通通信更有效率。SQLite将整个数据库作为一个单独的、可跨平台使用的文件存储在主机中

SQLite 是在世界上最广泛部署的 SQL 数据库引擎。像Android、IOS等移动操作系统中的数据库实现都是用SQLite

优点:

  • 无服务器、零配置、事务性。
  • 存储在一个单一磁盘文件中的一个完整数据库
  • 数据库文件可以在不同字节顺序的机器自由共享
  • 支持数据库大小2TB
  • 足够小,全部源代码250KB
  • 对数据操作快
  • 开源

结构

image.png

1.接口(Interface)
  接口由SQLite C API组成,也就是说不管是程序、脚本语言还是库文件,最终都是通过它与SQLite交互的(我们通常用得较多的ODBC/JDBC最后也会转化为相应C API的调用)。
2.编译器(Compiler)
  在编译器中,分词器(Tokenizer)和分析器(Parser)对SQL进行语法检查,然后把它转化为底层能更方便处理的分层的数据结构---语法树,然后把语法树传给代码生成器(code generator)进行处理。而代码生成器根据它生成一种针对SQLite的汇编代码,最后由虚拟机(Virtual Machine)执行。
3.虚拟机(Virtual Machine)
  架构中最核心的部分是虚拟机,或者叫做虚拟数据库引擎(Virtual Database Engine,VDBE)。它和Java虚拟机相似,解释执行字节代码。VDBE的字节代码由128个操作码(opcodes)构成,它们主要集中在数据库操作。它的每一条指令都用来完成特定的数据库操作(比如打开一个表的游标)或者为这些操作栈空间的准备(比如压入参数)。总之,所有的这些指令都是为了满足SQL命令的要求(关于VM,后面会做详细介绍)。
4.后端(Back-End)
  后端由B-树(B-tree),页缓存(page cache,pager)和操作系统接口(即系统调用)构成。B-tree和page cache共同对数据进行管理。B-tree的主要功能就是索引,它维护着各个页面之间的复杂的关系,便于快速找到所需数据。而pager的主要作用就是通过OS接口在B-tree和Disk之间传递页面。

参考:

SQLite剖析之体系结构

(2)SQL语言学习

参考:

SQLite 教程

(3)SQListeOpenHelper

是一个sqlite辅助操作类

常用方法:

/** 
  *  创建数据库
  */ 
 // 1. 创建 or 打开 可读/写的数据库(通过 返回的SQLiteDatabase对象 进行操作)
 getWritableDatabase()

 // 2. 创建 or 打开 可读的数据库(通过 返回的SQLiteDatabase对象 进行操作)
 getReadableDatabase()

 // 3. 数据库第1次创建时 则会调用,即 第1次调用 getWritableDatabase() / getReadableDatabase()时调用
 // 在继承SQLiteOpenHelper类的子类中复写
 onCreate(SQLiteDatabase db) 

 // 4. 数据库升级时自动调用
 // 在继承SQLiteOpenHelper类的子类中复写
 onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)

 // 5. 关闭数据库
 close()

 /** 
  *  数据库操作(增、删、减、查)
  */ 
 // 1. 查询数据
 (Cursor) query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)  
 // 查询指定的数据表返回一个带游标的数据集。
 // 各参数说明: 
 // table:表名称 
 // colums:列名称数组 
 // selection:条件子句,相当于where 
 // selectionArgs:条件语句的参数数组 
 // groupBy:分组 
 // having:分组条件 
 // orderBy:排序类 
 // limit:分页查询的限制 
 // Cursor:返回值,相当于结果集ResultSet 

 (Cursor) rawQuery(String sql, String[] selectionArgs) 
 //运行一个预置的SQL语句,返回带游标的数据集(与上面的语句最大的区别 = 防止SQL注入)

 // 2. 删除数据行  
 (int) delete(String table,String whereClause,String[] whereArgs) 
 
 // 3. 添加数据行 
 (long) insert(String table,String nullColumnHack,ContentValues values) 
 
 // 4. 更新数据行 
(int) update(String table, ContentValues values, String whereClause, String[] whereArgs) 
 
 // 5. 执行一个SQL语句,可以是一个select or 其他sql语句 
 // 即 直接使用String类型传入sql语句 & 执行
 (void) execSQL(String sql) 

参考

Android :SQLlite数据库 使用手册

ContentProvider

定义:内容提供者,是 Android 四大组件之一

作用:对外共享数据,使用ContentProvider的好处是统一了数据访问方式,实际上是对SQListOpenHelper的进一步封装,通过Uri映射来判断要操作数据库哪个表

(1)统一资源标识符(URI)

image.png
  • schema:固定为content://
  • authority:ContentProvider的唯一标记,调用者可以通过这个找到它
  • path:要操作的数据库表
  • id:表中的某个记 录
// 设置URI
Uri uri = Uri.parse("content://com.carson.provider/User/1") 
// 上述URI指向的资源是:名为 `com.carson.provider`的`ContentProvider` 中表名 为`User` 中的 `id`为1的数据

// 特别注意:URI模式存在匹配通配符* & #

// *:匹配任意长度的任何有效字符的字符串
// 以下的URI 表示 匹配provider的任何内容
content://com.example.app.provider/* 
// #:匹配任意长度的数字字符的字符串
// 以下的URI 表示 匹配provider中的table表的所有行
content://com.example.app.provider/table/# 

(2)ContentResolver

通过Uri来定位注册到系统的ContentProvider,找到ContentProvider之后通过ContentResolver来操作对应的数据库

获取方式:Context.getContentResolver()

常用方法:insert、query、delete、update等待

例如:读取联系人

(3)自定义ContentProvider

ContentProvider实际上是对SQLiteOpenHelper的进一步封装,通过Uri映射要判断选择需要操作的数据库中哪个表,并进行增删查改。

重写insert、query、update、delete、getType方法


public class MyProvider extends ContentProvider {
    private SQLiteDatabase db;
    public static final String AUTOHORITY = "cn.scu.myprovider";
    public static final int User_Code = 1;
    public static final int Job_Code = 2;
    private static final UriMatcher mUriMatcher;

    static {
        mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        // 初始化
        mUriMatcher.addURI(AUTOHORITY,"user",User_Code);
        mUriMatcher.addURI(AUTOHORITY,"job",Job_Code);
        // 若URI资源路径 = content://cn.scu.myprovider/user ,则返回注册码User_Code
        // 若URI资源路径 = content://cn.scu.myprovider/job ,则返回注册码Job_Code
    }

    /**
     * 根据URI匹配 URI_CODE,从而匹配ContentProvider中相应的表名
     */
    private String getTableName(Uri uri){
        String tableName = null;
        switch (mUriMatcher.match(uri)) {
            case User_Code:
                tableName = MySQListOpenHelper.USER_TABLE_NAME;
                break;
            case Job_Code:
                tableName = MySQListOpenHelper.JOB_TABLE_NAME;
                break;
        }
        return tableName;
    }
    @Override
    public boolean onCreate() {
        // 在ContentProvider创建时对数据库进行初始化
        // 运行在主线程,故不能做耗时操作,此处仅作展示
        SQLiteOpenHelper mDbHelper= new MySQListOpenHelper(getContext(),"test_person");
        db = mDbHelper.getWritableDatabase();
        return true;
    }

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

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        // 得到数据类型,即返回当前 Url 所代表数据的MIME类型
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        db.insert(getTableName(uri),null,values);
        // 当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
        getContext().getContentResolver().notifyChange(uri, null);
        return uri;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        return 0;
    }

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

UriMatcher

作用:

  • 在ContentProvider 中注册URI
  • 根据 URI 匹配 ContentProvider 中对应的数据表

ContentObserver

定义:内容观察者

作用:观察 Uri引起 ContentProvider 中的数据变化 & 通知外界(即访问该数据访问者)

// 步骤1:注册内容观察者ContentObserver
    getContentResolver().registerContentObserver(uri);
    // 通过ContentResolver类进行注册,并指定需要观察的URI

// 步骤2:当该URI的ContentProvider数据发生变化时,通知外界(即访问该ContentProvider数据的访问者)
    public class UserContentProvider extends ContentProvider { 
      public Uri insert(Uri uri, ContentValues values) { 
      db.insert("user", "userid", values); 
      getContext().getContentResolver().notifyChange(uri, null); 
      // 通知访问者
   } 
}

// 步骤3:解除观察者
 getContentResolver().unregisterContentObserver(uri);
    // 同样需要通过ContentResolver类进行解除

参考:

安卓开发进阶从小工到专家

Android:关于ContentProvider的知识都在这里了!

相关文章

网友评论

      本文标题:ContentProvider

      本文链接:https://www.haomeiwen.com/subject/lgdbpqtx.html