ContentProvider和Uri详解222
下列关于contentprovider的描述
下列关于contentprovider的描述ContentProvider是Android中重要的组件之一,它提供了数据共享和访问的机制。
本文将对ContentProvider进行详细的描述和解释。
正文ContentProvider是Android中的一个基础组件,用于实现应用程序之间的数据共享和访问。
它充当了数据访问的中间层,使得不同应用程序之间可以安全地共享数据,同时提供了标准化的接口和方法来进行数据操作。
下面是对ContentProvider的描述和解释:1. ContentProvider是用于在Android应用程序之间共享数据的一种机制。
它允许一个应用程序将自己的数据暴露给其他应用程序,同时提供了标准化的接口和方法来访问和操作这些数据。
2. ContentProvider提供了一种数据抽象的方式,使得应用程序可以通过URI来访问数据,而不需要了解数据的具体存储方式和位置。
这种抽象使得数据的存储和访问可以更加灵活和可扩展。
3. ContentProvider通过使用URI来标识和定位数据。
URI是一种统一资源标识符,它可以唯一地标识数据的位置和类型。
应用程序可以使用URI来获取和操作数据,而不需要了解数据的具体存储细节。
4. ContentProvider提供了一套标准化的接口和方法来进行数据操作,包括CRUD操作(创建、读取、更新和删除)。
这使得应用程序可以使用统一的方式来操作不同类型的数据,无论是数据库、文件系统还是网络数据。
5. ContentProvider还提供了数据权限和安全性的控制机制,可以限制其他应用程序对数据的访问权限。
通过在ContentProvider 中实现权限控制,可以确保数据的安全性和隐私。
总结起来,ContentProvider是Android中重要的组件之一,它提供了数据共享和访问的机制,使得不同应用程序之间可以安全地共享数据。
通过使用标准化的接口和方法,应用程序可以统一地访问和操作数据,而不需要了解数据的具体存储方式和位置。
内容提供者ContentProvider的使用详解
内容提供者ContentProvider的使用详解1.什么是ContentProvider首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少。
ContentProvider为不同的软件之间数据共享,提供统一的接口。
也就是说,如果我们想让其他的应用使用我们自己程序内的数据,就可以使用ContentProvider定义一个对外开放的接口,从而使得其他的应用可以使用咱们应用的文件、数据库内存储的信息。
当然,自己开发的应用需要给其他应用共享信息的需求可能比较少见,但是在Android系统中,很多系统自带应用,比如联系人信息,图片库,音频库等应用,为了对其他应用暴露数据,所以就使用了ContentProvider机制。
所以,我们还是要学习ContentProvider的基本使用,在遇到获取联系人信息,图片库,音频库等需求的时候,才能更好的实现功能2.如何定义一个ContentProviderAndroid系统为了让我们更好的对外暴露数据,提供了统一的接口,所以定义了抽象类ContentProvider,因此,如果我们想对外提供数据,我们需要继承ContentProvider,并且实现下面的这几个方法:onCreate()当我们的provider初始化时被调用,我们应该在这个方法里面完成部分初始化操作query() 查询方法,用于给调用者返回数据insert() 插入操作,用于让外部应用插入数据到内容提供者中update() 更新操作,用于更新内容提供者的数据delete() 用于删除数据getType 返回内容提供者的MIME Type上面这些方法,当我们继承自ContentProvider的时候,eclipse 会自动的给我们添加,但是这并不代表我们每个方法都需要自定义实现。
如果我们只希望给其他应用提供数据,而不允许其他应用修改我们的数据,那么我们只需要实现onCreate(),getType()和query()这三个方法就可以了,其他的三个方法我们可以根据业务需求,实现或者是不实现。
简述contentprovider的工作原理
ContentProvider的工作原理什么是ContentProviderContentProvider是Android中的一个组件,用于实现数据共享和数据访问的机制。
它允许一个应用程序将其数据暴露给其他应用程序,从而实现不同应用之间的数据共享和交互。
ContentProvider可以提供对结构化数据的访问,例如数据库中的表格,也可以提供对非结构化数据的访问,例如文件系统中的文件。
ContentProvider的作用ContentProvider主要有以下几个作用:1.数据共享:ContentProvider可以将一个应用程序的数据暴露给其他应用程序,从而实现数据的共享和交互。
其他应用程序可以通过ContentProvider访问和操作这些数据,而无需了解数据的具体存储方式和实现细节。
2.数据访问:ContentProvider提供了一种标准的接口,其他应用程序可以通过这个接口来访问和操作数据。
这样可以实现数据的统一管理,避免了重复的数据访问和操作代码。
3.数据保护:ContentProvider可以对数据进行权限控制,只有具有相应权限的应用程序才能访问和操作数据。
这样可以保护数据的安全性和私密性。
ContentProvider的工作原理ContentProvider的工作原理可以分为以下几个步骤:1. 注册ContentProvider在AndroidManifest.xml文件中,需要为ContentProvider注册一个相应的标签。
这个标签中需要指定ContentProvider的类名、权限等信息。
<providerandroid:name=".MyContentProvider"android:authorities="com.example.myapp.provider"android:exported="true" />2. 实现ContentProvider创建一个类来实现ContentProvider,并重写相应的方法。
4.1---Content Provider与ContentResolver 简介
如何调用系统的Content Provider一、ContentProvider简介我们说Android应用程序的四个核心组件是:Activity、Service、BroadcastReceiver和ContentProvider。
在Android中,应用程序彼此之间相互独立的,它们都运行在自己独立的虚拟机中。
ContentProvider提供了程序之间共享数据的方法,一个程序可以使用ContentProvider定义一个URI,提供统一的操作接口,其他程序可以通过此URI访问指定的数据,进行数据的增、删、改、查。
ContentProvider应该是Android在系统启动时就创建了,否则就谈不上数据共享了。
这就要求在AndroidManifest.XML中使用<provider>元素明确定义。
2. 可能会有多个程序同时通过ContentResolver访问一个ContentProvider,会不会导致像数据库那样的“脏数据”?这个问题一方面需要数据库访问的同步,尤其是数据写入的同步,在AndroidManifest.XML中定义ContentProvider的时候,需要考虑是<provider>元素multiprocess属性的值;另外一方面Android在ContentResolver中提供了notifyChange()接口,在数据改变时会通知其他ContentObserver,这个地方应该使用了观察者模式,在ContentResolver中应该有一些类似register,unregister的接口。
三、使用现成的ContentProvider下面我们就来看看代码,我们是怎么利用到现成的ContentProvider。
packageeoe.android.Demo;importandroid.app.Activity;importandroid.content.ContentResolver;importandroid.content.ContentValues;importandroid.database.Cursor;.Uri;importandroid.os.Bundle;importandroid.provider.ContactsContract;importandroid.view.View;importandroid.view.View.OnClickListener;importandroid.widget.Button;importandroid.widget.Toast;publicclassMainContentProviderextendsActivity{/**Calledwhentheactivityisfirstcreated.*/@OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(yout.main);Buttonb1=(Button)findViewById(R.id.Button01);OnClickListenerocl=newOnClickListener(){@OverridepublicvoidonClick(Viewv){ContentResolvercontentResolver=getContentResolver();//获得所有的联系人Cursorcursor=contentResolver.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);//循环遍历if(cursor.moveToFirst()){intidColumn=cursor.getColumnIndex(ContactsContract.Contacts._ID);intdisplayNameColumn=cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);do{//获得联系人的ID号StringcontactId=cursor.getString(idColumn);//获得联系人姓名StringdisPlayName=cursor.getString(displayNameColumn);Toast.makeText(MainContentProvider.this,"联系人姓名:"+disPlayName,Toast.LENGTH_LONG).show();//查看该联系人有多少个电话号码。
Android数据共享之ContentProvider总结
Content Provider由上一节内容,我们了解到Adroid的数据都是私有的,那么对于像通讯录之类,多个APP(拨号、通话、短消息…)都需要共享使用,该怎么实现呢?答案就是ContentProvider。
概述:ContentProvider是Android平台中,在不同应用程序之间实现数据共享的一种机制。
一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制。
并且此种方式忽略了底层的数据存储实现,ContentProvider提供了一种统一的通过Uri实现数据操作的方式。
Android为常用的数据类型(图片,音视频,通讯录)提供了大量的ContentProvider,它们被定义在android.provider包下面。
操作模型:ContentProvider类:定义在android.content包下面,主要数据存取类,提供了常用的数据操作接口•delete(): 删除数据集•insert():添加数据集•qurey():查询数据集•update():更新数据集•onCreate():初始化底层数据集和建立数据连接等工作•getType():返回指定URI的MIME数据类型,ContentResolver类:ContentProvider是实际操作数据库的方法,客户端通过ContentResolver实现,ContentResolver和ContentProvider提供了对应的方法,诸如insert(), delete(), query()和update()之类的方法。
我们间接的通过ContentResolver的方法来操作ContentProvider。
Uri介绍ContentProvider 通过URI对象共享数据;Uri代表了要操作的数据,Uri主要包含了两部分信息:1》需要操作的ContentProvider2》对ContentProvider中的什么数据进行操作Uri是一个通用资源标志符,将其分为A,B,C,D 4个部分:A:无法改变的标准前缀,包括;"content://"、"tel://"等。
android四大组件--ContentProvider详解
android四大组件--ContentProvider详解一、相关ContentProvider概念解析:1、ContentProvider简介在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences、网络存储、文件存储、外储存储、SQLite。
但是我们知道一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,有时候我们需要操作其他应用程序的一些数据,例如我们需要操作系统里的媒体库、通讯录等,这时我们就可能通过ContentProvider来满足我们的需求了。
2、为什么要选择ContentProvider?ContentProvider向我们提供了我们在应用程序之前共享数据的一种机制,而我们知道每一个应用程序都是运行在不同的应用程序的,数据和文件在不同应用程序之间达到数据的共享不是没有可能,而是显得比较复杂,而正好Android中的ContentProvider则达到了这一需求,比如有时候我们需要操作手机里的联系人,手机里的多媒体等一些信息,我们都可以用到这个ContentProvider来达到我们所需。
1)、ContentProvider为存储和获取数据提供了统一的接口。
ContentProvide 对数据进行封装,不用关心数据存储的细节。
使用表的形式来组织数据。
2)、使用ContentProvider可以在不同的应用程序之间共享数据。
3)、Android为常见的一些数据提供了默认的ContentProvider(包括音频、视频、图片和通讯录等)。
总的来说使用ContentProvider对外共享数据的好处是统一了数据的访问方式。
3、Uri介绍为系统的每一个资源给其一个名字,比方说通话记录。
1)、每一个ContentProvider都拥有一个公共的URI,这个URI用于表示这个ContentProvider所提供的数据。
2)、Android所提供的ContentProvider都存放在android.provider包中。
ContentProvider详解
ContentProvider详解⼏个概念:Cursor、 Content provider 、 Uri 、contentresolver1、Cursor :个⼈理解为数据库中的⼀⾏数据,它是每⾏数据的集合。
它是⼀个类。
通过它的⼀系列⽅法,我们可以对数据库中的每⾏进⾏定位,我们还可以知道每⼀列的信息。
⽐如:cursor(游标).moveToFirst(),表⽰定位到第⼀⾏,然后我们通过其他⽅法可以知道每列的名称,每列的数据类型等。
2、Content Provider :内容提供者,我们⼀个application中的其他类假如想操作数据库中的数据的话,就可以直接对此进⾏操作,⽽避免了对数据库进⾏直接操作,再说了,数据库这些个东西有权限要求的,我们不可能把数据库直接暴露出来,所以,通常采⽤这种形式。
其实他就是⼀个提供数据访问的⽹站,我们要访问它的话,就得知道他的域名。
android:authorities . 在minifest.xml中配置如下:(包含两个部分,name 与 anthorities)<provider android:name=".PersonProvider" android:authorities="com.sharpandroid.providers.personprovider"/>当某个应⽤,可能是外部的,可以通过这两个属性来找到这个Content Provider了。
Content Provider ⽀持在多个应⽤中存储和读取数据。
这也是跨应⽤共享数据的唯⼀⽅式。
在android系统中,没有⼀个公共的内存区域,供多个应⽤共享存储数据。
3、Uri:这个东西就是提供者提供数据的详细地址,到底是哪些数据,⽤此来对数据进⾏过滤操作。
假如说,Content Provider是⼀个DNS,域名的话。
那么Uri可以认为是IP地址,我们通过此IP地址找到我们所需要的数据。
Android四大组件 之ContentProvider
获得系统的CP 的数据
• Android系统中会给应用提供一些开放的系统数据,当然 它是采用CP的这种形式。 • 通过ContentResolver访问系统CP的步骤: – 调用Activity的ContentResolver获取CR对象 – 调用CR中的insert,delete,update,query方法获得系 统CP提供的数据
URI
例如以下是系统的一些 URI: content://media/internal/images (该 URI 返回设备上存储的所有图片)
content://contacts/people/5 (联系人信息中 ID 为 5 的联系人记录)
content://contacts/people (该 URI 返回设备上的所有联系人信息)
• 注意:
– 要获得系统CP提供的数据,必须要了解该CP的Uri。
使用CP 管理联系人
• Android系统中Contacts应用来管理联系人,而且暴露相 应CP。 • 此CP支持的Uri如下: – ContactsContract.Contacts.CONTENT_URI :管理联系 人的Uri – monDataKinds.Phone.CONTENT_ URI:管理联系人的电话的Uri – monDataKinds.Email.CONTENT_ URI:管理联系人的Email的Uri
2)、parseId(uri)//用于从指定uri中解析出所包含的id的值
Uri uri = Uri.parse("content://com.yfz.Lesson/people/10") long personid = ContentUris.parseId(uri); 最后personid 为 :10
通信工程设计与监理《ContentProvider共享数据的方法课件》
简介
A
scheme
URI
B
authority
A
A
host
port
第四页,共七页。
C
path
3获取系统内置和的方法
在取得ContentResolver对 象后,即可调用
ContentResolver类的 query(projection,String
selctioin,String[ ] selectionArgs,String sort()Order)方法从指定的 URI中获取需要的数据。
第五页,共七页。
查询返回的Cursor与类似 在标准SOL查询操作中返 回的结果集。通过它可以 遍历各行各列,取得各个
需要数据值。
谢谢
主讲: 电信系
石家庄邮电职业技术学院
第六页,共七页。
内容总结
目 录。在取得ContentResolver对象后,即可调用ContentResolver类的query(projection,String selctioin,String[ ] selectionArgs,String sort()Order)方法从指定的URI中获取需要的数据。查询返回的Cursor与类似在标准SOL查询操作中返回的结果集。主讲: 电信系
第七页,共七页。
第二页,共七页。
AA
通常客户端不会直接使 用这些方法,而是通过 ContentResolver对象实 现对ContentProvider的
操作。
AB
开发人员可以通过调用 Activity或其他应用程序
组件的 getContentResolver()方
法来获取 ContentResolver对象。
第三页,共七页。
安卓考试知识点总结
内容提供者内容提供者(ContentProvider )是Android 系统四大组件之一,用于保存和检索数据,是Android 系统中不同应用程序之间共享数据的接口。
ContentProvider 是不同应用程序之间进行数据交换的标准API ,以Uri 形式对外提供数据,允许其他应用操作本应用数据。
其他应用则使用ContentResolver ,并根据ContentProvider 提供的Uri 操作指定数据。
A 应用B应用使用ContentProvider暴露的数据ContentResolver通过ContentResolver操作A 应用数据操作暴露的数据返回操作结果返回操作结果数据模型Content Provider 使用基于数据库模型的简单表格来提供其中的数据,这里每行代表一条记录,每列代表特定类型和含义的数据。
例如,联系人的信息可能以如下方式提供:URI 的用法每个Content Provider 提供公共的URI (使用Uri 类包装)来唯一标识其数据集。
管理多个数据集(多个表格)的Content Provider 为每个都提供了单独的URI 。
所有为provider 提供的URI 都以“content://”作为前缀,“content://”模式表示数据由Content Provider 来管理。
A :标准前缀,用来说明一个Content Provider 控制这些数据,无法改变的;B :URI 的标识,它定义了是哪个Content Provider 提供这些数据。
对于第三方应用程序,为了保证URI 标识的唯一性,它必须是一个完整的、小写的 类名。
这个标识在<provider> 元素的 authorities 属性中说明:<provider name=”.TransportationProvider ” authorities=”com.example.transportationprovider ” . . . >C :路径,Content Provider 使用这些路径来确定当前需要生什么类型的数据,URI 中可能不包括路径,也可能包括多个;D :如果URI 中包含,表示需要获取的记录的ID ;如果没有ID ,就表示返回全部; 由于URI 通常比较长,而且有时候容易出错,切难以理解。
ContentProvider与ContentResolver使用
ContentProvider与ContentResolver使用1.什么是ContentProviderContentResolver是数据调用者,ContentProvider将数据发布出来后通过ContentResolver对象结合Uri进行调用。
通过ContentResolver可以调用ContentProvider的增、删、改、查操作。
122.什么是Uri?上面使用ContentResolver需要结合Uri进行调用,那么什么是Uri:通用资源标识符简称URI;Uri代表操作数据的地址,每个ContentProvider发布数据都有一个唯一的地址;Uri格式:content://com.android.app/contacts12343.创建自定义ContentProvide的步骤1.使用SQLine,创建数据库和数据表;2.新建类继承ContentProvider;3.创建UriMatcher定义Uri的规则;4.重写ContentProvider的6个方法;5.在Manifest中注册Provider;6.ContentResolver对ContentProvider共享数据进行操作;1234564.自定义ContentProvider简易例子:首先在一个项目中完成好数据库表的创建;新建一个类继承ContentProvider;并重写ContentProvider的6个方法;在方法中实现数据库增、删、改、查的操作;1234public class Myprovider extends ContentProvider {@Override//重写onCreate方法public boolean onCreate() {dbHelpter = new DBHelpter(getContext(), "demodb", null, 1);Log.e("0000000000","onCreate");return false;}@Nullable@Override//重写query方法、实现查询操作。
android contentprovider原理
android contentprovider原理Android ContentProvider是Android平台上的一项重要技术,它提供了一种统一的数据访问机制,方便不同应用程序之间共享数据。
本文将从 ContentProvider 的定义、工作原理、使用方法等方面来进行一一介绍。
一、ContentProvider的定义ContentProvider是Android平台上用于实现数据共享的一种机制。
ContentProvider负责对外部应用程序的数据进行管理,提供访问数据的统一接口。
使用ContentProvider,应用程序可以访问其他应用程序中的数据,也可以将自己的数据暴露给其他应用程序。
二、ContentProvider的工作原理ContentProvider基于ContentResolver和Cursor的方式来进行数据访问和传输。
ContentProvider提供了一组URI(Uniform Resource Identifier)来标识数据源,而这些URI通过ContentResolver来进行访问,ContentProvider返回的数据被封装成Cursor类型的数据结构进行传输,从而方便外部应用程序的访问。
ContentProvider的工作原理可以概括为以下三个步骤:1. 首先,外部应用程序通过ContentResolver发送请求到ContentProvider,并指定需要访问哪些数据。
2. 接着,ContentProvider解析请求,并查询相应的数据源,将结果封装成Cursor类型并返回给外部应用程序。
3. 最后,外部应用程序通过ContentResolver使用得到的Cursor数据,进行数据操作。
三、ContentProvider的使用方法ContentProvider的使用是围绕着ContentResolver进行的。
在使用ContentProvider时,需要先创建ContentProvider子类,并且需要实现4个方法:1. onCreate():在ContentProvider创建时调用。
content provider详解
内容提供者-Content ProviderContent providers管理对结构化数据集的使用.它们封装数据,并提供了数据安全的机制.Content providers是从一个进程连接另一个进程中的数据的标准接口.当你想使用一个content provider中的数据,你需在你的应用的Context 中使用ContentResolver对象作为客户端与provider 进行通讯.C ontentResolver对象与provider对象通讯,provider是实现ContentProvider的类.Provider对象接收客户端发来的请求,执行请求的动作,返回结果.如果你不想把你的数据共享给其它应用,你不需开发你自己的provider.然而,你需要自己的provider来在你的应用中提供自定义搜索建议.如果你需要从你的应用中考贝复杂的数据或文件粘贴到其它应用中,你也需要提供自己的provider.Android自己包含了管理音频,视频,图像,个人通讯录等数据的content providers.你可以从android.provider 包的参考文档中爪到它们.这些providers 可以被所有的android 应用使用,但可能带有一些限制.Content Provider 基础一个content provider 管理对中央数据仓库的使用.一个provider是一个Android应用的一部分,应用一般提供它自己的UI来操作数据.然而,content providers主要是为了给其它应用使用,其它的应用使用provider客户端对象来操作provider.providers 和provider 客户端一起提供了一致的,标准的接口来操作用于进程间通讯的数据并保处数据的安全性.本节讲解以下基础知识:· content providers如何工作.·从content provider取得数据的API.·向content provider插入,更新以及删除数据的API.·其它有助于使用providers的API.概述一个content provider代表了面向外部应用的数据,这些数据看起来就像关系型数据库中的一个或多个table.一行代表某种数据类型的一个实例,一列代表这个实例的一个属性或字段.举个例子,Android平台中的一个内建的provider是用户词典,它存储了用户想保存的非标准词的拼写.表1 演示了数据在provider的表中可能看起来的样子:Table 1:简单用户词典表在上表中,每行代表了一个不能在标准字典中找到的词.每一列代表了这个词了一个属性.列头是存储在provider中的列的名字.要引用一行的locale属性,需引用locale列.对于这个provider,_ID列作为"主键"列,provider会自动管理它.注:一个provider不是必须具备主键的,并且也不是必须使用_ID作为主键的列名来引用一行.然而,如果你把一个provider绑定到一个ListView,就必须有一个列名叫做_ID.此需求将在显示查询结果一节中有详细的解释.操作一个provider应用使用ContentResolver客户端对象来操作content provider中的数据.此对象具有一些与provider 对象中同名的方法,provider对象指的是某个ContentProvider具体派生类的实例.ContentResolver的方法们提供了对存储数据的基本的"CRUD" (增删改查)功能.ContentResolver对象处于客户端应用的线程中,ContentProvider对象位于另外的进程并且自动处理进程间通讯.ContentProvider也代表了数据层与可视层之间的一个抽象层.注:要使用一个provider,你的应用通常需要在manifest请求一些权限, 这将在Content Provider 权限一节中进行更详细的讲解.举个例子,要从用户词典Provider中获取取单词和它们的locale列表,你需调用ContentResolver.query().query() 方法会调用用户词典中的ContentProvider.query() 方法.下面的代码演示了ContentResolver.query() 调用:// 查询用户词典并返回结果mCursor = getContentResolver().query(UserDictionary.Words.CONTENT_URI, // 单词表的content URImProjection, // 每行要返回的列们mSelectionClause // Selection的条件mSelectionArgs, // Selection的条件mSortOrder); // 返回各行要如何排序表2展示了query(Uri,projection,selection,selectionArgs,sortOrder)的参数们如何与一个SQL SELECT语句匹配:Table 2: Query() 与SQL 查询的对比Content URIscontent URI 是一个标志provider中的数据的URI.Content URI中包含了整个provider的以符号表示的名字(它的authority) 和指向一个表的名字(一个路径).当你调用一个客户端的方法来操作一个provider中的一个表,指向表的content URI是参数之一.常量CONTENT_URI 中包含了用户词典table的content URI.ContentResolver 对象分析出URI的authority,并使用它与一个已知provider组成的系统表中的authority进行对比来"解决"provider.ContentResolver之后就会派送查询参数给正确的 provider.ContentProvider使要长content URI的路径辨别分来选择要操作的表.通常一个provider 中要暴露的每个表都具有一个路径.在上面的例子的代码中,"词典"表的全URI是:content://user_dictionary/wordsuser_dictionary部分是provider的 authority,words部分是表的路径.字符串 content:// (the scheme) 总是要存在,它表示引用一个content URI.很多provider允许你通过在URI的末尾增加一个ID来操作表中一个单独的行.例如,要从用户词典中获取_ID是4的一行,你可要行使用这样的content URI:Uri singleUri = ContentUri.withAppendedId(UserDictionary.Words.CONTENT_URI,4);当你要获取多行然后更新或删除其中一时,你经常要使用的是id值.注:Uri和Uri.Builder类包含由字符串构建格式正确的Uri对象的简便的方法们.ContentUris 包含向一个URI添加id值的简便方法们.上面的小代码片段就是使用了withAppendedId() 来向UserDictionary content URI添加id.从Provider取得data本节讲述了如何从provider取得数据,使用用户词典作为例子.为了清析易懂,本节中调用ContentResolver.query()的代码片断置于"UI 线程"中.但是,在实际代码中,你应该在另一个线程执行查询动作,这样做的一种方法是使用CursorLoader 类.而,那几行示例代码仅是片断,它们不能展示一个完整的应用.要从provider取得data,须依如下步骤:1 请求provider的读权限.2 定义发送请求到provider的代码.请求读权限要从一个provider中获取数据,你的应用需要对目标provider具有"读权限".你不能在运行时请求此权限,而只能在manifest文件中使用<uses-permission>元素指定你的权限需求.当你在manifest中指定此元素时,你实际上就是在为你的应用请求这个权限.当用户安装你的应用时,就表示同意了这个权限请求.要找到你使用的provider读权限的所对应的准确名字,以及其它用于provider的权限的名字,请浏览provider的文档.关于操作provider的权限的角色的更多信息,请见Content Provider权限一节.用户词典Provider在它的manifest 中定义了android.permission.READ_USER_DICTIONARY权限,所以一个想读取它内容的应用必须请求此权限.构建请求获取数据的下一步是构建一个请求(query).这里的第一个代码片段定义了一些用于操作用户词典Provider的变量:// "projection" 定义了要返回的各列们String[]mProjection ={UserDictionary.Words._ID,// Contract class constant for the _ID column name UserDictionary.Words.WORD,// Contract class constant for the word column name UserDictionary.Words.LOCALE // Contract class constant for the locale column name };// 定义一个包含"select"条款的字符串String mSelectionClause =null;// 初始化一个包含"select"参数的字符串String[]mSelectionArgs ={""};下一个代码片段演示了如何使用ContentResolver.query(),将用户词典Provider作为一个例子.一个provider客户端查询极像一个SQL查询,它包含了要返回的一坨column们,一堆筛选条件,和一个排序方式.查询返回的column集合被称作projection (变量mProjection).指定返回的列的语句被分解为选择条款和选择参数两部分.选择条款是逻辑和布尔表达式,列名以及值的组合体(变量mSelection).如果你在其中指定了使用?来代表一个值,查询方法就会从选择参数部分取得这个值(变量mSelectionArgs).在下一个代码片段中,如果用户没有输入单词,选择条款就被设为null,并且查询会反回所provider中所有的单词.如果用户输入了单词,选择条款就被设置为UserDictionary.Words.Word + " = ?"并且选择参数(数组)的第一项被设置为用户输入的单词./** 定义一个一维的字符串数组来容纳选择参数们*/String[]mSelectionArgs ={""};// 从界面中获取一个单词mSearchString =mSearchWord.getText().toString();// 记住要在此插插入代码检查不合法的或恶意的输入.// 如果单词是空的,则获取所有数据if(TextUtils.isEmpty(mSearchString)){// 设置选择条款为null就会返回所有单词mSelectionClause =null;mSelectionArgs[0]="";}else{// 构造一个匹配用户输入的单词的选择条款mSelectionClause =" = ?";// 将用户输入的单词置于选择参数中mSelectionArgs[0]=mSearchString;}// 执行查询并返回游标对象mCursor =getContentResolver().query(UserDictionary.Words.CONTENT_URI,// The content URI of the words table mProjection,// The columns to return for each rowmSelectionClause // Either null, or the word the user enteredmSelectionArgs,// Either empty, or the string the user enteredmSortOrder);// The sort order for the returned rows// 有些provider在出错时返回null,有抛出异常if(null==mCursor){/** 在此插入代码处理错误.记住不要使用游标! 你可能要调用* android.util.Log.e()把错误记录的日志**/// 如果游标是空的,找不到匹配的provider}else if(mCursor.getCount()<1){/** 在此插入代码来通知用户,查找不成功.这也不能完全算是个错误.你可能想为用户提供插入一个新行或重新输入查询单词的选项*/}else{// 在此插入代码,利用返回的结果做想做的事}查询与下面的SQL语句等价:SELECT _ID,word,frequency,locale FROM words WHERE word =<userinput>ORDER BY word ASC;在此SQL 语句中,以实际的列名代替了内置的类别常量.防止恶意输入如果被content provider管理的数据是一个SQL 数据库,在原始的SQL语句中包含不可信的数据会导致SQL注入.思考以下选择条款:// 通过连接用户输入到列名来构造一个选择条款String mSelectionClause ="var = "+mUserInput;如果你这样做,你就允许用户连接恶意的SQL语句到你的SQL语句中.例如,用户可以输入"nothing; DROP TABLE *;" ,这将在选择条款中变为var = nothing; DROP TABLE *;..既然选择条款被作为SQL语句,这就可能导致provider删除SQLite数据库中的所有的表(除非provider被设置成捕获SQL injection阴谋).要避免此问题,应使用一个运用?作为可替换参数的选择条款和一个作为选择参数的数组.当你这样做时,用户输入被直接绑定到查询而不是被解释为SQL语句的一部分.因为它不被认为是SQL,于是用户输入就不能注入恶意SQL.使用以下选择条款来代替连接用户输入的那个:// 构造一个带有占位符的选择条款String mSelectionClause ="var = ?";像这样建立起选择参数数组:// 定义一个数组来容纳选择参数String[]selectionArgs ={""};像这样把一个值置入选择参数数组中:// Sets the selection argument to the user's inputselectionArgs[0]=mUserInput;一个使用?作为占位符的选择条款+一个选择参数数组是指定一个选择器的最佳方式,即使provider不是基于SQL数据库的.显示查询结果客户端方法ContentResolver.query()总是返回一个包含所查询的列们的Cursor.一个Cursor对象提供了随机的读取它所包含的行和列的能力.使用Cursor的方法们,你可以迭代结果中的行,决定每列的数据类型,从列获得数据,以及检测结果的其它属性.一些Cursor的实现会在provider的数据改变时自动更新,或在Cursor改变时触发监听者的方法,或者两者都支持.注:一个provider可能跟据构建查询的对象的性质限制对某些列的操作.例如,联系人Provider会禁止同步适配器操作某些列,所以它不会把它们返回给一个activity或service.如果没有符合选择条件的行,provider返回一个Cursor对象,其Cursor.getCount()为0 (一个空cursor).如果一个内部错误发生,查询结果会因provider的不同而不同.它可能返回null,也可能抛出一个Exception.既然一个Cursor是行组成的"列表",那么一个和显示Cursor内容的好方法就是把它链接到一个ListView上,通过SimpleCursorAdapter.下面的代码片段是衔接前面的代码来的.它创建一个SimpleCursorAdapter对象,包含有查询返回的Cursor,然后设置这个对象为ListView的适配器.// 定义要从Cursor取出的并要加载到view中的列们String[]mWordListColumns ={UserDictionary.Words.WORD,// Contract class constant containing the word column nameUserDictionary.Words.LOCALE // Contract class constant containing the locale colum n name};// 定义一个View ID组成的列表,它们将接收每行的Cursor列的值int[]mWordListItems ={R.id.dictWord,R.id.locale};// Creates a new SimpleCursorAdaptermCursorAdapter =new SimpleCursorAdapter(getApplicationContext(),// The application's Context objectyout.wordlistrow,// ListView的一行的layoutmCursor,// The result from the querymWordListColumns,// A string array of column names in the cursormWordListItems,// An integer array of view IDs in the row layout0);// Flags (usually none are needed)// 将适配器设置给ListViewmWordList.setAdapter(mCursorAdapter);注:要使Cursor支持ListView,cursor必须包含一个叫做_ID的列,因此,上面所示的查询从"单词"表中取出了_ID,当然ListView可以不显示它.这条限制同时也解释了为毛大多数provider在它们的表中都具有一个_ID列.从查询结果中获取数据你可以使用查询结果做更多是事情,而不是仅简单地显示它们.比如,你可以从用户词典中获取拼法然后在其它provider中查找它们.要这样做,你需在Cursor中迭代所有的行.// 获取叫做"word"的列的序号int index =mCursor.getColumnIndex(UserDictionary.Words.WORD);/** 仅在cursor有效时执行下面语句.如果发生内部错误,用户词典Provider返回null. * 其它provider可能抛出一个异常而不是返回null.*/if(mCursor !=null){/** 移到cursor中的下一行.在第一次移动之前,* "行指针" 为-1,并且,如果你想获取那个位置的数据,你将得到一个异常*/while(mCursor.moveToNext()){// 从列中获取值.newWord =mCursor.getString(index);// 在此插入代码处理获取到的单词...// 循环结束}}else{// 如果cursor为null或前面抛出了异常,在处插入代码报告错误.}Cursor的实现包含了多个"get" 方法,用于从对象中获取不同类型的数据.例如,前面的代码片段使用getString().它们也具有一个getType()方法,用它可以返回的值代表了数据的类型.Content Provider的权限一个具有provider的应用可以指定其它要操作自己的数据所应具有的权限.这些权限保证了用户能了解一个应用将要操作那个数据.其它应用需基于provider的需求请求相应的权限.用户在安装应用时会看到它们所请求的权限.如果一个provider的应用没有指定任务权限,那么其它应用就不能操作provider的数据.然而,provider所在的应用的组件们却具有完整的读写权限,而不管是否指定了权限.如上面所提到的,用户词典Provider需要android.permission.READ_USER_DICTIONARY 权限来从它取得数据.Provider具有另一个android.permission.WRITE_USER_DICTIONARY权限,代表了插入,更新或删除的权限.要获取操作一个provider的权限,应用需在自己的manifest文件中使用<uses-permission>元素.当Android包管理器安装这个应用时,用必须批准所有的权限请求.如果用户批准了所有的权限请求,包管理器会继续安装这个应用;如果没有,包管理器就会取消安装过程.下面的<uses-permission>元素请求对用户词典的读权限:<uses-permission android:name="android.permission.READ_USER_DICTIONARY"> Provider操作权限的作用在指南安全和权限一节中有详细的描述.插入更新删除数据用从provider取得数据相同的方法,你也可以让provider 客户端与provider的ContentProvider以交互方式修改数据.你调用个ContentResolver的方法,其参数是要传给ContentProvider对应方法的.Provider与provider客户端自动处理安全问题和进程间通信问题.插入数据要向一个provider中插入数据,需调用ContentResolver.insert()方法.此方法插入一个新行到provider中并且返回一个代表这一行的content URI.下面的代码片段演示了如何将一个新行插入到用户词典中:// 定义一个新的Uri对象,用于接收插入后的返回值Uri mNewUri;...// 定义一个对象来包含要插入的值们ContentValues mNewValues = new ContentValues();/** 设置要插入行的每列的值."put"方法的参数是"column name"和"value"*/mNewValues.put(UserDictionary.Words.APP_ID, "er");mNewValues.put(UserDictionary.Words.LOCALE, "en_US");mNewValues.put(UserDictionary.Words.WORD, "insert");mNewValues.put(UserDictionary.Words.FREQUENCY, "100");mNewUri = getContentResolver().insert(UserDictionary.Word.CONTENT_URI, // 用户词典的content URImNewValues // 要插入的值们);新行的数据被置入一个ContentValues对象,就像构建一个单行cursor.对象中的列们不必都是相同的数据类型,并且如果你不想指定某列的值,你可以设置一个列为null ,使用ContentValues.putNull().此代码片段中没有添加_ID 列,因为此列是被自动维护的.Provider会为每个添加的新行分配一个唯一的_ID 值.Provider总是把它用作表的主键.返回的content URI newUri 代表了新添加的行,以下面的形式:content://user_dictionary/words/<id_value><id_value> 是新行的 _ID 的值.大多数可以自动检测content URI 的格式然后执行对此行的请求的操作.要从返回的Uri,获得_ID 的值,调用ContentUris.parseId().更新数据要更新一行,你可以使用一个ContentValues对象,向它填充要更新的值,就像你插入时做的,并且选择条件跟查询时是一样的.你应使用的客户端方法是ContentResolver.update().你只需把要更新的列的值添加到ContentValues对象.如果你想去清空一列的内容,设置其值为null.下面的片段改变所有语言列中带有"en"的行,把其locale置为null.返回值表明了多少行被更新:// 定义一个对象包含要更新的数据ContentValues mUpdateValues = new ContentValues();// 为要更新的行们定义选择条款String mSelectionClause = UserDictionary.Words.LOCALE + "LIKE ?";String[] mSelectionArgs = {"en_%"};// 定义一个变量存放更新的行的数量.int mRowsUpdated = 0;.../** 设置更新的值并且更新选择的单词*/mUpdateValues.putNull(UserDictionary.Words.LOCALE);mRowsUpdated = getContentResolver().update(UserDictionary.Words.CONTENT_URI, // the user dictionary content URImUpdateValues // the columns to updatemSelectionClause // the column to select onmSelectionArgs // the value to compare to);删除数据删除行与获取行的方式相似:你为想要更新的行指定选择条款,然后客户端方法就会返回被删除的行数.下面的代码片段删除那些appid等于"user"的行们.返回被删除的行数.// 定义要删除的行们的选择条款String mSelectionClause = UserDictionary.Words.APP_ID + " LIKE ?";String[] mSelectionArgs = {"user"};// 定义一个存放删除的行数的变量int mRowsDeleted = 0;...// 删除那些符合选择条款的单词们mRowsDeleted = getContentResolver().delete(UserDictionary.Words.CONTENT_URI, // the user dictionary content URImSelectionClause // the column to select onmSelectionArgs // the value to compare to);。
ContentProvider内容提供者
一;ContentProvider:内容提供者,用来存储数据。
二:数据库存储方式:文件存储,共享参数存储,数据库存储,和内容提供者。
三:基本概念:1:内容提供者作为Android四大组件之一;2:使用ContentProvider:可以再不同的应用程序之间共享数据,当然也可以在当前应用程序共享数据。
3:为存储数据和获取数据提供统一的接口。
也就是说,无论数据的存储方式如何,只需要调用该接口即可。
内容提供者的作用作为中间的桥梁,作为一个接口,如果想访问数据,直接访问内容提供者即可。
4:内容提供者中的数据更改可以被监听5:Android中常见的ContentProvider存储数据:通讯录,图片,音频,视频。
四:常用方法1:onCreate();返回值是boolean:该方法在ContentProvider:创建的时候调用。
2:insert(Uri uri, ContentValues values):返回值是URL:添加数据参数:路径,values添加的数据存放在values3:delete(Uri uri, String selection, String[] selectionArgs):返回值是Int,作用是添加数据参数:路径,删除的条件,4:update(Uri uri, ContentValues values, String selection, String[] selectionArgs):返回值是Int,更新ContentProvider中的数据参数:路径,更新的数据存放在values5:query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):返回值是Cursor:获取数据的方法参数:projection:列名,selectionArgs条件sortOrder排序方式6:getType(Uri uri):返回值是String:该方法用于返回当前URL所代表的数据的MIME类型五:URL:统一资源定位符,Universal Resource Indentifier,代表要操作的内容提供者的数据路径1:组成部分:scheme,authoriters,path,三部分组成,分别代表:协议,域名,路径例如一个网站:http协议,域名,路径。
一起学Android之ContentProvider
一起学Android之ContentProvider本文主要讲解在Android开发中ContentProvider的常规用法,仅供学习分享使用,如有不足之处,还请指正。
访问一个ContentProvider在Android开发中,应用程序通过ContentResolver(内容解析器)从ContentProvider(内容提供者)中获取数据,ContentResolver提供访问ContentProvider中同名方法,ContentProvider包括ContentProvider和它的子类,ContentResolver对ContentProvider的持久层存储提供了基本的CRUD (Create,Retrieve,Update,Delete)方法进行访问。
客户端App的ContentResolver对象自动处理和ContentProvider的App之间的进程间通信。
ContentProvider还充当数据库和外部数据视图表现之间的抽象层。
备注:如果要访问一个ContentProvider,App需要在清单文件中请求对应的权限。
例如:从User Dictionary Provider中获取单词和区域的列表,可以调用ContentResolver.query()方法,如下图所示:1 // 查询用户定义字典并返回结果2 mCursor = getContentResolver().query(3 UserDictionary.Words.CONTENT_URI, // 单词表的内容URI4 mProjection, // 查询的数据列名数组5 mSelectionClause //查询条件,可以为null6 mSelectionArgs, // 查询参数,可以为null7 mSortOrder); // 返回数据对象的排序条件下表显示了query(Uri,projection,selection,selectionArgs,sortOrder) 如何与SQL语句进行匹配:Content URIsContent URI是Provider中标识数据的URI,包括整个Provider (其权限)的符号名和指向表(或路径)的名称,Content URI是访问ContentProvider的参数之一。
Android中ContentProvider和ContentResolver详解
Android中ContentProvider和ContentResolver详解Android中ContentProvider和ContentResolver详解在Android中,我们的应⽤有的时候需要对外提供数据接⼝,可以有如下⼏种⽅法:1)AIDL 2)Broadcast 3)ContentProvider。
使⽤AIDL需要我们编写AIDL接⼝以及实现,⽽且对⽅也要有相应的接⼝描述,有点⿇烦;使⽤Broadcast,我们不需要任何接⼝描述,只要协议⽂档就可以了,但是有点不好就是,这种⽅式不直接⽽且是异步的;使⽤ContentProvider我们不需要接⼝描述,只需要知道协议,同时这种⽅式是同步的,使⽤⽅便。
下⾯是ContentProvider实现:package com.backgroundservice;import android.content.ContentProvider;import android.content.ContentValues;import android.content.UriMatcher;import android.database.Cursor;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteQueryBuilder;import .Uri;import android.util.Log;/*** TODO** @author zengpeng* @version 1.0 Create At : 2010-3-18 下午02:52:40*/public class TestContentProvider extends ContentProvider {private SQLiteDatabase mDb;private DatabaseHelper mDbHelper = null;private static final String DATABASE_NAME = "rssitems.db";private static final String DATABASE_TABLE_NAME = "rssItems";private static final int DB_VERSION = 1;private static final int ALL_MESSAGES = 1;private static final int SPECIFIC_MESSAGE = 2;// Set up our URL matchers to help us determine what an// incoming URI parameter is.private static final UriMatcher URI_MATCHER;static {URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);URI_MATCHER.addURI("test", "item", ALL_MESSAGES);URI_MATCHER.addURI("test", "item/#", SPECIFIC_MESSAGE);}// Here's the public URI used to query for RSS items.public static final Uri CONTENT_URI = Uri.parse("content://test/item");// Here are our column name constants, used to query for field values.public static final String ID = "_id";public static final String NAME = "NAME";public static final String VALUE = "VALUE";public static final String DEFAULT_SORT_ORDER = ID + " DESC";private static class DatabaseHelper extends AbstractDatabaseHelper {@Overrideprotected String[] createDBTables() {// TODO Auto-generated method stubString sql = "CREATE TABLE " + DATABASE_TABLE_NAME + "(" + ID+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + NAME + " TEXT,"+ VALUE + " TEXT);";return new String[] { sql };}@Overrideprotected String[] dropDBTables() {// TODO Auto-generated method stubreturn null;}@Overrideprotected String getDatabaseName() {// TODO Auto-generated method stubreturn DATABASE_NAME;}@Overrideprotected int getDatabaseVersion() {// TODO Auto-generated method stubreturn DB_VERSION;}@Overrideprotected String getTag() {// TODO Auto-generated method stubreturn TestContentProvider.class.getSimpleName(); }}/****/public TestContentProvider() {// TODO Auto-generated constructor stub}/** (non-Javadoc)** @see android.content.ContentProvider#delete(.Uri,* ng.String, ng.String[])*/@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {// NOTE Argument checking code omitted. Check your parameters!int rowCount = mDb.delete(DATABASE_TABLE_NAME, selection, selectionArgs); // Notify any listeners and return the deleted row count.getContext().getContentResolver().notifyChange(uri, null);return rowCount;}/** (non-Javadoc)** @see android.content.ContentProvider#getType(.Uri)*/@Overridepublic String getType(Uri uri) {switch (URI_MATCHER.match(uri)) {case ALL_MESSAGES:return "vnd.android.cursor.dir/rssitem"; // List of items.case SPECIFIC_MESSAGE:return "vnd.android.cursor.item/rssitem"; // Specific item.default:return null;}}/** (non-Javadoc)** @see android.content.ContentProvider#insert(.Uri,* android.content.ContentValues)*/@Overridepublic Uri insert(Uri uri, ContentValues values) {// NOTE Argument checking code omitted. Check your parameters! Check that// your row addition request succeeded!long rowId = -1;rowId = mDb.insert(DATABASE_TABLE_NAME, NAME, values);Uri newUri = Uri.withAppendedPath(CONTENT_URI, ""+rowId);Log.i("TestContentProvider", "saved a record " + rowId + " " + newUri); // Notify any listeners and return the URI of the new row.getContext().getContentResolver().notifyChange(CONTENT_URI, null); return newUri;}/** (non-Javadoc)** @see android.content.ContentProvider#onCreate()*/@Overridepublic boolean onCreate() {// TODO Auto-generated method stubtry{mDbHelper = new DatabaseHelper();mDbHelper.open(getContext());mDb = mDbHelper.getMDb();}catch(Exception e){e.printStackTrace();}return true;}/** (non-Javadoc)** @see android.content.ContentProvider#query(.Uri,* ng.String[], ng.String, ng.String[],* ng.String)*/public Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {// We won't bother checking the validity of params here, but you should! // SQLiteQueryBuilder is the helper class that creates the// proper SQL syntax for us.SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();// Set the table we're querying.qBuilder.setTables(DATABASE_TABLE_NAME);// If the query ends in a specific record number, we're// being asked for a specific record, so set the// WHERE clause in our query.if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){qBuilder.appendWhere("_id=" + uri.getLastPathSegment());Log.i("TestContentProvider", "_id=" + uri.getLastPathSegment());}// Make the query.Cursor c = qBuilder.query(mDb,projection,selection,selectionArgs,null,null,sortOrder);Log.i("TestContentProvider", "get records");c.setNotificationUri(getContext().getContentResolver(), uri);return c;}/** (non-Javadoc)** @see android.content.ContentProvider#update(.Uri,* android.content.ContentValues, ng.String, ng.String[])*/@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {// NOTE Argument checking code omitted. Check your parameters!int updateCount = mDb.update(DATABASE_TABLE_NAME, values, selection, selectionArgs);// Notify any listeners and return the updated row count.getContext().getContentResolver().notifyChange(uri, null);return updateCount;}}配⽂件如下:<provider android:name="TestContentProvider"android:authorities="test"></provider>在客户端中可以使⽤如下⽅法进⾏调⽤:ContentValues values = new ContentValues();values.put(, "testname1");values.put(TestContentProvider.VALUE, "testvalu1e");Uri newAddUri = TestActivity.this.getContentResolver().insert(TestContentProvider.CONTENT_URI, values);Cursor c = TestActivity.this.managedQuery(newAddUri, new String[]{}, null, null, null);Log.i("TestActivity", "" + c.getCount());if(c.moveToNext()){Log.i("TestActivity", c.getString(0));}上⾯的代码是先进⾏插⼊,然后进⾏查询并打印。
ContentProvider深入解析
}
} Biblioteka 这几句话,首先创建了一个IActivityManager.ContentProviderHolder,这个是怎么创建的?他是个什么东西?我们先看看ActivityManagerNative.getDefault()是怎么返回IActivityManager的
首先去获取一下,看看是不是这个IContentProvider已经存在,存在就直接返回,不存在,就去创造一个,也就是
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContentProvider(
Uri createdRow = provider.insert(url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
}
try {
ActivityManagerNative.getDefault().removeContentProvider(
getApplicationThread(), name);
@Override
protected IContentProvider acquireProvider(Context context, String name) {
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/s/blog_49f62c350101hhhl.html
Android四大组件是Activity, Service, Content Provider, Broadcast Receiver。
Activity作为程序界面,直接与用户交互
Service运行在后台,没有界面,完成特定的功能
ContentProvider维护应用数据,方便应用本身或其它应用访问
Broadcast Receiver提供异步广播消息接收机制,便于各应用/组件进行交互
通过AndroidManifest.xml, 可以看到一个应用使用了哪些组件:
attribute的定义可以参考
/guide/topics/manifest/manifest-intro.html 下面重点探讨Content Provider的实现和使用。
二.什么是ContentProvider
Content Provider维护特定的应用数据,并可以让其它应用轻松访问该数据。
对数据使
用者来说它是数据提供者。
它提供统一的接口对数据进行操作,使用者不用关心数据到底是如何存储的以及数据类型到底是什么。
也就是说,Content Provider作为数据提供者,提供了对外共享本地数据一种机制,使Android应用能方便地基于该机制进行数据访问。
为了便于管理和访问,每个Content Provider必须有唯一标示,用Uri表示。
Uri 类似http url, 构成如下:
content://authority/path
所有Content Provider的Uri必须以content://开头,这是Android规定的。
authority是个字符串,它由开发者自己定义,用于来唯一标示一个ContentProvider。
系统会根据这个标示查找ContentProvider。
path也是字符串,表示要操作的数据。
可根据自己的实现逻辑来指定:content://contacts/people表示要操作ContentProvider为contacts下的people表content://com.android.contacts/people/#表示要操作表people中特定id的行(记录)。
content://downloads/download/10/name表示要操作id为10的行的name字段。
content://downloads/download/*表示操作download表中的所有字段。
总之,#匹配一个数字字符串,*匹配一个文本字符串。
可以看出, 实现一个自定义的Content Provider,要基于系统提供的基类ContentProvider,需要实现6个接口。
大部分接口就是类似数据库的数据操作接口,实际上Content Provider是需要创建数据库并对数据库进行操作的。
完成实现之后,在
Androidmanifest.xml中声明自己的Content Provider以及与Provider相关的permission 声明(可以没有permission定义)。
例如:
使用非常简单,Android提供了Context级别的ContentResolver对象来对Content Provider 进行操作。
正是因为有了ContentResolver,使用者才不用关心Provider到底是哪个应用或哪个类实现的。
只要知道它的uri就能访问。
ContentResolver对象存在于每个Context 中。
几乎所有对象都有自己的Context。
四.ContentProvider内部机制
1.ContentProvider接口调用过程
ContentProvider依赖
ContentResolver/ActivityThread/ActivityManagerService对外提供
服务。
虽然ContentProvider的用法以及表现形式不是一个Service,实际上它可以看作是ActivityManagerService提供的一种服务, 它实现了IBinder接口。
首先调用者通过特定uri调用特定ContentProvider的接口函数,比如
insert(), 此时ContentResolver会通过uri获取特定ContentProvider的实例,ActivityThread检查本地Cache,如果发现此ContentProvider已经被引用过,则直接直接取出ContentProvider返回给调用者。
如果没有发现,由于ContentProvider可能已经被load了,可能还没有load;可能要创建Process,可能要检查permission,所以ActivityThread调用到ActivityManagerService来进行相关处理/检查。
如果该Provider 是Single Process,ActivityManagerService会为ContentProvider创建一个独立Process;如果是MultiProcess,说明每个调用者可以拥有独立的ContentProvider实例,于是ActivityManagerService只是返回ContentProvider的相关信息给ActivityThread,由ActivityThread负责ContentProvider的实例化,此时ContentProvider运行在调用者Process中。
实例化后,IConentProvider会返回给调用者,通过该接口可以调用所需功能。
ActivityThread本地维护一个mProviderMap <ProviderName, ProviderRecord >,记录已被引用的ContentProvider, 同时使用引用计数mProviderRefCountMap <IBinder, ProviderRefCount>记录特定ContentProvider的引用情况。
2.ContentProvider实例创建过程
ContentProvider实例的创建与multiprocess属性有关系(Androidmanifest.xml里指定),个人认为理解成多进程并不准确。
应该理解为ContentProvider的多实例,不会存在多个ContentProvider进程的情况,ContentProvider 可能存在多个实例。
1)对于android:multiprocess=true的ContentProvider,意味着可以多实例,那么由调用者在自己的进程空间实例化一个ContentProvider对象,此时定义
ContentProvider的App可能并没有启动。