主要比较的线程切换的控制方案java
很容易会采用回调的方式,来实现android
val mainHandler = Handler(Looper.getMainLooper())
interface CallBack {
fun onSuccess(response : String)
}
/**
* 1.根据url地址下载播放列表, 网络访问,运行后台
*/
fun download(url : String, callBack : CallBack) {
thread {
println("根据url下载播放节目表 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
callBack.onSuccess("节目表")
}
}
/**
* 2.先解析下载好播放列表文件中布局相关信息,协议解析,运行后台
*/
fun parseLayout(filePath : String, callBack : CallBack) {
thread {
println("先解析节目表界面布局 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
callBack.onSuccess("界面布局信息")
}
}
/**
* 3.根据布局信息先绘制出界面框架,界面绘制,运行主线程
*/
fun drawLayout(layoutInfo : String, callBack : CallBack) {
mainHandler.post(Runnable {
println("绘制ui界面布局 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
callBack.onSuccess("布局绘制完成")
})
}
/**
* 4.接着解析播放列表中的播放素材列表,解析协议,运行后台
*/
fun parsePlayList(filePath : String, callBack : CallBack) {
thread {
println("继续解析节目单播放的素材内容 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
callBack.onSuccess("播放素材列表")
}
}
/**
* 5.界面上播放多媒体素材,运行主线程
*/
fun startPlay(playList : String, callBack : CallBack) {
mainHandler.post(Runnable {
println("播放多媒体素材 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
callBack.onSuccess("播放成功")
})
}
/**
* 6.反馈平台播放结果,网络访问,运行后台
*/
fun notifyResult() {
thread {
println("反馈平台播放结果 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
}
}
/**
* android原生方式, 回调一旦太多,就会陷入回调地狱。。。
*
* 而且是把线程控制封装在相应的api中,一旦线程控制放在外面,则更加难以理解
*/
fun android() {
download("http://....", object : CallBack {
override fun onSuccess(filePath: String) {
parseLayout(filePath, object : CallBack {
override fun onSuccess(layoutInfo: String) {
drawLayout(layoutInfo, object : CallBack {
override fun onSuccess(filePath: String) {
parsePlayList(filePath, object : CallBack {
override fun onSuccess(playList: String) {
startPlay(playList, object : CallBack {
override fun onSuccess(response: String) {
notifyResult()
}
})
}
})
}
})
}
})
}
})
}
复制代码
rxjava相比原生方式,线程控制更加方便api
/**
* 1.根据url地址下载播放列表, 网络访问,运行后台
*/
fun _download(url : String) : String {
println("根据url下载播放节目表 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
return "节目表"
}
/**
* 2.先解析下载好播放列表文件中布局相关信息,协议解析,运行后台
*/
fun _parseLayout(filePath : String) : String {
println("先解析节目表界面布局 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
return "界面布局信息"
}
/**
* 3.根据布局信息先绘制出界面框架,界面绘制,运行主线程
*/
fun _drawLayout(layoutInfo : String) : String {
println("绘制ui界面布局 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
return "布局绘制完成"
}
/**
* 4.接着解析播放列表中的播放素材列表,解析协议,运行后台
*/
fun _parsePlayList(filePath : String) : String {
println("继续解析节目单播放的素材内容 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
return "播放素材列表"
}
/**
* 5.界面上播放多媒体素材,运行主线程
*/
fun _startPlay(playList : String) : String {
println("播放多媒体素材 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
return "播放成功"
}
/**
* 6.反馈平台播放结果,网络访问,运行后台
*/
fun _notifyResult() {
println("反馈平台播放结果 thread.name = ${Thread.currentThread().name} , id = ${Thread.currentThread().id}")
}
/**
* 使用rxjava的方式,可以免得一大堆自定义的结果回调,以及带来方便的线程切换功能
*/
@Test
fun rxjava() {
Observable.just("url")
.map(object : Function<String, String> {
override fun apply(url: String?): String {
//后台线程
return _download("http://......")
}
})
.map(object : Function<String, String> {
override fun apply(filePath: String): String {
//后台线程
return _parseLayout(filePath)
}
})
.observeOn(AndroidSchedulers.mainThread())
.map(object : Function<String, String> {
override fun apply(layoutInfo: String): String {
//UI线程
return _drawLayout(layoutInfo)
}
})
.observeOn(Schedulers.newThread())
.map(object : Function<String, String> {
override fun apply(filePath: String): String {
//后台线程
return _parsePlayList(filePath)
}
})
.observeOn(AndroidSchedulers.mainThread())
.map(object : Function<String, String> {
override fun apply(playList: String): String {
//UI线程
return _startPlay(playList)
}
})
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.newThread())
.subscribe(object : Consumer<String> {
override fun accept(isSuccess: String) {
//后台线程
_notifyResult()
}
})
}
//经过lambda表达式优化下
fun rxjavaLambda() {
Observable.just("http://......")
//后台线程
.map { url -> _download(url) }
//后台线程
.map { filePath -> _parseLayout(filePath) }
.observeOn(AndroidSchedulers.mainThread())
//UI线程
.map { layoutInfo -> _drawLayout(layoutInfo) }
.observeOn(Schedulers.newThread())
//后台线程
.map { filePath -> _parsePlayList(filePath) }
.observeOn(AndroidSchedulers.mainThread())
//UI线程
.map { playList -> _startPlay(playList) }
.subscribeOn(Schedulers.newThread())
.observeOn(Schedulers.newThread())
//后台线程
.subscribe{isSuccess -> _notifyResult()}
}
复制代码
协程的方式同样拥有很好的线程切换方式,而且可以比rxjava更加高效(看示例中的注释),表达上,更加简洁。(结合异常处理后,还会有更好的优点)bash
fun coroutines() {
//async默认最后一行是返回值,因此return@async均可以去掉
runBlocking {
//后台线程
var filePath = async(Dispatchers.Default) { _download("http://...")}.await()
//后台线程
val layoutInfo = async(Dispatchers.IO) { _parseLayout(filePath) }.await()
//这边是与上边rxjava方案相比最大的不一样,能够实现_drawLayout与_parsePlayList同步进行,效率更高
//UI线程
launch(Dispatchers.Main) { _drawLayout(layoutInfo) }
//后台线程
val playList = async(Dispatchers.IO) { _parsePlayList(filePath) }.await()
//UI线程
val isSuccess = async(Dispatchers.Main) { _startPlay(playList) }.await()
//后台线程
launch(Dispatchers.Default) { _notifyResult() }
}
}
复制代码