Download模块 (十二)

Download模块 (十二)

LocalDownloadResourceProvider implements了 DownloadPageProvider.
并且还封装了几乎所有create的view的逻辑交互<C>.
LocalDownloadResourceProvider还定义了几个要显示的View类。
LocalDownloadResourceProvider把V部分也给承包了。

<1> 定义了一个sectionContainerView,用于显示一批都是某个类型的itemView。
本质是一个vertical的LinearLayout,最上面的View作为一个title和折叠开关,其他view通过LinearLayout本身的
排布实现类似于列表的效果。

没有用ListView的原因是 考虑到这样的应用场景,可能会有很多个section, 每个section对应一个Lisview,想想麻烦,并且
涉及到点击section实现折叠展开也麻烦,adapter也会一堆。
LinearLayout在实现上比较简单,就按照这种方式来实现了。
一个section会包括两个部分,一直显示,并且在最上的section title,点击可以折叠/展开 section的内容,
然后就是一个真正容纳显示了DownloadItemView的contentView,可以被折叠/展开<用一个contentView包裹住所有的ItemView,
这样只改变contentView的visiblity就可以改变所有ItemView的visiblity>。

<2> sectionContainerView在构造初始化的时候就会从持久化的信息中将之前的Download信息全部载入,并按照此来更新UI上的内容<add
ItemView>,不过在调试中发现,一次性的add太多的itemView会引起进入DownloadFragment的卡顿,因此就实现为分批add,
每次add一定量的ItemView, add完这一批以后,post一个add下一批的runnable到主线程的下一个slice<因为UI操作只能在主线程>,直到全部add完.

<3> sectionContainerView维护了在此section的所有Download的信息<M>的引用, 以及对其内部View的引用<V>,同时还会保存一些状态信息<inEditMode, allSelected>这些状态数据应该是为C的部分.

<4> sectionContainerView 定义了一些abstract方法,让子类自己选择实现
getTitleLabel: section 的 title,
preloadContentsToPendingQueue: 如何将持久化的Download信息导入到sectionContainerView 的 pedingDownload list中去。
这一个函数的关键在于,每个section可能会展示符合某种条件的Download,因此这个步骤必须是可以由子类决定的,反正必须有可自由发挥的
地方。
getContentView: 获取contentView, 这一步也关键,因为每个section的contentView也是不同的,因此也要多态化。

<5> sectionContainerView 还实现了 onClickListener<C>,将自己内部View的click处理逻辑也都承包了,封装在自己的范围内。

<6> 折叠/展开的实现很简单,将contentView的visiblity改变,以及调整titleView的某些view.

<7> sectionContainerView同样对selectAll/clearAll等需要操作Itemview的方法 采用了 转发,单纯的调用 contentView的相关方法,
这也是一个基本的思想, 对于一个跨越了很多层的调用,每一层 都只专心于自己相关的事情,然后向下一层转发,直到处理完.

<8> DownloadingSectionView extends SectionView, 顾名思义,这个section展示的都是正在下载/暂停的Download,这时候
abstract的preloadContentsToPendingQueue起到了灵活性作用,自己定义了一套从所有Download过滤的机制,得到自己需要的Download,
而title也完全由该类自己决定。
getContentView生成自己定制的contentView.
该类监听了editMode change event。 那么在onAttach/DetachTo/FromWindow时应该register/unregister 监听器.
<这也是一个基本规范,对于View/Fragment,在 attach/dettach时要注意 监听器的注册和释放>

<9> DownloadedSectionView同上,只是显示的是已经下载完的DownLoad, 生成的contentView也是自己定制的。

<10> 上面取得所有当前Download信息的途径是通过DownloadManager<M>提供的接口 <数据流向: M->C->V>。

<11> SectionContentView是一个extends LinearLayout的class, 用于容纳itemsView,并作为sectionView的content呈现。
内部会维护一个存储了在其内部的ItemView的 LongSparseArray<SectionContentItemView><用long的原因是 key 是long的>,
每个itemView都和Download的Id一一对应,不需要再维护一个专门的Download list.

<12> SectionContentView也会在Edit/Normal之间进行切换,而同时SectionContentView还应该监听并处理一个
Download完成的事件<因为设计中会有两个SectionContentView容纳正在进行和和完成的download,这就需要在一个Download完成时,
按照自己的角色定位 加入/去掉 该download>,这一部分逻辑还要考虑到Edit模式的因素,如果是在Edit模式下,那么暂且不理会这个
Event,pending起来,等回到了normal模式再进行处理pending的event。而SectionContentView会对外开放一个自己内部的ItemView变化
event的监听借口<这个纯粹是交互上的考虑,一个SectionContentView中没有itemView的时候,应该自动折叠起来,这个event被设计的
更为通用,监视itemView的变化,而不是监视是否有itemView>,尽管可以通过给child获得SectionContentView内部的ItemView,
但是出于方便以及可以根据id直接获取对应的itemView,内部维护了一个longSparseArray来保存itemView。
也会有一个ArrayList来保存pending的Download。

