博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android学习笔记37:使用Content Providers方式共享数据
阅读量:6083 次
发布时间:2019-06-20

本文共 7176 字,大约阅读时间需要 23 分钟。

  在Android中一共提供了5种数据存储方式,分别为:

  (1)Files:通过FileInputStream和FileOutputStream对文件进行操作。具体使用方法可以参阅博文《》。

  (2)Shared Preferences:常用来存储键值对形式的数据,对系统配置信息进行保存。具体使用方法可以参阅博文《》。

  (3)Content Providers:数据共享,用于应用程序之间数据的访问。

  (4)SQLite:Android自带的轻量级关系型数据库,支持SQL语言,用来存储大量的数据,并且能够对数据进行使用、更新、维护等操作。具体使用方法可以参阅博文《》。

  (5)Network:通过网络来存储和获取数据。

  本篇博文介绍第三种方式,通过Content Providers实现应用程序之间的数据共享。

 

1.Content Providers简介

  在Android系统中,不存在一个公共的数据存储区供所有的应用程序访问,也就是说数据在各个应用程序中是私有的。那么,如何在一个应用程序中访问另一个应用程序中的数据,实现应用程序之间的数据共享呢?

  当然,你可以通过《Android学习笔记34:使用文件存储数据》一文中讲到的设置openFileOutput()方法中的第二个参数mode为Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE,让别的应用程序可以读写该应用程序中的文件。但是,使用这种方式的弊端也是显而易见的,不仅需要知道该文件的存储路径,而且会将该文件内容完全的暴露出去,对于内容提供者和内容访问者来说都是不方便和不安全的。

  为此,Android系统提供了Content Providers,用以方便安全的实现应用程序间的数据共享。

1.1ContentResolver

  所有的Content Providers都会实现一些共同的接口,包括数据的查询、添加、更改和删除。在应用程序中,我们可以通过使用getContentResolver()方法来取得一个ContentResolver对象,然后就可以通过这个ContentResolver对象来操作你需要的Content Provider了。ContentResolver类提供的用来操作Content Provider的方法主要有insert()、delete()、update()和query()。

  通常,对于开发者而言,并不需要同Content Provider对象直接打交道。系统运行时,会将所有的ContentProvider对象实例化,对于每一种类型的ContentProvider只有一个实例。这个实例可以与在不同的程序或进程中的多个ContentResolver对象进行通信。而这些进程间的交互则是由ContentResolver和ContentProvider类进行处理的。

  对于Content Providers而言,最重要的就是数据存储结构和URI。

1.2数据存储结构

  Content Providers将其存储的数据以数据表的形式提供给访问者,在数据表中,每一行为一条记录,每一列为具有特定类型和意义的数据。比如,联系人的Content Provider数据存储结构如图1所示。

图1 Content Provider数据存储结构示例

  可以看出,每条记录都有一个_ID字段用来唯一的标识该记录,类似于数据库中的主键。

1.3URI

  每一个Content Provider都对外提供一个能够唯一标识自己数据集的公开URI,如果一个Content Provider管理多个数据集,则需要为每一个数据集都分配一个独立的URI。

  Android规定,所有Content Provider的URI都必须以“content://”开头。通常,URI由3部分组成:“content://”、数据的路径、标识ID(可选)。

  比如,以下是系统提供的一些URI:

  (1)content://media/internal/images

  (2)content://contacts/people/2

  (3)content://contacts/people

  其中,(1)将返回设备上存储的所有图片;(2)将返回联系人信息中ID为5的联系人记录;(3)将返回设备上所有的联系人信息。

  每个ContentResolver对象都将URI作为其第一个参数,URI决定了ContentResolver将与哪一个Content Provider对话。

 

2.获取Content Provider内容

  Android系统为一些常见的数据类型(如音频、视频、图像、通讯录联系人等)内置了一系列的Content Provider。以下就以通讯录联系人为例,讲讲如何获取Content Provider内容。

  首先,我们需要在模拟器中运行“联系人”应用程序程序,并在其中添加联系人。如图2所示。

