ActiveAndroid 源码阅读笔记 (3)

10.自定义的contentProvider:
    直接extends android原生的ContentProvider,
    自定义的contentProvider被使用时必须添加至App自己的manifest文件中,
  (1)内部维护了一个自用的URI_MATCHER,以及一个当前Model衍生类的Class Type的 spareArray,
     authority字段和一个作为cache的MiMe sparseArray.
  (2)Override 了 onCreate, 会对ActivieAndroid进行初始化,初始化用的configuration
    直接是configuration的builder的生成,Authority字段直接取自App的package name,       
    使用Cahce中的ModelInfo的tableInfos列表,按照每个table的index 依次顺序从1分配tableKey  
    和ItemKey,分别利用tablekey和ItemKey结合相应table的tableName和之前的authrity字段,
    加入到UriMacther中,并且使用tablekey/ItemKey作为匹配码,同时将Table的type也结合tableKey/ItemKey加入到Model type的
    sparseArray中,itemkey的区别在于,tableName后面会加#, #在Uri中的意义是位置的标识符<这个其实算是内部定制,
    代表具体的某一row>,代表着某一个item,itemkey在这里一直是奇数,在后面的getType时会根据返回的匹配码的奇偶性来区分是dir还是item。
     UriMatcher的一些基础知识:
     UriMatcher:用于匹配Uri,它的用法如下:
     1.首先把你需要匹配Uri路径全部给注册上,如下:
     //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
     UriMatcher  uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
     //如果match()方法匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,返回匹配码为1
     uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
     //如果match()方法匹配   content://com.changcheng.sqlite.provider.contactprovider/contact/230路径,返回匹配码为2
     uriMatcher.addURI(“com.changcheng.sqlite.provider.contactprovider”, “contact/#”, 2);//#号为通配符
     2.注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,
     匹配码是调用addURI()方法传入的第三个参数,假设匹配content://com.changcheng.sqlite.provider.contactprovider/contact路径,
    返回的匹配码为1。
  (3)Override的getType(Uri uri):被用来获取Uri资源的MIME类型,对与单个记录,应该以
    vnd.android.cursor.item开头,多条的则以vnd.android.cursor.dir开头,注意此方法可能被
    多线程调用。这样之前的URIMatcher就起到作用了,利用其对Uri进行match,得到的index是
    之前MIMECache中的位置,不过也可能Cache已经将此MIME类型清除,如果被清除,就要跟据uri,
    来取得对应的Model的class type,如果match得到的index是偶数,那么就是一个dir<非item>,
   否则就是一个item,拼接出一个MIME 字串,将其加入到MIME cache中并返回。
   附一些Android MIMEtype的知识:
      当一个intent对象被一个Intent Filter进行匹配测试时,有三个方面会被参考到:动作、data
   (URI以及数据类型)和类别。其中的data就和MIME Type有关。在data里面定义了该过滤器的数据类型
  ,一般情况下是指匹配该过滤器的intent对象所包含的URI必须是该类型的。
  而一个URI返回什么样的类型是在相关Provider类的getType(Uri uri)方法中决定的。Content providers
  能以字符串的形式返回标准的MIME Type或者自定义的MIME Type。在自定义的ContentProvider类中,
  一般会重写getType()方法,用于返回一个与URI对应的MIMEType,一个MIME Type由媒体类型(type)与子类型(subtype)组成,
  它们之间使用反斜杠/分割,形式是:type/subtype.
  自定义MIME type的Type值总是如下两种形式:
  1.vnd.android.cursor.dir代表返回结果为多列数据
  2.vnd.android.cursor.item 代表返回结果为单列数据.
  定义MIME type的subtype值
  自定义媒体类型的子类型subtype叫做provider-specific,android内置的provider中出现的subtype一般都比较简单。
  比如联系人应用中为一个电话号码创建一个新的联系人,URI对应的MIME type如下:
  vnd.android.cursor.item/phone_v2.注意这里子类型subtype的值只是简单的phone_v2。
  而对于一般开发者的应用而言,subtypes的值要复杂一些,具体形式可能是根据provider的authority和要查询的表名来的。
  例如一个包含火车时刻信息的provider,其中provider的authority为com.example.trains,provider创建的表格中有表Line1,Line2和Line3。
  那么查询表Line1记录的URI一般写为content://com.example.trains/Line1,则provider为这个URI的返回的MIME type为
  vnd.android.cursor.dir/vnd.example.line1.
  查询表Line2中第五条记录的URI为:content://com.example.trains/Line2/5.
  provider为这个URI的返回的MIME type为vnd.android.cursor.item/vnd.example.line2.
  (4) insert(Uri uri, ContentValues values),将values插入到Uri代表的DB位置中,
   这里会得到Cache提供的SqliteDataBase,基于Uri得到对应的Model的ClassType,然后使用该Type得到Table
   的Name,调用 SqliteDataBase的insert将values插入,并根据返回的id来决定是否需要notifyChange<如果是有效Id的话>。
   并根据返回的Id和Class type构造一个Uri返回。
  (5) createUri(Class<? extends Model> type, Long id): 根据提供的Model的类型和id 构造一个指向DB中该条记录的Uri,
  "content://" + Authority字段/ + Tablename/ + id<如果有的话>,最后将拼接的字符串作为参数进入Uri.parse得到。
  (6)getModelType(Uri uri), 利用UriMatcher得到匹配码,然后从之前的Model sparseArray中获取Model type,找不到就返回null,
  以为初始化的时候已经加了一遍了,如果找不到,那就应该是不支持的uri 或 class。
  (7)notifyChange(Uri),只是对ContentResolver的notifyChange的转发罢了,以后还要把这一块系统逻辑也看看。
  (8)update/delete也没什么特殊的,得到tablename和SqlliteDataBase,进行操作,然后notify,query 则是在得到了Cursor以后指定
   此Cursor的watch Uri,Specifies a content URI to watch for changes.<这一块的系统逻辑也要看, mark>

12. Sqlable接口: 很简单,只有一个函数:   String toSql(),说白了implements Sqlable的类对于DB,最后还是化为一句
    Sql语句.
13. Delete implements Sqlable, toSql函数只返回一个"DELETE ",因为Delete 在Sql中要搭配condition, 因此Delete还有一个
    方法,from(Class<? extends Model> table),返回一个From对象,自己也作为此From对象的构造参数。
14. class Select implements Sqlable, 本身有2个Flag:  mDistinct 和 mAll,对应Sql中的Distinct和All<两者互斥>.有对应的
    setter,要得到的Column则通过一个String数组承载,在构造时可以作为可变列表参数传入。既可以接受纯String,也可以接受
    专门的Column类,后者多一个alias<Sql中概念>,toSql()其实就是根据上面的信息构造一个Select语句,如果没有指定Column,
    那么使用 "*",同样会有一个from方法,得到一个from对象。
15. Set implements Sqlable,
    set用于更新数据记录:
    sql="update 数据表 set字段名=字段值 where 条件表达式"
    sql="update 数据表 set 字段1=值1,字段2=值2 …… 字段n=值n where 条件表达式",
    那么显然构造时需要一个Update对象作为构造参数,也需要一个字符串来制定修改哪些Field和新的修改值。
    还有一个mWhere来代表条件表达式,会有一个where()方法来提供此条件,也是字符串,
    toSql()也很直白,就是纯粹的SQL语句拼接。
    因为Set()后面不会在跟别的SQL修饰,因此可以直接execute了,该execute方法就是把toSql的值和Arugments传给
    SQLiteUtils来execute,后者其实也是调用SqlLiteDataBase的execSQL()<为啥不直接调用update?>。
16. Update implements Sqlable, 很简单,就是为上面的Set服务的前缀,在构造时就指定了Class<? extends Model>,
    及Table, 会有一个set(String set)方法来拼接构造出上面的Set对象以真正的执行操作。
17. Join不再赘述。
18. From implements Sqlable,另外一个可以execute的结尾SQL操作类,Sql中的From后面接了很多的修饰限定,
    看样子作者是懒了,不想再把后面的修饰限定进行独立成类,因此代价就是From类会有很多的方法来表示
    这些修饰限定,From的构造参数是 Class<? extends Model>(要进行操作的Table)以及Sqlable queryBase(前置的操作类型),
    为了指定filter,会有where方法来供使用者填入filter<两种形式: 纯string 和 参数列表都支持>,
    而where用的filter为了支持And/Or等逻辑操作,From也提供了这些方法,每次where函数调用都会拼接出最新的filter字符串。
    groupBy/having/orderBy/limit/offset    都是对应的Sql修饰,也是内部有flag/String保存这些值,最后toSql()时拼接。
    对了还有join和Join的一堆兄弟姐妹<最晕的操作>。

   纵观这些Sql操作类,其实用的都是类Builder模式,只不过不是很规范的builder生成对象的模式,而是自己build<配置>自己。
   execute/executeSingleLine方法都是直接调用了SQLiteUtils的对应方法。
   exists/count则是会对当前的Sql语句在进行处理<"SELECT EXISTS(SELECT 1 "/"SELECT COUNT(*) ">,然后交给SQLiteUtils进行Query.
   
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值