当前位置: 代码迷 >> Android >> android Content Provider详解8-实现ContentProvider MIME 类型
  详细解决方案

android Content Provider详解8-实现ContentProvider MIME 类型

热度:478   发布时间:2016-05-01 12:11:15.0
android Content Provider详解八-实现ContentProvider MIME 类型

迎大家加入android技术交流QQ群:209796692)


实现ContentProvider MIME 类型

ContentProvider 有两个方法返回MIME类型。 

getType() 

一个对任何provider都要实现的方法。 

getStreamTypes() 

如果你的provider提供的是文件,此方法是期望被实现的。 

表的MIME类型们

getType()方法返回一个MIME格式的String ,此String描述了由content URI参数计算出的数据类型。Uri 可以是一个模式而不是一个具体的URI;此时,你应该返回对应于那些符合content URI模式的的数据的类型。

对于普通的数据类型,比如文本, HTML或 JPEG,getType()应该返回标准的MIME类型。关于标准MIME类型的一个完整的列表能在IANA MIME Media Types 网站上找到。 

对于指向表数据的一行或多行的content URI们,getType()应返回一个Android vendor-specific MIME 格式: 

· 类型部分:vnd 

· 子类型部分: 

· 如果URI指向单行:android.cursor.item/ 

· 如果URI 指向多行:android.cursor.dir/ 

· Provider-specific 部分:vnd.<name>.<type> 

你要提供 <name> 和 <type><name>的值应是一个全局唯一的,并且<type> 的值对于对应的URI模式也需是唯一的。对<name> 的一个好的选择是用你公司的名字或你的应用的Android包名的一部分。对于<type>的一个好的选择是使用标志与URI相关连的表的字符串。 

例如,如果一个provider的authority是com.example.app.provider,并且它曝露了一个叫做table1的表,那么表示表中多行的MIME类型就是: 

vnd.android.cursor.dir/vnd.com.example.provider.table1

表示单行的MIME类型是: 

vnd.android.cursor.item/vnd.com.example.provider.table1

表示文件的MIME 

如果你的provider提供文件,就要实现getStreamTypes()。这个方法对传入的content URI返回一个由指向文件们的MIME类型组成的String 数组,你应该跟据MIME类型过虑参数过虑MIME 类型们,所以你只返回那些客户端真正相要的MIME类型们。 