<13> 增加一个Download到SectionContentView,可以在输入参数中指定添加在那个位置<index>,
动态生成一个ItemView<一个性能优化是可以将ItemView池化,牺牲内存提升速度,不过当时没做>,然后将Download 通过setter给
ItemView,在两者间建立映射<再次体现了M 和 V的分离>,如果没有指定index,那么获取一个合适的。这一部分的默认实现是
排在最下方<不过这个方法是一个protected的方法,可以子类自己定制>,然后常规的addView加入到contentView中,同时将id和itemView
填入到longSparseArray,最后如果有外部的itemviewNumChangeListener,那么触发。

<14>Remove Download更为简单<不过注意这个只是删除掉了View,即在V这一层删掉download的体现,但是在M中还保留>,通过Id获取了
Itemview,removeView,然后从相应的SparseArray同步清掉,而如果是在Edit模式下清除的,
还会触发一个表示此SectionContentView选中的item的数量变化的event<删除掉的itemview自然不可能是seletcted的了,细节>,
从pendingCompelete中也要清除此Download,这些都是V所维护的信息,而对DownloadManager维护的M信息,不进行操作。
其实可以给这个函数加一个标记输入 来标示 是否也删除M的信息。
这个函数是必须,因为V 和 M不能是绑定的, 在V上消失 不代表 在M中也应该被消除, 可能从这个V消失, 在另一个V显示。

<15>clear All基本同样操作,不过会把DownloadManager<M>中也清掉,

<16>select All 转发了方法select到每个ItemView中.

<17>clearAllSelected,内部调用了Remove和DownloadManager来实现V 和 M的同时移除,一个注意是
因为是需要遍历检测并处理ItemView的SparseArray,但是Remove本身会对SparseArray造成影响,因此需要
clone一个sparseArray来进行遍历<这和C++ STL中的erase以后iterator无效是一个case>

<18>规范做法,在View attach/deattach的时候 要register/unregister相应的Listener。

<19>上面只所以定义了一个contentView的abstract base class,是因为设计中的contentView会有不同的定位,
一个只会显示正在下载的,一个只会显示下载完成的。这个两个类主要的区别就在这里,开放出有变化和分歧的地方,
就是对下载完成的Download的处理不同,一个会remove view, 一个 会 add view。
不过除此之外,两者还要监听不同的事件,这一部分不同无法在base class中以函数表现出来<如果监听的事件一致的话,还是可以的,
当前两个子类已经有重复code了>

<20>DownloadedContentView override 了添加新View要显示位置的取得函数,根据完成时间来排序。

<21>Itemview也在该类中被extends了,主要实现其抽象的UpdateViewByStatus,以及对一系列的event的响应,
一个交互细节是会监听PackageChangeEvent,如果该event的packageName和Download一致,并且此ItemView代表的Download也已经完成,
那么根据event来携带的信息更新 itemview上button显示是打开 还是 安装。

<22>DownloadItemView切换Edit模式,对于有些按钮在两种不同模式下的还有不同selected显示图案的case,可以采用selector的方式实现.

<23>ItemView封装了自己的所有处理逻辑,所有的event到来的时候,都会统一的触发ItemView的update, 根据当前Download状态的不同,
采取不同的操作,当然在监听事件处理前,要对比一下event是否是针对自己所代表的Download,通过直接对比Download对像的地址<被id更
保险和方便>,注意ItemView在这里只是 随着 M的改动 来调整 V层面的变化。 Itemview应该尽量不改变M<除了在其实现的onCLickListener 等 C 中>,在DownloadW完成时,如果是COMPLETE,会execute一个AysncTask来从APK中获取Icon<IO活动>并在其onPostExecute中为ItemView设置上<这里有一个trick,就是 在设置前要检查此itemView是否还有相关的view组件,以及是否还为一个Download所服务,一个Android
guide 提倡的优化是 AysnTask应该维护的ItemView的一个weakReference,这样不会影响Itemview在不被使用时的GC,在这里,AsyncTask直接作为一个匿名内部类,必然会维护一个对ItemView的strongRef,而如果还实现了ItemView的池化重用,那么在onPostExecute的时候还要
检测当前的itemView所服务的Download是否还是AsynTask为之工作的Download>。

<24>对于View本身的click也会根据当前Download的状态引起不同的操作 <V -> M -> C>,long click也是如此,专门将Edit模式下,click的
处理抽离为一个单独函数。

<25>因为很多逻辑都封装了内部定义的各种view中,downloadProvider本身的逻辑不多,主要处理逻辑是自定义View之外的但是还在在layout
中的View组件的click等交互和。因为DownloadedSectionView和DownloadingSectionView本身在Provider这一层上还要区分出来以执行不同的逻辑<这其实某种意义上将已经破坏了封闭性,增加了耦合>,因此会有两个引用各指向不同的sectionView,
这样后面实现的clearAllSelected和getSelectedNum也直接在这两个引用上进行操作了,而更好的是因为两个sectionView都是同一个base
class,应该维护一个base class数组,然后上面这两个函数的实现直接遍历数组即可。

<26>按照项目的设计惯例,provider除了负责提供PagerView外,还应该提供对应的IndicatorView 和 title,总之一切自己的都由自己提供和管理。


<27>DownloadItemView都是基于相同的layout文件动态生成的,那么为了在Touch某个ItemView时能够正确的响应这个onClick,必须由ItemView实现onClickListener并

设置给自己,从外部不可能,而外部声明一个onClickListner则无法知道是哪个ItemView响应,因此只能由这种方式实现,这也是对于动态生成的相同layout的View做onClick判断的一种常用方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值