协程入门(七):异常处理方案比较

713 阅读3分钟

Android原生方案

可能部分人会才取接口增加onError的方案,至于原因,可以是因为不同线程抛出的异常,android无法直接在最外层try catch住,但是这种方案在调用层次一多,书写上就更加缭乱了。

val mainHandler = Handler(Looper.getMainLooper())

    interface CallBack {
        fun onSuccess(response : String)
        fun onError(errorCode : Int)
    }

    /**
     * 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原生方式, 回调的方法一多,回调层次多,更加眼花缭乱
     */
    fun android() {

        download("http://....", object : CallBack {
            override fun onError(errorCode: Int) {
                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
            }
            override fun onSuccess(filePath: String) {
                parseLayout(filePath, object : CallBack {
                    override fun onError(errorCode: Int) {
                        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                    }

                    override fun onSuccess(layoutInfo: String) {
                        drawLayout(layoutInfo, object : CallBack {
                            override fun onError(errorCode: Int) {
                                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                            }

                            override fun onSuccess(filePath: String) {
                                parsePlayList(filePath, object : CallBack {
                                    override fun onError(errorCode: Int) {
                                        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                                    }

                                    override fun onSuccess(playList: String) {
                                        startPlay(playList, object : CallBack {
                                            override fun onError(errorCode: Int) {
                                                TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
                                            }

                                            override fun onSuccess(response: String) {
                                                notifyResult()
                                            }
                                        })
                                    }
                                })
                            }
                        })
                    }
                })
            }
        })
    }

rxjava实现

rxjava支持统一的异常处理,已经能满足大部分需求,但是相比kotlin还是存在不足。

/**
 * 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}")
}

//通过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()},
                        { throwable -> fun(){}})//统一的异常处理
}

kotlin协程实现方式

协程的方式不仅可以统一处理, 并且可以有选择的忽略某些步骤中抛出的异常,以免影响继续往下执行。

    fun coroutines() {
        //async默认最后一行是返回值,所以下面的return@async都可以去掉
        runBlocking {
            try {
                //后台线程
                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.Main) { _notifyResult() }
            } catch (exception : Exception) {
                //统一处理异常
            }

        }
    }

微信公众号