在Android 应用程序之间数据共享—-ContentResolver中,已经说明了Android是如何实现应用程序之间数据共享的,并详细解析了如何获取其他应用 程序共享的数据。ContentProviders存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。那么如何 将应用程序的数据暴露出去?
        通过以前文章的学习,知道ContentResolver是通过ContentProvider来获取其他与应用程序共享的数据,那么ContentResolver与ContentProvider的接口应该差不多的。
其中ContentProvider负责
组织应用程序的数据;
向其他应用程序提供数据;
ContentResolver则负责
获取ContentProvider提供的数据;
修改/添加/删除更新数据等;
ContentProvider 是如何向外界提供数据的?
       Android提供了ContentProvider,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProviders是以类似数据库
表的方式将数据暴露,也就是说ContentProvider就像一个“数据库”。那么外界获取其提供的数据,也就应该与从数据库中获取数据的操作基本一
样,只不过是采用URI来表示外界需要访问的“数据库”。至于如何从URI中识别出外界需要的是哪个“数据库”,这就是Android底层需要做的事情
了,不在此详细说。简要分析下ContentProvider向外界提供数据操作的接口:
query(Uri, String[], String, String[], String)
insert(Uri, ContentValues)
update(Uri, ContentValues, String, String[])
delete(Uri, String, String[])
       这些操作与数据库的操作基本上完全一样,在此不详细说,具体的解析可以参考Android Sqlite解析篇中的详细说明。需要特殊说明的地方是URI:

在URI的D部分可能包含一个_ID
,这个应该出现在SQL语句中的,可以以种特殊的方式出现,这就要求我们在提供数据的时候,需要来额外关注这个特殊的信息。Android 
SDK推荐的方法是:在提供数据表字段中包含一个ID,在创建表时INTEGER PRIMARY KEY AUTOINCREMENT标识此ID字段。
ContentProvider 是如何组织数据的?
组织数据主要包括:存储数据,读取数据,以数据库的方式暴露数据。数据的存储需要根据设计的需求,选择合适的存储结构,首选数据库,当然也可以选择本地其
他文件,甚至可以是网络上的数据。数据的读取,以数据库的方式暴露数据这就要求,无论数据是如何存储的,数据最后必须以数据的方式访问。
可能还有2个问题,是需要关注的。
ContentProvider是什么时候创建的,是谁创建的?访问某个应用程序共享的数据,是否需要启动这个应用程序?这个问题在Android
SDK中没有明确说明,但是从数据共享的角度出发,ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。
这就要求在AndroidManifest.XML中使用<provider>元素明确定义。
可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面
需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时候,需要考虑
是<provider>元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了
notifyChange()接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在
ContentResolver中应该有一些类似register,unregister的接口。
Android是如何实现应用程序之间数据共享的?我们以前谈到外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据,今天我们来谈下如何创建自己的ContentProvider来实现应用程序之间的数据共享。

一个应用程序可以创建自己的数据,这个数据对该应用程序来说是私有的,外界更本看不到,也不知道数据是如何
存储的,或者是使用数据库还是使用文件,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和这个程序里的数据打交道,例
如:添加(insert)、删除(delete)、查询(query)、修改(update)。

Android为我们提供了ContentProvider来实现数据的共享,一个程序如果想让别的程序可以操作自己的数据,就定义自己的
ContentProvider,然后在AndroidManifest.xml中注册,其他application可以通过获取
ContentResolver通过Uri来操作上一程序的数据。

Android中的电话本等数据就是通过ContentProvider实现数据共享的,系统中有很多已经存在的共享Uri。我们可以使用
ContentResolver通过Uri来操作不同表的数据;如Contacts.People.CONTENT_URI。

查询Content Provider的方法有两个:ContentResolver的query() 和 Activity 对象的
managedQuery(),二者接收的参数均相同,返回的都是Cursor 对象,唯一不同的是 使用managedQuery
方法可以让Activity 来管理 Cursor 的生命周期。
    被管理的Cursor 会在 Activity进入暂停状态的时候调用自己的 deactivate
方法自行卸载,而在Activity回到运行状态时会调用自己的requery
方法重新查询生成的Cursor对象。如果一个未被管理的Cursor对象想被Activity管理,可以调用Activity的
startManagingCursor方法来实现。
 
什么是URI?

将其分为A,B,C,D 4个部分:

A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;"content://"

B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它     
必须是一个完整的、小写的 类名。这个标识在 元素的
authorities属性中说明:一般是定义该ContentProvider的包.      类的名称
;"content://com.android.calendar" (系统日历的URI)

C:路径,URI下的某一个Item,就像网站一样,主网页下包含很多小网页。这里通俗的讲就是你要操作的数据库中表的名     
字,或者你也可以自己定义,记得在使用的时候保持一致就ok了;"content://com.android.calendar/calendars"

