第四章 ContentProvider(精通Android3 )

REST和SOAP


表征状态转移(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。

        目前在三种主流的Web服务实现方案中,因为REST模式的Web服务与复杂的SOAPXML-RPC对比来讲明显的更加简洁,越来越多的web服务开始采用REST风格设计和实现。

        需要注意的是,REST是设计风格而不是标准。REST通常基于使用HTTPURI,和XML以及HTML这些现有的广泛流行的协议和标准。

    • 资源是由URI来指定。
    • 对资源的操作包括获取、修改、创建和删除资源,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。
    • 通过操作资源的表现形式来操作资源。
    • 资源的表现形式则是XML或者HTML,取决于读者是机器还是人,是消费web服务的客户软件还是web浏览器。当然也可以是任何其他的格式。
 
简单对象访问协议SOAP,全写为Simple Object Access Protocol
        是交换数据的一种协议规范,使用在计算机网络Web服务(web service)中,交换带结构信息。SOAP为了简化网页服务器(Web Server)从XML数据库中提取数据时,节省去格式化页面时间,以及不同应用程序之间按照HTTP通信协议,遵从XML格式执行资料互换,使其抽象于语言实现、平台和硬件。
        简单对象访问协议(SOAP)是一种轻量的、简单的、基于 XML 的协议,它被设计成在 WEB 上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议( HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还支持从消息系统到远程过程调用(RPC)等大量的应用程序
 
 
sqlite3 命令行

Note:adb的提示符为#,sqlite3的提示符为sqlite>

adb shell                 进入到shell
ls -R /data/data/*/databases                   列出所有*.db文件:
sqlite3              进入到sqlite3
.exit                退出sqlite3
.tables              列出数据库中的所有表
.schema people       contacts.db的people表的create语句
.help                帮助
 
 
 
ContentProvider的架构

        设备上的每个ContentProvider都会使用字符串注册自身,这个字符串类似于域名,但称为授权(authority)。这个可唯一标识的字符串是此ContentProvider可提供的一组URI的基础,授权的注册在AndroidManifest.xml中时进行。
     标识NotePadProvider数据库中的笔记目录或集合的URI为:
         content://com.android.provider.NotePad/Notes
     标识具体笔记的URI为:
         content://com.android.provider.NotePad/Notes(其中#是特定的笔记的id)
 
1.Android内容URI的结构
    从ContentProvider中获取的数据是由Android Cursor 对象表示的一些行和列的集合,Android中的内容URI具有以下通用形式:
    content://authority-name/path-segmetl/path-segmet2/etc...
    
    以 content://com.android.provider.NotePad/Notes/23为例
  • content:之后,该URI包含授权的唯一标识符,该标识符用于在提供程序注册表中定位ContentProvider,在示例中com.android.provider.NotePad是URI的授权部分
  • /Notes/23是URI中特定于每个ContentProvider的路径部分,路径中的Notes和23称为路径片段。对URI的路径部分和路径片段部分的记录和解释由ContentProvider负责。通常路径的第一部分可以指向一个对象集合,/Notes标识一个笔记集合或目录,而/23指向特定的笔记
    
2.Android MIME类型的结构
    就像网站返回给定URL的MIME类型一样(这使浏览器能够调用正确的程序来查看内容),ContentProvider还负责返回给定URI的MIME类型。这使用户能够灵活地查看数据。知道数据的类型之后,可能有多个程序知道如何处理该数据。例如,如果在硬盘上有一个文本文件,那么许多编辑器都可以显示该文本文件。取决于使用的操作系统,可能还可以 选择 使用哪个编辑器。
     Android MIME类型中的vnd表示这些类型和子类型具有非标准的、供应商特定的的形式。为了实现唯一性,Android使用了多个类似域规范的部分来进一步区分类型和子类型,而且,每个内容类型的 Android MIME类型都具有两种形式:一个用于某条具体的记录,另一个用于多条记录。
  • 对于单条记录,MIME类型类似于:      vnd.android.cursor.item/vnd.yourcompanyname.contenttype
  • 对于记录或行的集合,MIME类型类似于:   vnd.android.cursor.dir/vnd.yourcompanyname.contenttype
    MIME类型广泛用于Android中,尤其是在Intent中,系统在Intent中根据数据的MIME类型来判断调用哪些活动。MIME类型总是通过ContentProvider从它们的URI得出的,在使用MIME类型时,需要注意以下3点:
  • 类型和子类型对于它们表表示的内容必须是唯一的
  • 如果类型和子类型不是标准的(在谈到具体的记录通常属于这种情况),则需要在它们前面添加vnd
  • 它们通常是针对具体需求添加了命名空间
    通过Android cursor返回的项集合的主要MIME类型应该始终为 vnd.android.cursor.dir ,通过Android cursor获取的单一项的主要MIME类型应该是vnd.android.cursor.item 
 
3.使用URI读取数据
    要从ContentProvider获取数据,需要使用该ContentProvider提供的URI,因为ContentProvider定义的URI对该ContentProvider是唯一的,所以记录这些URI并使其能被程序员看到和调用非常重要。Android中包含的ContentProvider通过定义表示这些URI字符串常量来实现此目的。
    
    给定这些URI,从联系人提供程序获取单行联系人信息的代码类似于:
        Uri peopleUri = Contacts.People.CONTENT_URI;
        Uri myPersonUri = Uri.withAppendedPath( Contacts.People.CONTENT_URI,"23" );
        Cursor cur = managedQuery( myPersonUri  ,null,null,null,null);
    Note:ContentProvider应该实现一组接口或是将列名称作为常量列出,以列出它支持的列。但是,定义列常量的类或接口也应该通过列命名约定、注释或文档清晰地表明列的类型,因为没有正式的方式通过常量指定列的类型
    
4.使用游标(curosr)    
    游标的一些知识:
  • 游标是一个行集合
  • 读取数据之前,需要使用moveToFirst(),因为游标放在第一行之前
  • 需要知道列名称
  • 需要知道列类型
  • 所有字段访问方法都是基于列编号,所以必需首先将列名称转换为列编号
  • 游标可以随意移动(可以向前向后移动,也可以跳过一段距离)
  • 由于游标可以随意移动,所以可以向它获取行计数
   建议首先从游标显式的获取所引,以避免意外。为了找到游标中的行数,Android为游标对象提供了一个getConut()方法。
 
5.使用where子句
    ContentProvider提供了两种方式来传递where子句
    a.通过URI
        String noteUri = "content://com.google.provider.NotePad/notes/23";
        Cursor cur = someActivity.managedQuery(noteUri
                     projection,//which columns to return 
                     null,      //where clause
                     null);     //orderby clause
    b.通过String子句与一组可替换的字符串数组参数的组合         
        Cursor cur = someActivity.managedQuery("content://com.google.provider.NotePad/notes/23";  //Uri
                     null,                   //String[] projection
                     "_id = ?"               //String selection
                     new String[] {23},      //String [] selectionArgs
                      null);                 //sortOrder
 
6.插入记录
    Android使用类Android.content.ContentValues来保存将插入的单一录音的值,ContentValues是一个键/值对字典,非常类似于列名称和它们的值。要插入记录,首先将记录填充到ContentValues,然后告诉Android.content.ContentValues使用URI插入该记录。
    ContentValues values = new ContentValues();
    values.put("tile","New note");
    values.put("note","This is a new note");
    ContentResolver contentR = activity.getContentResolver();
    在NoteP示例中,
    Uri uri = contentResolver.insert(NotePad.Notes.CONTENT_URI,values);
    此调用返回一个指向新插入记录的URI,回返的URI将具有以下结构:                      
    NotePad.Notes.CONTENT_URI/new_id
 
7.更新和删除
    更新使用的主要是:
    int numberOfRowUpdated = 
    activity.getContentReslover().update(
        Uri uri,       //数据URI类型
        ContentValues values,  //要更新的值
        String whereClause,    
        String [] selectionArgs);
   删除主要使用的是:
     int numberOfRowDeleted = 
    activity.getContentReslover().update(
        Uri uri,
        String whereClause,
        String [] selectionArgs);
 
8.使用UriMatcher来解析URI
    Android的UriMatcher实用程序类有助于识别URI类型。它的工作原理:你告诉UriMatcher实例需要什么样的URI模式,还将一个唯一编号与每个模式关联,注册这些模式之后,可以询问UriMatcher,传入的URI是否与某个模式匹配。
 
9.使用投影映射
    ContentProvider充当着抽象列集和数据库中真实的列集之间的媒介,这些列集可能是不同的。在构造查询时,必须在客户端指定的where子句列与真实的数据库列之间建立映射。可以借助SQLiteQueryBuilder类建立此投影映射。
 
 
实现ContentProvider

    要编写ContentProvider,必须扩展android.content.ContentProvider并实现以下重要方法:        
  • query()    
  • insert()
  • update()
  • delete()
  • getType() 
 
 
 
 
    采取的各种步骤:
  • 计划数据库、URI列名称等,创建无数据类来定义所有这些元数据元素的常量
  • 扩展抽象类ContentProvider
  • 实现方法:query、insert、update、delete和getType
  • 在AndroidManifest.xml文件中注册提供程序
 
getType(uri uri)这个方法何时被调用

    当我们在程序中需要启动例外的activity时,很多时候我们是使用的隱式調用,即我们不直接指定要跳转的Activity,而是为Intent提供一些相关的参数,让其自动去和AndroidManifest.xml中已有的Activity去匹配,而IntentFilter(Intent 过滤器)在xml中有三個主要的参数:action,categary,data。
    我们通过Intent的构造函数或者Intent提供的方法可以指定这个三个参数,如方法有:
            intent.setAction(action);
            intent.setData(data);
            intent.addCategory(category);
    等,比如在记事本程序中有:
         <intent-filter android:label="@string/resolve_edit">
                <action android:name="android.intent.action.VIEW" />
                <action android:name="android.intent.action.EDIT" />
                <action android:name="com.android.notepad.action.EDIT_NOTE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
         </intent-filter>
    我们很容易看出action和category是很容易匹配的,而我们传的Uri的数据怎么匹配呢,这时系统会去调用你定义的ContentProvider中的getType,取得相关的返回值來和上面的data串进行匹配,当然getType的返回结果你是需要自己去定义的。
    但在程序中你也可以自己知道data的类型,就直接匹配了:intent.setType(type);
 
    

你可能感兴趣的:(ContentProvider)