图2 添加联系人

  如图2所示,我在“联系人”应用程序程序中添加了两个联系人:李明和王磊。

  然后,我们需要创建一个自己的工程,该工程的主要功能就是得到持有联系人信息的Content Provider中的数据。这里,我在布局文件中定义了一个TextView控件,用来将获得的联系人数据显示出来,运行后的效果如图3所示。

图3 获取Content Provider内容

  由图3可以看出,我们自己创建的应用程序确实从“联系人”应用程序程序中获得了数据(ID和Name字段),当然,如果你需要,你可以获取图1中的更多的字段信息。

  下面的代码给出了实现这一功能的一种方案。

1     /* 2      * Function  :    获取联系人列表信息 3      * Author    :    博客园-依旧淡然 4      */ 5     public String getResult() { 6          7         String result = ""; 8         Uri uri = Uri.parse("content://contacts/people");        //联系人Content Provider的URI 9         String[] columns = {People._ID, People.NAME};            //联系人的ID和Name10         11         ContentResolver contentResolver = getContentResolver();     //获取ContentResolver对象12         Cursor cursor = contentResolver.query(uri, columns, null, null, null);    //查询Content Provider13             int peopleId = cursor.getColumnIndex(People._ID);       //获得ID字段的列索引14             int peopleName = cursor.getColumnIndex(People.NAME);    //获得Name字段的列索引15             16         //遍历Cursor对象,提取数据17         for(cursor.moveToFirst(); (!cursor.isAfterLast()); cursor.moveToNext()) {18             result = result + cursor.getString(peopleId) + "\t\t";19             result = result + cursor.getString(peopleName) + "\t\n";20         }21         cursor.close();22         return result;23     }

  通过以上的代码可以看出,要获取Content Provider内容,我们需要知道Content Provider的URI以及Content Provider的数据存储形式(字段名称和字段类型)。然后,我们便可以通过使用ContentResolver对象的query()方法对Content Provider进行查询了,查询的结果需要使用Cursor对象存储(有关Cursor的介绍可以参阅《Android学习笔记36:使用SQLite方式存储数据》一文)。最后遍历Cursor对象,取出各个字段的信息即可。

  因为该应用程序需要访问联系人信息,所以还需要在AndroidManifest.xml文件中加入相应的权限许可,具体如下:

  

  至此,我们便完成了获取联系人Content Provider内容的功能。

 

3.提供Content Provider内容

  上面介绍了如何从别的应用程序中获取Content Provider内容,那么如何在自己的应用程序中提供Content Provider内容供别的应用程序访问呢?

  一般来说,让自己的数据被别的应用程序访问有两种方式:创建自己的Content Provider(即继承自Content Provider的子类),或者是将自己的数据加入到已有的Content Provider中去。将自己的数据加入到已有的Content Provider中去有一定的局限性,因为要保证自己的数据和现有的Content Provider数据类型相同,并且具有该Content Provider的写入权限。

  下面将说说如何创建一个自己的Content Provider,大致可以分为3个步骤。

3.1建立数据的存储系统

  很显然,要将自己应用程序中的数据共享给他人,肯定需要建立自己的数据存储系统。当然了,选择什么样的存储系统(文件存储系统、SQLite数据库等)完全由开发者决定。

  在《Android学习笔记36:使用SQLite方式存储数据》一文中,我们搭建了一个简单的SQLite数据库系统。在该数据库中,我们新建了一张具有3个字段(studentId、studentName、studentAge)的表,用来存储学生信息。

  这里,我们就以该工程为例,讲讲如何将该工程中的学生信息通过Content Provider方式共享出去。

3.2扩展Content Provider类

  在该工程中,我们需要新建了一个继承自ContentProvider的类。用来将要共享的数据进行包装并以ContentResolver对象和Cursor对象能够访问的形式对外展示。这里,我将这个类命名为了“StudentContentProvider”。

  在ContentProvider类中提供了6个抽象方法,分别为:

  (1)public abstract Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);

  (2)public abstract Uri insert (Uri uri, ContentValues values);

  (3)public abstract int update (Uri uri, ContentValues values, String selection, String[] selectionArgs);

  (4)public abstract int delete (Uri uri, String selection, String[] selectionArgs);

  (5)public abstract String getType (Uri uri);

  (6)public abstract boolean onCreate ();

  其中,query()方法用于将查询到的数据以Cursor对象的形式返回;insert()方法用于向Content Provider中插入新数据记录,该方法中的第二个参数ContentValues对象表示数据记录的列名和列值的映射;update()方法用于更新Content Provider中的已存在的数据记录;delete()方法用于从Content Provider中删除数据记录;getType()方法用于返回Content Provider中数据的(MIME)类型;onCreate()方法当Content Provider启动时被调用。

  以上的6个方法将会在ContentResolver对象中被调用,所以很好的实现这些抽象方法就会为ContentResolver提供一个完善的外部接口。

  当然了,你可以根据自己应用程序的需要,有选择的实现上述6个方法,比如,你可以只实现query()方法,这样别的应用程序就自能对你提供的Content Provider进行查询操作,而无法对你提供的Content Provider进行添加、删除等操作,从而保证了数据的安全性。

  如下的代码实现了query()方法。

