android contentProvider

除了共享内存(SDCard)的数据外,其他包括SQLite、SharedPreferences都是仅限于被当前所创建的应用访问,而无法使它们的数据在应用程序之间交换数据,所以Android提供了ContentProvider,ContentProvider具有以下特点:

  • 应用程序间共享数据的一种方式
  • 为存储和获取数据提供统一接口
  • android为一些常见的数据提供了ContentProvider:
    • Browser:存储如浏览器的信息。
    • CallLog:存储通话记录等信息。
    • Contacts:存储联系人等信息。
    • MediaStore:存储媒体文件的信息。
    • Settings:存储设备的设置和首选项信息。
android contentProvider_第1张图片
ContentProvider可以理解为一个Android应用对外开放的接口, 只要是符合它所定义的Uri格式的请求,均可以正常访问执行操作。
访问ContentProvider

ContentProvider 实例通过处理来自其他应用的请求来管理对结构化数据集的访问。所有形式的访问最终都会调用 ContentResolver,后者接着调用ContentProvider的具体方法来获取访问权限

一般使用Context.getContentResolver()方法获取ContentResolver对象。

ContentResolver 可提供insert、query、update、delete等方法.

例如,要从用户字典提供程序中获取字词及其区域设置的列表,则需调用 ContentResolver.query()。

// Queries the user dictionary and returns results
mCursor = getContentResolver().query(
    UserDictionary.Words.CONTENT_URI,   
    mProjection,                        
    mSelectionClause                  
    mSelectionArgs,                     
    mSortOrder);                        
query() 参数 SELECT 关键字/参数 备注
Uri FROM table_name Uri 映射至名为 table_name 的提供程序中的表。
projection col,col,col,... projection 是应该为检索到的每个行包含的列的数组。
selection WHERE col = value selection 会指定选择行的条件。
selectionArgs (没有完全等效项。选择参数会替换选择子句中 ? 的占位符。)
sortOrder ORDER BY col,col,... sortOrder 指定行在返回的 Cursor 中的显示顺序。
内容 URI

在Android中,Uri是一种比较常见的资源访问方式。每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。

:////

  • :
    ContentProvider的标准前缀始终是content://
  • :URI 的标识,用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的类名。一般为该ContentProvider的包.类的名称
  • :请求的数据类型, 如数据库的表。
  • :指定请求的特定数据。如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全部
content://user_dictionary/words
content://com.example.app.provider/table3/1
//对应由 表table3中1标识的行的内容 URI。
content://com.example.app.provider/table3/1/name
//对应由 表table3中1标识的行的name字段内容 URI。
UriMatcher

UriMatcher会将内容 URI“模式”映射到整型值。 可以在一个 switch 语句中使用这些整型值,为匹配特定模式的一个或多个内容 URI 执行相应操作。

内容 URI 模式使用通配符匹配内容 URI:

*:匹配由任意长度的任何有效字符组成的字符串
#:匹配由任意长度的数字字符组成的字符串

假设一个具有权限 com.example.app.provider的提供程序能识别以下指向表的内容 URI:

content://com.example.app.provider/table1:一个名为 table1 的表
content://com.example.app.provider/table2/dataset1:一个名为 dataset1 的表
content://com.example.app.provider/table2/dataset2:一个名为 dataset2 的表
content://com.example.app.provider/table3:一个名为 table3 的表

可以使用以下内容 URI 模式:

content://com.example.app.provider/*
//匹配提供程序中的任何内容 URI。
content://com.example.app.provider/table2/*:
//匹配表 dataset1 和表 dataset2 的内容 URI,但不匹配 table1 或 table3 的内容 URI。
content://com.example.app.provider/table3/#
//匹配 table3 中单个行的内容 URI,
//如 content://com.example.app.provider/table3/6 对应由 6 标识的行的内容 URI。

方法 addURI() 会将权限和路径映射到一个整型值。 方法 match() 会返回 URI 的整型值。switch 语句会在查询整个表与查询单个记录之间进行选择:

public class ExampleProvider extends ContentProvider {
      ...
    // Creates a UriMatcher object.
    private static final UriMatcher sUriMatcher;

    sUriMatcher.addURI("com.example.app.provider", "table3", 1);

    sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
    ...
    // Implements ContentProvider.query()
    public Cursor query(Uri uri, String[] projection, String selection, 
                String[] selectionArgs, String sortOrder) {
        ...
        switch (sUriMatcher.match(uri)) {
            // If the incoming URI was for all of table3
            case 1:
                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
                break;
            // If the incoming URI was for a single row
            case 2:
                /*
                 Because this URI was for a single row, the _ID value part is
                 present. Get the last path segment from the URI;
                 this is the _ID value.Then, append the value to the WHERE 
                 clause for the query
                 */
                selection = selection + "_ID = " uri.getLastPathSegment();
                break;

            default:
            ...
                // If the URI is not recognized, you should do some error handling here.
        }
        // call the code to actually do the query
    }
创建ContentProvider

在Android中,如果要创建自己的内容提供者的时候,需要扩展抽象类ContentProvider,并重写其中定义的各种方法。然后在AndroidManifest.xml文件中注册该ContentProvider。

创建ContentProvider的步骤:

  1. 创建一个ContentProvider的子类。
  1. 定义内容Uri
  1. 创建SQLiteOpenHelper的子类,创建一个用于存储内容的数据库。
  1. 在ContentProvider的子类中实现query()、insert()、update()、delete()、getType()、onCreate()方法。
  1. 在AndroidManifest.xml文件中注册自定义的ContentProvider。
    :一般只需要设置两个属性即可访问,一些额外的属性就是为了设置访问权限而存在的:
    android:name:provider的响应类。
    android:authorities:Provider的唯一标识,用于Uri匹配,一般为ContentProvider类的全名。
android contentProvider_第2张图片

在实现ContentProvider的方法时需要注意一下几点:

  • 所有这些方法(onCreate() 除外)都可由多个线程同时调用,因此它们必须是线程安全方法。
  • 避免在 onCreate() 中执行长时间操作。将初始化任务推迟到实际需要时进行。
  • 尽管必须实现这些方法,但代码只需返回要求的数据类型,无需执行任何其他操作。 例如,可能想防止其他应用向某些表插入数据。 要实现此目的,可以忽略 insert() 调用并返回 0。

你可能感兴趣的:(android contentProvider)