Android的数据(包括files, database等...)都是属于应用程序自身,其他程序无法直接进行操作。
因此,为了使其他程序能够操作数据,在Android中,可以通过做成 ContentProvider提供数据操作的接口。其实对应用而言,也可以将底层数据封装成ContentProvider,这样可以有效的屏蔽底层操作的细节,并且是程序保持良好的扩展性和开放性。
ContentProvider,顾名思义,就是数据内容的供应者。在Android中它是一个数据源,屏蔽了具体底层数据源的细节,在ContentProvider内部你可以用Android支持的任何手段进行数据的存储和操作,可能比较常用的方式是基于Android的SQLite数据库(恩,文档中和示例代码都是以此为例)。无论如何,ContentProvider是一个重要的数据源,可以预见无论是使用和定制ContentProvider都会很多。于是花了点时间仔细看了看。
数据库操作
从我目前掌握的知识来看,SQLite比较轻量(没有存储过程之类的繁杂手段),用起来也比较简单。实例化一个SQLiteDatabase类对象,通过它的APIs可以搞定大部分的操作。从sample中看,Android中对db的使用有一种比较简单的模式,即派生一个 ContentProviderDatabaseHelper类来进行SQLiteDatabase对象实例的获取工作。基本上, ContentProviderDatabaseHelper类扮演了一个singleton的角色,提供单一的实例化入口点,并屏蔽了数据库创建、打开升级等细节。在ContentProvider中只需要调用ContentProviderDatabaseHelper的openDatabase方法获取SQLiteDatabase的实例就好,而不需要进行数据库状态的判断。
URI
像进行数据库操作需要用SQL一样,对ContentProivder进行增删改查等操作都是通过一种特定模式的URI来进行的
(ig:content: //provider/item/id),URI的能力与URL类似,具体细节可以查看SDK。建立自己的ContentProvider,只需要派生 ContentProivder类并实现insert, delete, update等抽象函数即可。
在这些接口中比较特殊的是getType(uri)。根据传入的uri,该方法按照MIME格式返回一个字符串唯一标识该uri的类型。所谓uri的类型,就是描述这个uri所进行的操作的种类,比如content://xx/a与 content://xx/a/1不是一个类型(前者是多值操作,后者是单值),但content://xx/a/1和content://xx/a/2 就会是一个类型(只是id号不同而已)。
在ContentProvider通常都会实例化一个ContentURIPraser来辅助解析和操作传入的URI。你需要事先(在static域内)为该ContentURIPraser建立一个uri的语法树,之后就可以简单调用 ContentURIPraser类的相关方法进行uri类型判断(match方法),获取加载在uri中的参数等操作。
增删改查
ContentProvider 和所有数据源一样,向外提供增删改查操作接口,这些都是基于uri的指令。
进行insert操作的时候,你需要传入一个uri和 ContentValues。uri的作用基本就限于指明增减条目的类型(从数据库层面来看就是table名),ContentValues是一个 key/value表的封装,提供方便的API进行插入数据类型和数据值的设置和获取。在数据库层面上来看,这应该是column name与value的对应。但为了屏蔽ContentProvider用户涉及到具体数据库的细节,在Android的示例中,用了一个小小的模式。它为每一个表建一个基于BaseColumn类的派生类(其实完全可以不派生自BaseColumn,特别当你的表不基于默认的自动id做主键的时候),这个类通常包括一个描述该表的ContentURI对象和形如
public static final TITLE = "title" 这样的column到类数据的对应。从改变上角度来看,你可以修改column的名字而不需要更改用户上层代码,增加了灵活性。
insert方法如果成功会返回一个uri,该uri会在原有的uri基础上增加有一个row id。对于为什么使用row id而不是key id我想破了脑袋。因为ContentProvider不一定需要使用数据库,使用数据库对应的表也可以没有主键,只有row id,才能在任何底层介质下做索引标识。
但,基于row id在删除和修改操作是会造成一定的混乱。删除和修改操作类似。删除操作需要传入一个uri,一个where字串,一组where的参数(做条件判定...),而修改操作会多一个ContentValues做更新值。着两个操作的uri都支持在末尾添加一个row id。于是混乱就出现了。当在where参数中指明了key id,而在uri中提供了row id,并且row id和key id所指函数不一致的时候,你听谁的?示例代码中的做法是完全无视row id(无语...),
我看了下上层对 ContentProvider的删除操作,其实都不会直接进行,而是通过调用Cursor的delete方法进行,在这前提下,我想Cursor会处理好这些东西吧。
最后一个操作是查询操作,可以想见,查询的参数是最多的,包括uri和一组条件参数。条件参数类型和标准的sql类似,包括 sort, projection 之类的。从这些参数到sql语句的生成,可以寻求QueryBuilder类的帮助,它提供了一组操作接口,简化了参数到sql的生成工作,哪怕你不懂 sql都完全没有问题,查询返回一个Cursor。Cursor是一个支持随机读写的指针,不仅如此,它还提供了方便的删除和修改的API,是上层对ContentProvider进行操作一个重要对象,需要仔细掌握(Cursor还可以绑定到view上,直接送显,并与用户进行交互,真是程序越往上,封装越好,工作越机械没有复杂性了...)。
数据模型
在与界面打交道的Cursor、ContentResolver等数据操作层中,大量采用观察者模式建立数据层与显示层的联系。一个显示层的视图,可以做成某一种观察者注册到Cursor或ContentResolver等数据中间层中,在实现底层ContentProvider中,我们需要特别注意在对数据进行修改操作(包括增删改...)后,调用相应类型的notify函数,帮助表层对象进行刷新(还有一种刷新方式是从一个view发起的)。可以看到 Android的整体数据显示框架有点像MVC的方式(贫瘠了...叫不出名)。Cursor、ContentResolver相当于控制层,数据层和显示层的交互通过控制层来掌管,而且控制层很稳定不需要特别定制,通常工作只在定制数据层和显示层空间,还是比较方便和清晰的。
分享到:
相关推荐
ContentProvider的数据模型通常是基于SQLite数据库,但并不限于此。它可以用任何方式存储和操作数据,例如文件系统、网络资源等。在ContentProvider内部,开发者通常会使用SQLite数据库来管理数据,因为SQLite是一个...
1. 创建数据模型:定义数据结构,通常使用SQLite数据库存储数据。 2. 创建数据库辅助类:如SQLiteOpenHelper,用于数据库的创建、升级等操作。 3. 实现ContentProvider类:覆盖其中的关键方法,如query()、insert()...
1. 创建数据模型:首先,你需要定义你的数据模型,这通常是一个简单的Java类,包含了你需要共享的数据字段。 2. 创建ContentProvider类:继承自android.content.ContentProvider,并实现其关键方法: - onCreate()...
3. **ContentContract**:定义数据模型和操作接口,包括常量(如表名、列名)以及公开的Uri常量,有助于提高代码可读性。 4. **SQLite数据库**:通常,ContentProvider会与SQLite数据库配合,将数据存储在本地。...
1. **定义Contract类**:首先,你需要定义一个Contract类,用于声明ContentProvider对外暴露的数据模型和URI。在这个类中,通常会包含常量,定义数据表名、列名以及对应的URI。 2. **继承ContentProvider**:然后...
在JFace Viewer中,数据模型是通过ContentProvider和LabelProvider来定义的。ContentProvider负责提供视图中的数据项,而LabelProvider则负责将数据项转换为可视化的表示,如文本或图像。这两者共同定义了数据如何被...
Content Provider基于数据库模型,通过简单的表格结构来存储数据。每个表的行代表一条记录,列则表示特定类型和含义的数据。例如,一个简单的联系人表可能包括`_ID`(唯一标识符)、`NAME`(姓名)、`NUMBER`(电话号码)...
三、联系人数据模型 1. RawContacts:代表单一的联系人源,如Google账户或SIM卡。 2. Data:存储具体的数据项,如名字、电话号码、电子邮件地址,每个数据项关联一个RawContacts。 3. Contacts:表示用户看到的联系...
开发者可以根据自己的数据模型定制ContentProvider,实现对自定义数据源的支持。 七、SuggestionsAdapter和SuggestionsProvider SuggestionsAdapter负责将查询结果适配为ListView显示,而SuggestionsProvider则是...
4. 数据模型类:定义媒体数据的实体类,如MediaItem,用于数据的封装和解析。 五、学习MediaProviderSample的意义 通过MediaProviderSample,开发者可以深入理解ContentProvider的机制,掌握如何与系统服务交互,...
5. **处理结果**:在`onPerformSync()`中,开发者需要实现数据的下载、上传和本地存储逻辑,完成后更新ContentProvider中的数据。 四、SyncAdapter的优势 1. **后台运行**:SyncAdapter在单独的进程中运行,不会...
1. **模型(Model)**:在Android中,模型通常包括数据实体类(如Parcelable或Serializable对象)以及访问数据的类,如ContentProvider、SQLite数据库、网络API接口等。模型类不依赖于Android框架,确保了数据处理的...
2. 数据模型:为了存储日记条目,开发者通常会创建一个数据模型类,如`DiaryEntry`,它包含日记的标题、内容、日期等属性,并提供getter和setter方法。 3. ContentProvider:为了与其他应用共享数据或者遵循Android...
2. **Content Provider**:示例可能包含一个自定义的ContentProvider,用于管理同步的数据模型。 3. **Authentication Service**:如果需要用户登录,SampleSyncAdapter会包含一个实现了AccountAuthenticator接口的...
新的存储模型引入了媒体库的概念,应用可以通过ContentProvider访问公共文件,而不是直接操作文件系统。 四、案例分析 根据提供的文件夹名"Day02_store_2(外置sdcard)",这可能是一个关于在Android设备外部存储...
在Android平台上,开发者需要了解Android的组件模型,如Activity、Service、BroadcastReceiver和ContentProvider,以及如何使用XML布局文件创建用户界面。此外,还要掌握Java或Kotlin编程语言,并熟悉Android SDK、...
Binder驱动使用Client/Server模型实现进程间的通信,且只进行一次数据拷贝,大大提高了进程间通信的效率。Ashmem是一个使用文件描述符描述的内存管理子系统,通过Binder在进程间传递,有助于更高效地管理共享内存。 ...
在这个项目中,Adapter被用来将数据模型与视图组件关联,实现列表项的动态加载和滚动效果。 六、图片加载库 考虑到性能和用户体验,源码可能使用了 Glide 或 Picasso 图片加载库,它们能优化图片的加载和显示,...