Android Adapter 源码笔记(3)

  1. SimpleAdapter extends BaseAdapter implements Filterable本质上和ArrayAdapter一样,只不过Data的数据结构更为复杂,支持的View layout也更为复杂.

    • 为了支持携带多childView的数据,mData在这里的数据结构变为了List<? extends Map<String, ?>>,每份Item都有一个Map<String, ?>对应, 里面存储了多元化的值(其实主要是为了多样化的View准备的).但是mData在这里本质还是一个List,因此在Item的层面还是按照一个List来操作.
    • interface ViewBinder: 供SimpleAdapter的外部使用者自己规定怎样将Data的value绑到对应的View上,以及其他的定制化操作,关键的钩子(setViewValue(…)),SimpleAdapter view 和 value 之间的配置灵活性就是通过这个来实现的.
    • bindView(position, v), 用来返回要呈现的Item的View的关键函数,bind挺上去有点唬人,其实就是把Item Map中的各项具体Data 到对s应的View上罢了. 会先去获取对应pos的data(Map),尝试获取一下ViewBinder(可以不设的),这里会有两个关键的数组: String[] mFrommTo,这两个值是SimpleAdapter构造的必须参数,直接拉注释了:

      • from A list of column names that will be added to the Map associated with each item.
      • to The views that should display column in the “from” parameter. These should all be TextViews. The first N views in this list are given the values of the first N columns in the from parameter

      可以看出来,这是一种很笨的一一对应法, from存的是在代表Item Data的Map中的key,而to则存的是与此Key对应的TextView的resId., 之所用from和to代表的是 bind from key to View. 并且这里所有的Item都共用一套from/to.
      了解了这些概念,看bindView就更简单了, 挨个遍历to中的View(注意bindView是针对一个ItemView的),获取to 中resId对应的View,同时以相应的from的位置的key获得Map中的value(是一个Object,不过这里会强制的使用toString转成String),拿到了view, 对应的 data,以及data转的string,如果有binder,就调用binder的setViewValue,如果binder返回false(放弃bind或者没有bind成功),就会转到默认的步骤,对应几种common的View类型:

      • Checkable 的 View:

        • 如果data是Boolean型,那么setChecked
        • 否则如果View也是TextView,那么setText

      • TextView:setText
      • ImageView:

        • 如果data是Integer,那么作为resId设置
        • 否则,会将text转为Integer,然后作为resId


      上面这段过程表达的是一种力所能及的设置,尽可能的按照正常情况为View设置合适的值.(兄弟只能帮到这里了).其他部分不赘述,差别不大.
  2. **abstract class CursorAdapter extends BaseAdapter implements Filterable,
    CursorFilter.CursorFilterClient**,故名思意,背后的Data是Cursor,两个抽象方法: newView()和bindView()保证了子类在Data和View间映射的灵活性.

    • 两个FLAG用来影响cursor data change时的行为:

      • FLAG_AUTO_REQUERY 0x01: 如果设置了,那么每次有content change notification到来时,Adapter会对Cursor调用requery()(这个操作还没有仔细看过源码,mark一下,带有enable的含义),设置这个隐含设置了FLAG_REGISTER_CONTENT_OBSERVER
      • FLAG_REGISTER_CONTENT_OBSERVER: 0x02 adapter会register一个Cursor上的content observer,并且在change notification来的时候会onContentChanged(), 注意:register在Cursor上的observer会会导致Cursor的泄漏,记得不用的时候把Cursor和这些Observer的关联切断, 不过如果使用了CursorLoader,就没必要使用这个flag了
    • CursorAdapter的构造函数必须一个Cursor(不过可以是null),以及对上面flag的设置, mAutoRequery在FLAG_AUTO_REQUERY时为true. mRowIDColumn代表”_id”column的index, 如果FLAG_REGISTER_CONTENT_OBSERVER,会new 一个ChangeObserver + MyDataSetObserver,并且会尝试register到当前的Cursor上.

      • MyDataSetObserver在onChanged()/onInvalidated()会设置mDataValid,以及notify
      • ChangeObserver -> onChange -> onContentChange()
  3. changeCursor(Cursor cursor)会调用到swapCursor(cursor),并且关闭被swap的Cursor.swapCursor(Cursor newCursor)会做常规的地址相等检测,在卸掉old cursor前,会将其observer unregister,并register到new cursor上,同时刷新mRowIDColumn,mDataValid = true,然后notifyDataSetChanged(),如果new Cursor是null,那么mRowIDColumn = -1/mDataValid = false/notifyDataSetInvalidated().(又一次验证Invalidate对应的是数据无效,而不是简单的没有数据count == 0)

  4. newView/bindView都在getView被调用,不过newView是在convertView无效时,用来生成ItemView的,而bindView则是根据data来设置一个View.角色不同.

  5. onContentChanged()时,如果开了FLAG_AUTO_REQUERY,那么会调用Cursor的requery,并res作为mDataValid.

  6. getItem(int position):因为现在Data的形式是Cursor,因此需要现将Cursor moveToPos.

  7. getItemId(int position): 在Cursor moveToPos以后,通过getLong + mRowIDColumn得到 当前row的”_Id”值. 失败无效时为0.

  8. FilterQueryProvider:用来做到DB的query,一般来说不应该在主线程(可以理解,是一个磁盘IO过程).runQueryOnBackgroundThread(CharSequence constraint)的注释可以看出.在进行了Filter以后得到的新的Cursor会通过changeCusrsor来更新. FilterQueryProvider的runQsuery(constraint)会返回新的Cursor.

  9. abstract class ResourceCursorAdapter extends CursorAdapter: 和CursorAdapter相比多了一个Resource,这里指的是layout resource,即支持在构造/setter中直接指定Item view的layout 的resId.newView(….)被实现来直接从 resId中inflate一个View作为ItemView,要注意的是bindView这里仍然是没有实现的(关键的一步留给子类自由发挥).

  10. SimpleCursorAdapter extends ResourceCursorAdapter这时候看就很明晰了,在实现上就SimpleAdapter + ResourceCursorAdapter:主体其实就是SimpleAdapter: 也有mFrom 和 mTo[]作为bindView时的辅助,也有ViewBinder来定制View显示信息的灵活性. 主题逻辑部分和simpleAdapter基本一样,主要区别就是Data的表现形式不同.

  11. 主要是int[] mFrom 和findColumns(String[] from)这个函数, 在构造时的mFrom还是String,代表要绑到To对应的View的内容的Key,但是在Cursor形式下,数据存储是以Column形式存储的,直接用String[]不行,还需要借用Curosr的getColumnIndexOrThrow(String ColumnName)将String key转换为 int ColumnId,然后就可以用此Id获得Cursor中对应的值了.

  12. changeCursor的函数也变为了changeCursorAndColumns,因为这里限定了From(ColumnName),因此如果Cursor变化,那么相应的ColumnName也需要进行更新. From和to当然也需要跟进.

你可能感兴趣的:(android)