1     /*2      * Function  :    查询方法3      * Author    :    博客园-依旧淡然4      */5     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {6         db = mySQLiteOpenHelper.getWritableDatabase();7         Cursor cursor = db.query("tab_student", projection, selection, selectionArgs, null, null, sortOrder);8         return cursor;9     }

  可以看出,查询的核心其实还是调用SQLiteDatabase类提供的query()方法,将查询到的结果存储在Cursor对象中,最后直接将Cursor对象返回即可。

  此外,在继承自ContentProvider类的“StudentContentProvider”中,我们还需要做一件很重要的事,那就是指定Content Provider的URI。该URI必须是唯一的,不能和系统的URI相同,更不能与其他应用程序提供的Content Provider的URI相同。

  这里我定义了Content Provider的URI为“content://com.example.sqlite.studentProvider/student”。

3.3声明Content Provider的权限

  创建好的Content Provider必须在应用程序的AndroidManifest.xml文件中进行声明,否则,该Content Provider对于Android系统是不可见的。

  具体的声明方式如下:

1     
2
4

  其中,<provider></provider>标签位于<application></application>标签下。android:name属性用于指明StudentContentProvider的全称类名,android:authorities属性唯一的标识了一个Content Provider。

  至此,我们便在该工程中创建了自己的Content Provider,并提供了query()方法供别的应用程序查询该工程中的SQLite数据表。

3.4验证

  在应用程序Android_DataStorage_SQLite的SQLite数据表中,我们添加了3条记录,如图4所示。

图4 SQLite数据表信息

  新建一个应用程序Android_DataStorage_ContentProviders,用来获取自定义的Content Provider内容。获取自定义的Content Provider内容的方法,和前面讲的获取联系人应用程序的Content Provider内容的方法类似。使用自定义的Content Provider的URI,并查询数据表中相应的字段即可。可以看到查询到的信息如图5所示。

图5 查询自定义的Content Provider内容

  可以看出,在应用程序Android_DataStorage_ContentProviders中确实访问到了应用程序Android_DataStorage_SQLite中的数据表信息,通过Content Provider方式实现了数据在应用程序之间的共享。

转载地址:http://gxzwa.baihongyu.com/

你可能感兴趣的文章
First Show
查看>>
选择排序(C语言实现) 分类: 数据结构 2015-...
查看>>
通过ADB查看当前Activity
查看>>
[模板] 各种并查集
查看>>
oracle表空间查看增加等操作
查看>>
windows Phone Push Notification
查看>>
EntityFramework6 in github
查看>>
bootstrap table处理后台返回的数据
查看>>
(译)Windsor入门教程---第一部分 获取Windsor
查看>>
Jquery实现图片轮播效果
查看>>
hibernate中懒加载和及加载的区别
查看>>
八皇后问题 思路
查看>>
[POI2018]Plan metra
查看>>
陶哲轩实分析 命题7.4.3 (级数的重排) 证明
查看>>
机器学习_线性回归
查看>>
Swift(一)简单值
查看>>
20172304 2018-2019-1 《程序设计与数据结构》课程总结
查看>>
(剑指Offer)------二进制中1的个数
查看>>
[转载]AxureRP使用参考建议
查看>>
[转载]版本发布模式有几种?
查看>>