Android 抽象协程结构
使用Android 抽象协程结构,android,kotlin,kotlin-coroutines,Android,Kotlin,Kotlin Coroutines,使用RxJava我们可以执行以下操作: BaseViewModel protected void subscribe(Completable completable, MutableLiveData<Response> response) { mDisposable.add( completable.observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Sc
RxJava
我们可以执行以下操作:
BaseViewModel
protected void subscribe(Completable completable, MutableLiveData<Response> response) {
mDisposable.add(
completable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(disposable -> response.setValue(Response.loading()))
.doFinally(() -> response.setValue(Response.idle()))
.subscribe(
() -> response.setValue(Response.success(true)),
e -> response.setValue(Response.error(e))
)
);
}
protected <T> void subscribe(Single<T> single, MutableLiveData<Response> response) {
mDisposable.add(
single.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(disposable -> response.setValue(Response.loading()))
.doFinally(() -> response.setValue(Response.idle()))
.subscribe(
result -> response.setValue(Response.success(result)),
e -> response.setValue(Response.error(e))
)
);
}
apiCx<YourModelClass> {
request = yourApiCall()
success { yourModelClass ->
Log.d(TAG, "success")
}
error {
Log.e(TAG, "error")
}
}
protectedvoid subscribe(Completable Completable,MutableLiveData响应){
mDisposable.add(
completable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(一次性->response.setValue(response.load())
.doFinally(()->response.setValue(response.idle())
.订阅(
()->response.setValue(response.success(true)),
e->response.setValue(response.error(e))
)
);
}
受保护的void subscribe(单个、可变的LiveData响应){
mDisposable.add(
single.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(一次性->response.setValue(response.load())
.doFinally(()->response.setValue(response.idle())
.订阅(
结果->response.setValue(response.success(result)),
e->response.setValue(response.error(e))
)
);
}
然后,我们从存储库中获取Single/Complete
,并将其传递给我们的自定义subscribe()
,然后我们获得带有数据的通用结果
(可选),这是处理异步请求的非常简单的方法
我们如何用相似的结构抽象
协同程序
,而不是在ViewModel
中的每个方法中编写Launch
,并手动尝试/捕获错误?您可能正在寻找类似的东西
CoroutineWrapper
fun <T> ViewModel.apiCx(context: CoroutineContext = Dispatchers.Default, init: suspend CxWrapper<T>.() -> Unit) {
val wrap = CxWrapper<T>(context)
wrap.launch {
try {
init.invoke(wrap)
callCx(wrap)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun <T> callCx(wrap: CxWrapper<T>) {
val response: Response<T>? = wrap.request
response?.let {
if (it.isSuccessful) {
wrap.success(it.body())
} else {
wrap.fail(Pair(it.code(), it.message()))
}
}
}
class CxWrapper<T>(override val coroutineContext: CoroutineContext) : CoroutineScope {
var request: Response<T>? = null
internal var success: (T?) -> Unit = {}
internal var fail: (Pair<Int, String?>) -> Unit = {}
fun success(onSuccess: (T?) -> Unit) {
success = onSuccess
}
fun error(onError: (Pair<Int, String?>) -> Unit) {
fail = onError
}
}
fun ViewModel.apiCx(上下文:CoroutineContext=Dispatchers.Default,init:suspend CxWrapper.(->Unit){
val wrap=CxWrapper(上下文)
包装,发射{
试一试{
init.invoke(wrap)
callCx(包装)
}捕获(e:例外){
e、 printStackTrace()
}
}
}
专用趣味callCx(wrap:CxWrapper){
val响应:响应?=wrap.request
回答?让我说{
如果(it.ISSUCCESS){
wrap.success(it.body())
}否则{
wrap.fail(配对(it.code(),it.message())
}
}
}
类CxWrapper(重写val coroutineContext:coroutineContext):CoroutineScope{
var请求:响应?=null
内部变量成功:(T?->Unit={}
内部变量失败:(对)->Unit={}
趣味成功(成功时:(T?->单位){
成功=成功
}
有趣的错误(一个错误:(对)->单位){
失败=错误
}
}
您可以将其作为一个单独的帮助器类,并从您的视图模型中使用它
protected void subscribe(Completable completable, MutableLiveData<Response> response) {
mDisposable.add(
completable.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(disposable -> response.setValue(Response.loading()))
.doFinally(() -> response.setValue(Response.idle()))
.subscribe(
() -> response.setValue(Response.success(true)),
e -> response.setValue(Response.error(e))
)
);
}
protected <T> void subscribe(Single<T> single, MutableLiveData<Response> response) {
mDisposable.add(
single.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.doOnSubscribe(disposable -> response.setValue(Response.loading()))
.doFinally(() -> response.setValue(Response.idle()))
.subscribe(
result -> response.setValue(Response.success(result)),
e -> response.setValue(Response.error(e))
)
);
}
apiCx<YourModelClass> {
request = yourApiCall()
success { yourModelClass ->
Log.d(TAG, "success")
}
error {
Log.e(TAG, "error")
}
}
apiCx{
request=yourApiCall()
成功{yourModelClass->
日志d(标记“成功”)
}
错误{
Log.e(标记“error”)
}
}
您也可以这样做,只是适应了协同程序。只需使用所需的暂停方法替换不同的流类型
protected inline fun <T> MutableLiveData<Response>.subscribe(single: suspend () -> T) {
viewModelScope.launch {
try {
value = Response.loading()
value = withContext(Dispatchers.IO) {
Response.success(single())
}
} catch(e: Throwable) {
value = Response.error(e)
} finally {
value = Response.idle()
}
}
protectedinlinefun MutableLiveData.subscribe(单个:suspend()->T){
viewModelScope.launch{
试一试{
value=Response.loading()
值=withContext(Dispatchers.IO){
Response.success(single())
}
}捕获(e:可丢弃){
值=响应。错误(e)
}最后{
value=Response.idle()
}
}
要使用它,只需使用livedata作为接收器进行调用
responseLiveData.subscribe<T> {
singleFromRepo()
}
responseLiveData.subscribe<Unit> {
completableFromRepo()
}
responseLiveData.subscribe{
singleFromRepo()
}
responseLiveData.subscribe{
completableFromRepo()
}
我建议您在迁移到协同程序时,不要紧跟您已有的代码,只进行最小的修改,而要全面检查您的设计
嵌入到协同程序中的一个重要原则是结构化并发。这不仅与协同程序的作用域和取消有关,还与以任何名称使用未来有关(无论是CompletionStage
,delivered
,Task
,Single
或任何其他名称).根据结构化并发,未来基本上等同于没有定义作用域的活动线程。您应该避免它们
相反,您应该在代码中清楚地划分出启动新并行工作的位置,这些工作包含在启动站点提供的单个顶级代码块中
到目前为止,这意味着您在Android框架的每个代码入口点都有一个launch
块,这是由于面向回调的编程模型的性质造成的
但是,该块中的所有内容都应根据结构化并发进行编码。如果只需要进行一次网络调用,则代码完全是按顺序进行的:进行调用、获取响应、处理它。网络调用本身成为挂起函数,并随调用结果完成,不接受回调。所有来自阻塞调用世界的传统设计模式适用于此
请参阅此处,了解如何将协同程序与LiveData
一起使用,它可能会帮助您将设计映射到面向协同程序的设计: