记一次相册重构

• 6 分钟阅读 • Android

相册重构背景

旧相册现状:

  1. 多种相册耦合严重,难以维护迭代
  2. 入口参数混乱,容易出错
  3. 分页多次扫描,多次查询
  4. 数据结构不合理,数据源管理较多
  5. 扫描入口调用较多,界面退出扫描未及时终止

相册入口


class Picker {

    companion object{

        const val allTag = "全部"

        /**

         * 普通选择器

         */

        @JvmStatic

        fun basic() = BasicPicker()

        /**

         * 创作模板选择器

         */

        @JvmStatic

        fun creation() = CreationPicker()

        /**

         * AI模板选择器

         */

        @JvmStatic

        fun ai() = AiPicker()

    }

}

//启动示例代码,可链式设置常见参数通过回调直接返回

Picker.basic().setMax(1).setType(PickType.IMG).start(medias -> {

                            

                        });

相册选取的配置选项


class BasicPicker : BasePicker() {

    /**

     * 设置类型,默认图片 + 视频

     */

    fun setType(type: PickType): BasicPicker {

        config.type = type

        return this

    }

    /**

     * 是否保留选择页面

     */

    fun setKeep(value:Boolean): BasicPicker{

        config.keep = value

        return this

    }

    /**

     * 设置最小选择数量

     */

    fun setMin(value:Int): BasicPicker{

        config.minPick = value

        return this

    }

    /**

     * 设置最大选择数量

     */

    fun setMax(value:Int): BasicPicker{

        config.maxPick = value

        return this

    }

    /**

     * 设置自定义检查器(其他关于选取的限制条件会失效)

     */

    fun setChecker(clazz:Class<out AbsBaseChecker>): BasicPicker{

        config.checker = clazz

        return this

    }

    /**

     * 设置选取提示文案

     */

    fun setPickTip(value:String): BasicPicker{

        config.pickTip = value

        return this

    }

    /**

     * 开始跳转选择

     */

    fun start(call: PickCall){

        [config.call](http://config.call) = call

        [AbsBasePickAct.data](http://AbsBasePickAct.data) = config

        ActivityUtils.startActivity(BasicPickAct::[class.java](http://class.java))

    }

}

<br/>

相册展示及扫描流程(这里只列举基础相册)

  1. 入口设置选项,并生成配置一个配置对象 PickConfig,跳转并传递到展示页(部分代码)

 class PickConfig {



     //最少数量

     var minPick = 1



     //最大数量

     var maxPick = -1



     //最小时长(视频,毫秒)

     var limit: Int = Int.MAX_VALUE



     //类型,默认 图片+视频

     var type = PickType.BOTH



     //选择完是否保留页面

     var keep = false



     //回调

     var call: PickCall? = null



     //选取检查器,可自定义

     var checker: Class&lt;out AbsBaseChecker&gt; = BasicChecker::[class.java](http://class.java)



     //选取文字提示

     var pickTip: String = ""



     //note 基础相册

     //选择结果

     val selList = ArrayList<Media>()



     }

  1. 展示页如BasicPickAct 继承 AbsBasePickAct。如配置读取,执行扫描器,封装相册用到的通用行为:

     /**

      * 开始扫描

      */

     abstract fun startScan()



     /**

      * 目录更新通知

      */

     abstract fun notifyDir()



     /**

      * 分页更新通知

      */

     abstract fun notifyPage()



     /**

      * 选择文件夹更新

      */

     abstract fun pickDir(dir: MediaDir)



     /**

      * 选择变化(tab) 选中、取消

      */

     abstract fun selectChange()



     /**

      * 移除选中(底部)

      */

     abstract fun selectRemove()



     /**

      * 预览选中状态更新

      */

     abstract fun preViewUpdate(media: Media)



     /**

      * 回收

      */

     abstract fun destroy()

  1. 相册扫描–PickScanner

其主要功能是相册扫描,扫描图像跟视频,并根据文件夹名称进行分类,还有通知功能

扫描过程中,PickScanner会根据一定的数量进行分页通知,以通知UI及时更新

这里扫描用到 lifecycleScope管理生命周期,会在界面finish的时候提前终止扫描,避免性能浪费
4. 选择器–BasicChecker,可在Config.checker进行配置

类似Okhttp拦截器原理,接入方可继承AbsBaseChecker,干预 图片/视频是否可以被选取的状态,

替换check后,默认的可选配置会失效,需要自行根据配置处理
5. 图片/视频Tab 展示页 BasicMediaTabFrag,负责具体资源展示,还有选取,预览等操作

BasicMediaTabAdapter适配器是其核心代码,第4点的BasicChecker在此处判断选取及展示

阅读进度 0%