D:如果URI中包含表示需要获取的记录的ID;则就返回该id对应的数据,如果没有ID,就表示返回全
部;                           
"content://com.android.calendar/calendars/#" #表示数据id(#代表任意数字)
     "content://com.android.calendar/calendars/*" *来匹配任意文本
 
UriMatcher:用于匹配Uri,它的用法如下:

1.首先把你需要匹配Uri路径全部给注册上。
        1.常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
UriMatcher                                       uriMatcher = new
UriMatcher(UriMatcher.NO_MATCH);
        2.如果match()方法匹content://com.android.calendar/calendars路径,返回匹配码为1
       uriMatcher.addURI(“content://com.android.calendar”, “calendars”, 1);
        3.添加需要匹配uri,如果匹配就会返回匹配码 //如果match()方法匹配
  
content://com.android.calendar/calendars/23路径,返回匹配码为2
uriMatcher.addURI(“content://com.android.calendar”, “calendars/#”, 2);
 
      2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹
配就返回匹配码,匹配码是调用 addURI()方法传入的第三个参数,假设匹配
content://com.android.calendar/calendars路径,返回的匹配码为1。
       ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
withAppendedId(uri, id)用于为路径加上ID部分
parseId(uri)方法用于从路径中获取ID部分
 
以下是一个例子的简单说明:
 
Xml代码 
<?xml version="1.0" encoding="utf-8"?> 
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
    android:versionCode="1" android:versionName="1.0" 
    android:installLocation="internalOnly" package="com.calendarwidget"> 
 
    <application android:icon="@drawable/icon" android:label="@string/app_name"> 
                <!-- 告诉系统,你的应用程序有provider组件 --> 
        <provider android:name=".CalendarProvider" 
            android:authorities="com.calendarwidget.provider" 
        /> 
             
    </application> 
    <uses-permission android:name="android.permission.READ_CALENDAR" /> 
    <uses-permission android:name="android.permission.WRITE_CALENDAR" /> 
</manifest> 
 public class CalendarProvider extends ContentProvider
Java代码 

 
    private static final String URI_AUTHORITY = "com.calendarwidget.provider"; 
     
    public static final String URI_PATH = "RecordSet"; //只是填充,没有作用 
    public static final String URI_PATH2 = "RecordSet/#";//只是填充,没有作用 
     
    public static final Uri CONTENT_URI = Uri.parse("content://" 
            + URI_AUTHORITY + "/" + URI_PATH); 
     
    private static final UriMatcher sMatcher; 
     
    public static final int ALL_EVENT_RECORDS = 0; 
     
    static 
    { 
        sMatcher = new UriMatcher(UriMatcher.NO_MATCH); 
        sMatcher.addURI(URI_AUTHORITY, URI_PATH, ALL_EVENT_RECORDS); 
        sMatcher.addURI(URI_AUTHORITY, URI_PATH2, ALL_EVENT_RECORDS); 
    } 
     
    private Context mContext; 
     
    @Override 
    public boolean onCreate() 
    { 
        if (mContext == null) 
        { 
            mContext = getContext(); 
        } 
        return true; 
    } 
     
    @Override 
    public Cursor query(Uri uri, String[] projection, String selection, 
            String[] selectionArgs, String sortOrder) 
    { 
        //匹配码 
                int match = sMatcher.match(uri); 
        Cursor cur = null; 
        switch (match) 
        { 
            case ALL_EVENT_RECORDS: 
                cur = loadAllCalendarEvent(this); 
                break; 
             
            default: 
                break; 
        } 
        return cur; 
    } 
     
    private MatrixCursor loadAllCalendarEvent(CalendarProvider calendarProvider) 
    { 
        MatrixCursor mc = new MatrixCursor(CalendarConstants.PROJECTION); 
        Cursor calendarCursor = null; 
        try 
        { 
            calendarCursor = calendarProvider 
                    .getContext() 
                    .getContentResolver().query("content://com.android.calendar/calendars", 
                            null, null,  
                            null, null); / 
             
            while (calendarCursor.moveToNext()) 
            { 
                 
                    //TODO 
                                ..... 
                mc.addRow(rowObject); 
            } 
            return mc; 
        } finally 
        { 
            calendarCursor.close(); 
        } 
    } 
     
    @Override 
    public String getType(Uri uri) 
    { 
        return null; 
    } 
     
    @Override 
    public Uri insert(Uri uri, ContentValues values) 
    { 
        return null; 
    } 
     
    @Override 
    public int delete(Uri uri, String selection, String[] selectionArgs) 
    { 
        return 0; 
    } 
     
    @Override 
    public int update(Uri uri, ContentValues values, String selection, 
            String[] selectionArgs) 
    { 
        return 0; 
    } 

 
    关于getType使用提示:
 
   <intent-filter android:label="@string/resolve_edit">
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.EDIT" />
                <action android:name="com.android.notepad.action.EDIT_NOTE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
    </intent-filter>
 
     
我們很容易看出action和category是很容易匹配的,而我們傳的Uri的數據怎麼匹配呢,這時系統就會去調用你定義的
ContentProvider中的getType,取得相關的返回值來和上面的data串進行匹配,當然getType的返回結果你是需要自己去定義
的。
但在程序中你也可以自己知道data的類型,就直接匹配了:intent.setType(type);

Android ContentResolver的更多相关文章

  1. android ContentResolver详解

    查询出来的cursor的初始位置是指向第一条记录的前一个位置的cursor.moveToFirst()指向查询结果的第一个位置.一般通过判断cursor.moveToFirst()的值为true或fa ...

  2. android播放器如何获取音乐文件信息

    转http://blog.csdn.net/hellofeiya/article/details/8464356, android自带的音乐播放器中,在获取音乐文件信息的时候是通过扫描得到相关信息的. ...

  3. Android:联系人Contacts之ContentResolver query 参数详解

    注:本片整理自 http://blog.csdn.net/wssiqi/article/details/8132603 1.获取联系人姓名 一个简单的例子,这个函数获取设备上所有的联系人ID和联系人N ...

  4. Android 创建内容提供器(ContentResolver)

    如果想实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承 ContentResolver 的方式来创建一个自己的内容提供器. ContentProvider 类中有六 ...

  5. android利用ContentResolver访问者获取手机联系人信息

    转载自:http://www.jb51.net/article/106379.htm 首先需要在AndroidManifest.xml文件中添加权限: <uses-permission andr ...

  6. [ 原创 ]学习笔记-Android 学习笔记 Contacts (一)ContentResolver query 参数详解 [转载]

    此博文转载自:http://blog.csdn.net/wssiqi/article/details/8132603 1.获取联系人姓名 一个简单的例子,这个函数获取设备上所有的联系人ID和联系人NA ...

  7. [Android] Content provider, ContentResolver

    Content provider的作用: Content providers manage access to a structured set of data. They encapsulate t ...

  8. Android ContentProvider、ContentResolver和ContentObserver的使用

    1.ContentProvider.ContentResolver和ContentObserver ContentProvider是Android的四大组件之中的一个,可见它在Android中的作用非 ...

  9. Android中的UriMatcher、ContentUrist和ContentResolver

    因为Uri代表了要操作的数据,所以我们很经常需要解析Uri,并从Uri中获取数据.Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris .掌握它们的 ...

随机推荐

  1. oracle中的内连接和外连接区别

    表t_user1,t_user2,t_user3,各有id,name两列 id name 1 10A 2 20A id name 1 10B 3 30B id name 1 10C 4 40C 连接分 ...

  2. Python 数据类型:列表

    一.列表介绍 1. 列表可以存储一系列的值,使用中括号来定义,每个元素之间用逗号隔开,形如 ['a', 'b', 'c', 'd']2. 列表与元组的区别是:列表中的元素是可变的,元组中的元素是不可变 ...

  3. 图片上传根据stream生成image

    对于图片上传代码的整合 因为需要判断上传的图片的宽高是否符合尺寸,所以在最初拿到inputstream的时候,就直接获取image格式的图片 本来是想在下面的checkFile中获取的,不过直接使用S ...

  4. Android之ListView分页数据加载

    1.效果如下: 实例如下:  上图的添加数据按钮可以换成一个进度条  因为没有数据所以我加了一个按钮添加到数据库用于测试:一般在服务器拉去数据需要一定的时间,所以可以弄个进度条来提示用户: 点击加载按 ...

  5. java Log4j封装,程序任何位置调用

    一般写log4j,每个类都会定义一个logger 明显这样太麻烦了, 然后封装了一下,明显好用多了. package tools; import java.io.IOException; import ...

  6. 国内linux 镜像

    北京理工大学开源软件镜像服务mirrors.ustc.edu.cn 开源中国社区软件镜像下载资源库mirrors.oss.org.cn 阿里云开源镜像站mirrors.aliyun.com<ig ...

  7. JS-点和中括号

    今天上午做一个很low的小练习,代码写完了想要封装重复利用来着 可是憋屈啊,怎么都不对,在document.style.width这里,想把width变成参数可是用点的话,会报错说找不到点后边这个属性 ...

  8. 使用commons-email解析 eml文件

    在对eml文件进行索引的时候需要先对其进行解析,提取出其中的收件人.发件人.文件内容和附件等信息 下边是解析eml文件的一个demo(在运行之前需要先导入mail.jar 和commons-email ...

  9. 微软官方:SELECT语句逻辑处理顺序

    以下步骤显示SELECT 语句的逻辑处理顺序或绑定顺序.此顺序确定在一个步骤中定义的对象何时可用于后续步骤中的子句. 例如,如果查询处理器可以绑定到(访问)在FROM 子句中定义的表或视图,则这些对象 ...

  10. apache+tomcat实现session共享

    apache+tomcat上篇文章,实现了负载均衡,现在我们实现session共享 一.tomcat集群配置,session 同步配置: tomcat1配置  A.修改Engine节点信息: < ...