例如,假设一个provider提供图像文件,有 .jpg .png,和 .gif类型。如果一个应用使用过滤字符串image/* (表示某些是"image"的东西)调用ContentResolver.getStreamTypes() ,那么ContentProvider.getStreamTypes() 方法应返回数组: 

{ "image/jpeg", "image/png", "image/gif"}

如果应用只对.jpg 文件感兴趣,它应使用过滤字符串 *\/jpeg 调用 ContentResolver.getStreamTypes(),并且 ContentProvider.getStreamTypes()应该返回: 

{"image/jpeg"}

如果你的provider没有提供过滤字符串中所请求的MIME, getStreamTypes() 应返回 null. 

实现一个Contract(契约)类

Contract class是一个public final 类,它包含有定义URI们的常量,列的名字,MIME类型们,以及其它用于provider的元数据。这个类建立了一个provider和其它应用之间的契约以保证在URI、列名等项的值发生变化时依然能被正确的操作。

一个契约类对开发者有帮助,因为它提供了一个好识别的名字,而不用直接使用数字,于是开发者就不会为列名或URI们使用错误的值。因为它是一个类,它就可以包含Javadoc文档。集成开发环境,比如Eclipse可以跟据契约类自动完成常量名并为常量显示Javadoc。 

开发者不能从你的应用操作契约类的类文件,但是他们可以从你提供的.jar文件中静态的把它编译到他们的应用中 。 

ContactsContract 类和它的嵌套类们就是契约类的例子。 

实现Content Provider 权限

对android系统的所有方面的权限在主题Security and Permissions中有详细的描述。主题 Data Storage 中也描术了安全和权限对各种存储类型的影响。简略的说,重要的几点是: 

· 默认下,存储在设备的内部存储器上的数据文件是你的应用和provider私有的。 

· 你创建的SQLiteDatabase 数据库是你的应用和provider私有的。 

· 默认上,保存到外部存储器上的数据文件是公有的和全局可读的。你不能使用一个content provider来限制外部存储上的文件的操作,因为其它应用可以使用其它API 来读写它们。 

· 那些用于在你的设备内部存储器上打开或创建文件或SQLite数据的方法们可能会暗中给予其它应用读写的权限。如果你使用一个内部文件或数据库作为你的provider的数据仓库,并且你给予它们"world-readable" 或"world-writeable" 权限,你在manifest中对你的provider的权限声明将不能保护你的数据。内部存储上的文件和数据库的的默认权限是"private",并且你也不应该改变你的provider的数据仓库的权限。 

如果你想使用content provider 的权限来控制对你的数据的操作,那么你应该存储你的数据到内部文件,SQLite 数据库,或"cloud" (例如,在一个远程服务上),并且你应该保持文件和数据库私属于你的应用。 

实现权限

所有的应用都可以从你的provider读或写你的provider写,即使后台的数据是私有的。因为默认下你的provider 没有权限设置。要改变这种情况,可以在manifest文件中设置你的provider的权限,使用<provider> 元素的属性或其儿子元素。你可以设置应用于整个provider的权限,或只应用于特定表的,或特定记录的,或所有三者的。 

你在manifest文件中用一个或多个<permission> 元素定义你的provider的权限。要使用于你的provider的权限是唯一的,为使用android:name属性使用Java风格的范围限定。例如, 为读权限命名为com.example.app.provider.permission.READ_PROVIDER. 

下面所列的描述说明了provider权限的范围,开始是应用于整个provider的然后变成更细颗粒度。更细颗粒度的权限优先级高于大范围的权限: 

单一的read-write provider-level权限 

一个权限,它控制对整个provider的读和写权限,用<provider> 元素的android:permission 属性指定。 

分开的读和写provider-level权限

控制整个provider的一个读权限和一个写权限。你用<provider> 元素的android:readPermissionandroid:writePermission属性指定它们。它们的优先级比android:permission更高。

Path-level 权限

对你的provider中的content URI的读、写,或读/写权限。你使用<provider> 元素<path-permission> 子元素指定的指定每个URI的权限,你可以指定一个读/写权限,一个读权限,或一个写权限,或所有三者。读和写权限优先级高于读/写权限。并且,path-level权限优先级高于 provider-level权限。

临时权限

也是一个权限级别,它代表了临时获取并赋于一个应用的权限,即使这个应用不具有权限。临时权限特性减少了一个应用需要在其mainifest中声明的权限的数量。当你打开了临时权限,只有那些持续操作你的所有数据的应用们才需要对你的provider有“持久的”权限

考虑一下你实现一个email provider和应用,当你想允许一个外部图像查看应用通过你的provider来显示图像附件时所需的权限。要想不用声明权限就给予图像查看应用所需的权限,就需设置图像的content URI的临时权限。这样设计你的email 应用:当用户想要显示一个图像,你的应用发送一个intent给图像查看应用,这个intent包含了图像的content URI 和权限。图像查看应用之后可以请求你的email provider来获取图像,即使图像查看应用对你的provider不具有普通的读权限。 

要开启临时权限,既可以设置<provider>元素的android:grantUriPermissions 属性,也可以添加一个或多个 <grant-uri-permission> 子元素到你的<provider> 元素。如果你使用临时权限,你必须在从你的provider删除对一个content URI的支持时调用Context.revokeUriPermission() ,如果这个content URI关联了一个临时权限的话。 

属性的值决定了你的provider具有什么操作的可操作性。如果属性被设置为true,那么系统将为你的整个provider获取临时权限,覆盖任何其它通过provider-level或path-level 获取的权限。 

如果这个flag 设置为false, 那么你必须添加<grant-uri-permission> 子元素到你的<provider> 元素上。每个子元素指定了哪个content URI 或哪些URI们授予了临时权限。

要把临时权限委托给一个应用,intent必须包含FLAG_GRANT_READ_URI_PERMISSION 或FLAG_GRANT_WRITE_URI_PERMISSION 标志,或两者都有。它们可用setFlags() 方法设置。 

如果android:grantUriPermissions 属性不存在,就被认为是false。 

  相关解决方案