Android中应用程序之间的数据共享

本文深入探讨了Android应用间数据共享的机制,包括ContentProvider的使用方法及ContentResolver的实现细节,阐述了如何通过ContentProvider对外共享数据以及如何通过统一接口获取其他APP暴露的数据,详细解释了ContentProvider的关键方法如query、insert、delete的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

      如何将应用程序的数据暴露出去?Android提供了一种统一的接口,即ContentProvider,一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Content providers是以类似数据库中表的方式将数据暴露。Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。要想使应用程序的数据公开化,可通过2种方法:创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限。

    如何通过统一的接口获取其他APP暴露的数据呢?Android提供了ContentResolver,APP通过ContentResolver访问ContentProvider中的数据(通过Uri查询数据)。

 

二、ContentProvider的使用

2.1 特点:

a、使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
b、ContentProvider基本不需要用户与它的对象交互,系统会自动唤醒所有注册了的provider;

c、ContentProvider的OnCreate方法,并不是一直被系统调用的<网上好多人是误导,本人亲测,只有你第一次安装该apk的时候才会被调用>

d、ContentProvider通过uri来访问数据;


2.2 使用步骤

a、继承ContentProvider,并重写一些重要的方法:

 
public class PersonContentProvider extends ContentProvider{ public boolean onCreate() public Uri insert(Uri uri, ContentValues values) public int delete(Uri uri, String selection, String[] selectionArgs) public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) public String getType(Uri uri) }

 

b、在AndroidManifest.xml使用<provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider ,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识,你可以把ContentProvider看作是一个网站(想想,网站也是提供数据者),authorities 就是他的域名:

 
< manifest.... > < application android:icon ="@drawable/icon" android:label ="@string/app_name" > < provider android:name =".PersonContentProvider"(需与a中继承的类名一致 android:authorities ="com.ljq.providers.personprovider" /> </ application > </ manifest >

 

c、当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。 ContentResolver 类提供了与ContentProvider类相同签名的四个方法。

 

三、ContentProvider各种方法的重写

3.1 query

    // 查询
    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

        switch (sUriMatcher.match(uri)) {
        // 查询所有
        case TASKS:
            qb.setTables(TASK_LIST_TABLE_NAME);
            qb.setProjectionMap(sTaskListProjectionMap);
            break;
        // 根据ID查询
        case TASK_ID:
            qb.setTables(TASK_LIST_TABLE_NAME);
            qb.setProjectionMap(sTaskListProjectionMap);
            qb.appendWhere(Tasks._ID + "=" + uri.getPathSegments().get(1));
            break;
        default:
            throw new IllegalArgumentException("Uri错误! " + uri);
        }

        // 使用默认排序
        String orderBy;
        if (TextUtils.isEmpty(sortOrder)) {
            orderBy = TaskList.Tasks.DEFAULT_SORT_ORDER;
        } else {
            orderBy = sortOrder;
        }

        // 获得数据库实例
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        // 返回游标集合
        Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
        c.setNotificationUri(getContext().getContentResolver(), uri);
        return c;
    }

 

参数分析:

    uri,查询时传入的uri,它代表了我们要查找的数据源。
    projection,查询时传入的一个字符串数组,通过它来表明我们需要数据表中的哪些row。当查询结束后就会返回包含这些row的结果表。
    selectionArgs,功能不清楚,猜想为表明结果表中各个row的排列顺序。
    sortOrder,表示返回的结果集的排列顺序的语句。

返回值:

       Cursor对象

函数体分析:

        a、SQLiteQueryBuilder:一个用来构造SQL查询语句的辅助类,可以方便的去访问SQLiteDatabase. 在构造SQL查询语句时,它同样也需要指定表名,指定列名,指定where条件。其中的方法使用如下:

              setTables方法设置了它查询工作将要针对的表;

              setProjectionMap方法:不同的uri设置了不同的projection map;

(这个map是对用户查询操作传入的column名和数据表中存在的column名进行了一个映射,这样一来,有些数据库中抽象的表的column名就可以通过这个projection map实现重新命名,以达到方便开发者做一些类似于数据库表联接(join)操作的目的。一般情况下数据库中的表的column名就已经够清晰了,所以你可以不用再在projection map里面做一些column重命名的操作了——也就是说,你可以将这个map对象中的key和value都设为同样的值(接下来的代码会有体现)。)

 

疑问:SQLiteDatabase不是有query吗,为什么要通过SQLiteQueryBuilder来查询呢?SQLiteQueryBuilder能提供什么?

       

         b、UriMatcher类的使用

          首先第一步,初始化:

           private static final UriMatcher sUriMatcher;

          sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);(UriMatcher.NO_MATCH 表示不匹配任何路径的返回码

          第二步注册需要的Uri:

        sUriMatcher.addURI(TaskList.AUTHORITY, "taskLists", TASKS);
        sUriMatcher.addURI(TaskList.AUTHORITY, "taskLists/#", TASK_ID);  (# 号为通配符,* 号为任意字符

          第三部,与已经注册的Uri进行匹配:

          sUriMatcher.match(uri)  (返回TASKS或者TASK_ID)

          match方法匹配后会返回一个匹配码Code,即在使用注册方法addURI时传入的第三个参数。 

 

c、setNotificationUri方法的使用(http://www.myexception.cn/database/487982.html

 

3.2 insert的实现(以SQLiteDatabase.insert和ContentValues为基础,参见SQLiteDatabase知识点)

3.2.1 函数分析

原型:Uri android.content.ContentResolver.insert(Uri url,ContentValues values);
作用:在给定Uri对应的数据表中插入一行。If the content provider supports transactions the insertion will be atomic.

参数:

            Uri url  要插入的表对应的Uri

            ContentValues values   要插入行的内容。The key is the column name for the field。如果内容为空,将创建一个空行。

返回值:创建的新列的Uri。

3.2.2 实现过程

a、检查Uri的有效性(UriMatcher

        if (sUriMatcher.match(uri) != TASKS) {
            throw new IllegalArgumentException("错误的 URI: " + uri);
        }

b、创建ContentValues对象,将参数中传递进来的values传递给该对象

        ContentValues values;
        if (initialValues != null) {
            values = new ContentValues(initialValues);
        } else {
            values = new ContentValues();
        }

c、创建 SQLiteDatabase对象,利用SQLiteDatabase.insert方法插入新行

        // 获得数据库实例
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        // 保存数据返回行ID
        long rowId = db.insert(TASK_LIST_TABLE_NAME, Tasks.CONTENT, values);


d、对返回行ID进行检查,如果插入成功,则返回新行的Uri

        if (rowId > 0) {
            Uri taskUri = ContentUris.withAppendedId(TaskList.Tasks.CONTENT_URI, rowId);
            getContext().getContentResolver().notifyChange(taskUri, null);
            return taskUri;
        }
        throw new SQLException("插入数据失败 " + uri);


疑问:

a、关于监视器的问题还没弄懂,参见

http://www.cnblogs.com/bastard/archive/2012/06/02/2531663.html

http://blog.youkuaiyun.com/xiazdong/article/details/7706977

http://blog.youkuaiyun.com/java2009cgh/article/details/7367940


b、关于异常的使用也没有深入。




3.3 delete的实现

http://blog.sina.com.cn/s/blog_69092aea0101879o.html

http://www.w3school.com.cn/sql/sql_and_or.asp


四、ContentResolver的使用

4.1 概述

4.2 常用方法





 参看资料:

http://blog.youkuaiyun.com/feng88724/article/details/6331396

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值