好久没有发过文章了,发生了好多事,一言难尽,言归正传,自我检讨感觉自己越来越懒,本来想说工作忙,但是感觉是在给自己找借口,只是希望自己不要断更,不求一周一篇,一月一篇就可以了。原创文章,如需转载请私聊作者
这一系列文章都是android框架设计,然后git地址:
点击此进入github,包含所有源码设计图
多任务处理器(初版)
多任务处理库为的是解决批量任务处理应运而生,最初是因为写图片压缩库,当时图片处理作为一个单独的库,里面其实抽象了多任务。
PS:暂时只能在android
中使用,但是如果把handler
去掉的话可以供java
后台使用
接入以及使用
1. 引入
引入使用
根build.gradle
中添加以下代码:
maven {
url "https://dl.bintray.com/1181631922/maven"
}
然后再module
的build.gradle
中进行引入即可
//已将将库发布到jcenter上,还需要配置点东西才能看到kotlin的源码,不过可以看到java源码
implementation 'com.ripple.component:task:0.0.4'
2. 使用
2.1 定义taskmodel
首先需要定义taskmodel
,定义完成后便可以使用了,下面定义了三个不同的任务
data class Task1 @JvmOverloads constructor(
private val sourcePath: String,
private var targetPath: String = ""
) : ProcessModel {
override fun getSourcePath(): String {
return sourcePath
}
override fun getTargetPath(): String? {
return targetPath
}
override fun setTargetPath(target: String) {
this.targetPath = target
}
override fun parse(sourcePath: String, targetPath: String?): String {
return sourcePath.toUpperCase()
}
}
data class Task2 @JvmOverloads constructor(
private val sourcePath: String,
private var targetPath: String = "任务2目标路径"
) : ProcessModel {
override fun getSourcePath(): String {
return sourcePath
}
override fun getTargetPath(): String? {
return targetPath
}
override fun setTargetPath(target: String) {
this.targetPath = target
}
override fun parse(sourcePath: String, targetPath: String?): String {
return "我是任务2$targetPath"
}
}
data class Task3 @JvmOverloads constructor(
private val sourcePath: String,
private var targetPath: String = "任务三目标路径"
) : ProcessModel {
override fun getSourcePath(): String {
return sourcePath
}
override fun getTargetPath(): String? {
return targetPath
}
override fun setTargetPath(target: String) {
this.targetPath = target
}
override fun parse(sourcePath: String, targetPath: String?): String {
return sourcePath.toUpperCase() + "在来个任务3一起走"
}
}
2.2 开始使用
定义完成后交给批量任务处理器即可
handleTaskList(
listOf(
Task1("abdaafda"),
Task2("不会输出"),
Task3("abdaafda又变大写了")
)
) {
onSuccess { successResult ->
}
onFailed { failedResult ->
}
onFinish { finishResult, unFinishResult ->
println("结果回调" + finishResult.toString())
println(unFinishResult.toString())
}
}
一、背景
咱们来分析一下多任务,在使用者的角度可以简单理解为其是一个黑盒,使用者放入之后经过黑盒处理之后再取出这样就达到了最终的结果。
二、分析抽象
既然是这样我们可以抽象一下,因为在linux
中万物皆文件,所以咱们传入的其实是一个sourcePath
,那么下一步我们就考虑我们想要的是什么了,然后咱们可以把那个黑盒理解为规则,那么可以抽象为fun parse(sourcePath:String,targetPath:String?):String
,这里估计大家会疑问为什么会有targetPath
,不是已经有处理结果了么,这其实是使其更具扩展性,比如要处理一个文件,使用者在处理之前就已经为其定好了targetPath
,那么在使用时直接传入即可,但是还有一种比如将图片转为base64
那么知道的只是规则结果是未知的,这时候就需要去取这个返回值了。
经过以上的分析这个库的主干就出来了,那么下一步就是要为其装饰了。
使用者在使用时肯定想的是这个库能够处理批量任务并且能够有相应的回调通知,这样使用者只需要自己定义好处理规则封装为对象,传入这个多任务处理器引擎中,得到相应的回调。
三、多任务处理器结构图
四、伪代码真调用
这里以kotlin
为例,当然也支持java
,只是kotlin
使用起来会更简洁,来模拟一下咱们想要调用
handleTaskList(taskList){
onSuccess{ successResult->
}
onFailed{ failedResult->
}
}
以上只是简单写了几个回调,基本调用方式是这样,可能使用者还想要自定义一下线程池,并行,串行等
五、编码
因为要写的是一个框架类的库,需要对扩展开放对修改关闭,此时再根据上面的抽象以及图便可以很清晰明了的将其完成,下面来细看
5.1 任务Model封装
因为是批量任务处理,并且还需要兼容不同类型,那么这个Model
必须要实现ProcessModel
接口,设计之初为了灵活设计了三个接口,但是又发现用起来比较麻烦,后来又将其粒度变大,有舍有得吧。下面来看一下接口的实现:
PS:注释中有详细的说明不再做细说明
/**
* Author: fanyafeng
* Data: 2020/6/3 19:15
* Email: fanyafeng@live.cn
* Description: 单项任务接口
*/
interface ProcessModel : Serializable {
companion object {
const val PROCESS_ITEM = "process_item"
const val PROCESS_LIST = "process_list"
}
/**
* 获取需要处理的源路径
* 不能为空皮之不存毛将焉附
*/
fun getSourcePath(): String
/**
* 目标路径可以为空
* 因为有时只知道规则不知道结果
*/
fun getTargetPath(): String?
/**
* 处理后的目标路径不能为空
*/
fun setTargetPath(target: String)
/**
* 任务解析器
* 这里按道理说如果有了targetPath那么这个返回值是可以不需要的
* 但是就是因为如果你去处理一个任务但是有规则没有输出那么这个返回值就是必须的了
* 而且不能为空
*
* 分为以下两种以下两种情况:
* 1.处理文件类
* @param sourcePath 文件原路径
* @param targetPath 文件目标路径
*
* 2.有处理规则,和原路径,那么方法的返回值就是处理结果
* @param sourcePath 文件原路径
*
*/
fun parse(sourcePath: String, targetPath: String?): String
}
5.2 引擎处理设置
这里使用的是java
的线程池的主要接口ExecutorService
,主要是其中为我们封装好了我们需要的一些通用的方法,我这里还是把任务交给线程去处理,如果是单线程则是串行,多的话就是并行处理了,还可以实现接口进行自定义
/**
* Author: fanyafeng
* Data: 2020/5/6 17:51
* Email: fanyafeng@live.cn
* Description: 使用java自带的任务服务
*/
interface ProcessEngine : Serializable {
companion object {
/**
* 单线程处理器
* 处理任务为串行处理
*/
val SINGLE_THREAD_EXECUTOR: ProcessEngine =
object : ProcessEngine {
override fun getExecutorService(): ExecutorService {
return Executors.newSingleThreadExecutor()
}
}
/**
* 自带6个线程的处理器
* 不用纠结个数为什么这么定义,纯属个人喜欢的数字
* 处理任务为并行处理,并且顺序是打乱的
*/
val MULTI_THREAD_EXECUTOR: ProcessEngine =
object : ProcessEngine {
override fun getExecutorService(): ExecutorService {
return Executors.newFixedThreadPool(6)
}
}
}
/**
* 获取任务处理任务
*
* 1、线程池: 提供一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁的额外开销,提高了响应的速度。
*
* [java.util.concurrent.Executor]
* [java.util.concurrent.ExecutorService]
* [java.util.concurrent.ThreadPoolExecutor]
* [java.util.concurrent.ScheduledExecutorService]
* [java.util.concurrent.ScheduledThreadPoolExecutor]
*
* 2、线程池的体系结构:
* java.util.concurrent.Executor 负责线程的使用和调度的根接口
* |--ExecutorService 子接口: 线程池的主要接口
* |--ThreadPoolExecutor 线程池的实现类
* |--ScheduledExecutorService 子接口: 负责线程的调度
* |--ScheduledThreadPoolExecutor : 继承ThreadPoolExecutor,实现了ScheduledExecutorService
*
* [java.util.concurrent.Executor]
*
* 3、工具类 : Executors
* ExecutorService newFixedThreadPool() : 创建固定大小的线程池
* ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
* ExecutorService newSingleThreadExecutor() : 创建单个线程池。 线程池中只有一个线程
*
* ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务
*/
fun getExecutorService(): ExecutorService
}
5.3 核心任务处理
这里就包含了任务处理器以及任务回调了,因为使用者想要的就是把任务处理完成以及结果的回调不论成功或者失败。
/**
* Author: fanyafeng
* Data: 2020/6/3 19:39
* Email: fanyafeng@live.cn
* Description:
*/
interface ProcessTask {
/**
* 所有单个任务回调,任务回调包含以下所有回调,但是为了简化使用
* 除去单项任务完成回调必须重写其余进行了空实现
*
* 单项任务开始回调
* [com.ripple.task.callback.OnItemStart]
*
* 单项任务进行回调
* [com.ripple.task.callback.OnItemDoing]
*
* 单项任务打断回调
* [com.ripple.task.callback.OnItemInterrupted]
*
* 单项任务失败回调
* [com.ripple.task.callback.OnItemFailed]
*
* 单项任务成功回调
* [com.ripple.task.callback.OnItemSuccess]
*
* 单项任务完成回调
* [com.ripple.task.callback.OnItemFinish]
*/
fun getItemResult(): OnItemResult<ProcessModel>?
/**
* 所有任务回调,基本同上除去具体回调
*
* 所有任务开始回调
* [com.ripple.task.callback.OnStart]
*
* 所有任务进行回调
* [com.ripple.task.callback.OnDoing]
*
* 所有任务失败回调
* [com.ripple.task.callback.OnFailed]
*
* 所有任务成功回调
* [com.ripple.task.callback.OnSuccess]
*
* 所有任务完成结束回调
* [com.ripple.task.callback.OnFinish]
*/
fun getAllResult(): OnAllResult<List<ProcessModel>>?
/**
* 获取任务处理器引擎
* [com.ripple.task.engine.ProcessEngine]
*/
fun getProcessEngine(): ProcessEngine
}
5.4 以上任务处理的必须部分都完成,剩下的就是将任务model交付ProcessTask处理即可
因为库的主要作用是为了方便大家使用,这里进行默认实现,因为代码量略大不在这里贴了,如果感觉默认的使用不能满足大家的使用,大家可以自己在实现相关接口之后进行自己的impl
,这里贴一下库的使用代码,所有回调的结果都有,需要哪个回调实现哪个回调方法即可。
5.4.1 以下为java方式调用
主要是kotlin
使用比较简洁,但是兼容了java
的调用:
val task = ProcessTaskImpl()
task.onAllResult = object : OnAllResult<List<ProcessModel>> {
override fun onFinish(
finishResult: List<ProcessModel>?,
unFinishResult: List<ProcessModel>?
) {
TODO("所有任务完成回调")
}
}
task.handleTaskList(listOf(
Task1("abdaafda"),
Task2("不会输出"),
Task3("abdaafda又变大写了")
))
5.4.2 以下为kotlin方式调用
kotlin
调用的话就稍微简单一点
handleTaskList(
listOf(
Task1("abdaafda"),
Task2("不会输出"),
Task3("abdaafda又变大写了")
)
) {
onSuccess { successResult ->
}
onFailed { failedResult ->
}
onFinish { finishResult, unFinishResult ->
println("结果回调" + finishResult.toString())
println(unFinishResult.toString())
}
}