DownLoad模块 (二)

来源:互联网 发布:知乎 中科大 清华北大 编辑:程序博客网 时间:2024/06/06 06:30
DownLoad模块 (二)

FolderBrowser是一个相对独立的模块,其作用就是展示一个可以显示文件内容并且可以前进后退交互的对话框.
结合其定位,决定使用Fragment来实现FolderBrowser, 直接使用dialogBuilder应该也可以,但是android guide中建议
此类使用DialogFragment来实现。DialogFragment与Fragment在表面上的主要区别就是DialogFragment在create的时候会apply
 android dialog 的style,这样UI上表现就像一个dialog,如果想让其全屏:http://blog.csdn.net/fyfcauc/article/details/43851233

<1>封装为Fragment可以实现对此组件的高效重用.也是android所提倡的.
<2>FolderBrowser类除了extends DialogFragment外,还implements OnClickListener<按钮点击>, OnItemClickListener<文件列表点击>,
因为FolderBrowser类的定位是C, 那么上面的OnClickListener和OnItemClickListener是可以放在这里实现的,当然,
专门定义类来实现OnClickListener和OnItemClickListener也可以,最后通过聚合/属于的方式在FolderBrowser类中工作也可以,
这样做的有点是逻辑和结构更加明晰,缺点就是有点繁琐以及对代码惯例的违背.
<3>声明一个enum类来标示 File 和 Folder,虽然依赖于Java的File类的是否是Folder函数, 但是这个enum标示可以简化一些实现。
<4>Dialog中有一个展示文件的列表ListView,那么必然要实现一个相应的BaseAdapter,此BaseAdapter的角色是重C+轻M(因为有的时候,
Adapter之间包含了M的功能),同时类似于上面的一个类兼任多种角色的风格<这种理念其实违背的类的单一性原则,but....>,该adapter顺带实现了对File类的Comparator<>接口,这样才可以顺序的展示File.
<5>Adapter中的getItemViewType和getViewTypeCount都用不到,直接pass。
<6>Adapter内部维护一个File对象数组<这个其实可以看作是M>,代表着当前所处的Folder内的文件,注意此File数组不一定忠实反映Folder下文件的状况,
有一个case:在某个folder内没有任何可见文件时,在UI上此List还会有一个叫<无>的选项,因此这种情况下,File数组会存在一个文件名叫<无>的临时文件,这样做可以保持其他部分逻辑的简单。
<7>Adapter的getCount()返回File数组的长度.
<8>Adapter的getItem(int position)直接返回File数组相应position地方的File对象.
<9>Adapter的getItemId(int position)直接返回position.
<10>Adapter的getView(int position, View convertView, ViewGroup parent),
首先获取此position的Type(File/Folder),如果convertView不可用,那么就inflate一个View,
注意如果convertView可用,也不能直接返回,因为不能保证虽然其代表的文件还存在,但是文件的类型可能发生了变化(比如从文件变成了文件夹),每次都需要重新根据File的类型来调整UI,对于Folder,该ListViewItem是可以被点击的<setEnable>,并且View的左侧会显示一个文件夹图标,每个View的Text当前还是使用对应的File对象的Name,不过可以加一个getTitle()的函数来做自定义变化.
可以通过TextView的CompoundDrawables来优化。
<11>FolderAdapter只有一个以File为参数的构造函数,标示这此ListView对应的Folder
<12>在每次进入/出来文件夹时,ListView的内容都需要更新,对应的就是M需要更新,即File数组需要更新,
update函数作用就是触发M的更新,有一个File对象作为参数来表示新进入的Folder,调用update的必须保证File的存在,是文件夹,以及可读.通过File的listFiles来获取非隐藏的文件集合并将此集合作为M的新值。然后检测文件列表是否是空,如果是空,那么加一个UI上表示空文件夹的临时File对象到M中,否则,就将M中的File以Adapater作为Comparator来进行sort.
最后一步,notifyDataSetChanged()来触发UI(V)的更新<tip: ListView的notifyDataSetChanged()会触发自己的UI刷新,但是其父类AdapterView并不会,使用时要自己实现触发环节>。完整的体现了Adapter的C角色.
<13>FolderBrowser对象在构造的时候会传递一个当前所在的文件夹路径作为参数,并且此参数要填充在一个bundle,并且通过fragment的
setArguments()来进行传递<使用bundle传递的原因:http://blog.csdn.net/fyfcauc/article/details/43839659>,因此取得FolderBrowser的实例会通过一个static的newInstance函数来返回一个可用的FolderBrowser实例
<14>和上面的bundle对象,在FolderBrowser的onSaveInstanceState中,还要将当前所在的Foldler路径<可能已经变化了>存储在提供的bundle中.
<15>在FolderBrowser的onCreate中,要为其设置style和theme,本UI不需要TITLE.
<16>在onCreateView生成UI的过程中,从bundle<onCreateView函数提供的的savedInstanceState>中获取当前所处的Folder.
并且将所有的button的clickListener设置为FolderBrowser本身<看前面的解释>以及LisView的ItemClickListener.
同时还有一步就是构造ListView使用的Adapter,并将当前Folder路径<会对其可用性进行检查,如果不OK,回退到一个缺省的文件夹>构造为File函数传给Adapter,最后触发一次update来刷新UI(V).
<17>update()主要工作是操作V,如果当前所处的Foler已经是root<File的getParent为空,或是在>=kitkat时,
Foler路径等于Environment.getExternalStorageDirectory()>,那么隐藏向上按钮,触发Adapter的update来更新ListView,setSelectionAfterHeaderView()来将ListView自动移到最上.update就是将所有UI的组件按照当前C和M的情况全部刷新一遍,因此一般M/C变化时,都会触发update.
<18>onItemClick,FolderBrowser作为C的一个功能,在用户点击了ListView上某个Enabled的View(Folder)以后,会更新相应的M(mCurrentFoler代表当前所处的Folder,这里是直接赋值来改变,其实更好的是通过一个可扩展的函数,或者listener的方式),同时update来更新V。
<19>onClick是FolderBrowser的另一个C功能,直白不解释.
<20>FolderBrowser的close是调用了DialogFragment特有的dismiss()方法<为何和dialog的行为一致>:
    /**
     * Dismiss the fragment and its dialog.  If the fragment was added to the
     * back stack, all back stack state up to and including this entry will
     * be popped.  Otherwise, a new transaction will be committed to remove
     * the fragment.
     */
<21>上一级目录: 直接更新M中的mCurrentFolder到其parent,然后update V。
<22>添加新目录:
一些要点:构造出的dialog中的EditView要实现textWatcher来检测onTextChanged,这样如果用户输入了重名或者非法的目录名,可以检测到.
输入法mode暂时切换为不需要resize,在dialog消失以后restore回来.
在成功的创建了一个Folder以后,要触发update来更新V.
<23>trivial:
(1)update函数其实可以拆分为几个小函数来分别负责update一些相互关联紧密的View集合.
(2)在click函数中处理选中Folder的逻辑时, 这里直接调用了DownloadsUtils这个全局static类的setter来存储了选择的Folder,
不过这样做有些耦合,可以采用项目中经常使用的eventBus来通过Listener模式解耦.


0 0
原创粉丝点击