AAC尝试性封装

aac全称为Android-Architecture-Components,Google不久前发布了正式版本,一下子就被吸引了,这不就是改良传统MVP的妙药吗?
添加依赖就不再赘述了,网上大把的例子,本文只是对ViewModel及LiveData做简单的封装!

勘误:
注意之前的DemoViewModel编写有些问题,极端情况下如断开wifi,此时throwableLiveData 会比isLoadingLiveData 更快进入回调,导致网络失败界面加载不出来,更改代码如下:

 private fun startInitProp() {
//        isLoadingLiveData.apply {
//            this.addSource(resultLiveData) { this.value = false }
//        }
        throwableLiveData.apply {
            this.addSource(resultLiveData) {
                isLoadingLiveData.value = false
                it?.second?.let { this.value = it }
            }
        }
        reposLiveData.apply {
            this.addSource(resultLiveData) { it?.first?.let { this.value = it } }
        }
    }

isLoadingLiveData.value = false这段代码也可以写在reposLiveData逻辑中,注意用setValue方法,不要用postValue方法。

勘误2:
其实也不算勘误,之前代码没有将aac优势发挥出来,即界面被系统销毁后的数据恢复,演示代码如下,测试时可将屏幕来回旋转,观察Activity重建后,数据是否正常:


    @AutoRestore
    var userName: String = ""
    @AutoRestore
    var pwd: String = ""

    //    val viewModel :<And>
    val viewModel: LoginViewModel by lazy {//LoginViewModel 继承自AppViewModel
        loge("get viewmodel ")
        ViewModelProviders.of(this).get(LoginViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (savedInstanceState != null && !TextUtils.isEmpty(userName)) {
            loge("应用重启")
        }
        observe()
    }

    private fun observe() {
        loge(   "${viewModel} : addr")
        viewModel.isLoadingLiveData.observe(this, Observer {
            loge("isload suc")
            if (it!!) showLoadingDialog() else showContent()
        })
        viewModel.throwableLiveData.observe(this, Observer {
            TipUtils.showToast(app, it?.message!!)
            loge("fail suc")
        })
        viewModel.reposLiveData.observe(this, Observer {
            addTokenParams(it!!.data.token)
            UserCache.saveUser(it.data, app)
//            MainActivity_.intent(this).start()
//            finish()
            loge("login suc")
        })
    }

1.创建ViewModel

import android.arch.lifecycle.MediatorLiveData
import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.ViewModel
import com.blk.resp.RespLiveData
import com.lzy.okgo.model.HttpParams

/**
 * Created by gcy on 2018/2/1 0001.
 */
class DemoViewModel<T> : ViewModel() {
    private val params = MutableLiveData<HttpParams>()

//    val resultLiveData = ReposLiveData().apply {//注意此处设计的巧妙
//        this.addSource(organizationLiveData) { it?.let { this.organization = it } }
//    }


    lateinit var resultLiveData: RespLiveData<T>

    val isLoadingLiveData = MediatorLiveData<Boolean>()/*.apply {
        this.addSource(resultLiveData) { this.value = false }
    }*/

    val throwableLiveData = MediatorLiveData<Throwable>()/*.apply {
        this.addSource(resultLiveData) { it?.second?.let { this.value = it } }
    }*/

    val reposLiveData = MediatorLiveData<T>()/*.apply {
        this.addSource(resultLiveData) { it?.first?.let { this.value = it } }
    }*/

    fun setParams(params: HttpParams, data: RespLiveData<T>) {
        resultLiveData = data
        resultLiveData.apply {
            this.addSource(this@DemoViewModel.params) { it?.let { 
            this.params = this@DemoViewModel.params.value } }
        }

        startInitProp()
        this@DemoViewModel.params.value = params
        isLoadingLiveData.value = true
    }

    private fun startInitProp() {
        isLoadingLiveData.apply {
            this.addSource(resultLiveData) { this.value = false }
        }
        throwableLiveData.apply {
            this.addSource(resultLiveData) { it?.second?.let { this.value = it } }
        }
        reposLiveData.apply {
            this.addSource(resultLiveData) { it?.first?.let { this.value = it } }
        }
    }

}

以上代码参考的是github上一位大神的例子,具体地址找不到了,在这个代码中ViewModel包含了多个LiveData,分别是正在加载(便于展示progressbar之类的),加载成功及失败时的情形。

2.简单封装LiveData

import android.arch.lifecycle.MediatorLiveData
import com.lzy.okgo.model.HttpParams

/**
 * Created by gcy on 2018/2/1 0001.
 */
abstract class RespLiveData<T> : MediatorLiveData<Pair<T?, Throwable?>>() {
    abstract var params: HttpParams?
    abstract var url: String
}

代码很简单,实际中可根据需要自己定制需要的参数,这只是一个例子!
假设现在请求的String类型的数据,抛砖引玉,可以这样写了:

import com.blankj.ALog
import com.lzy.okgo.model.HttpParams
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers

/**
 * Created by gcy on 2018/2/1 0001.
 */
class RespStringLiveData : RespLiveData<String>() {
    private var disposable: Disposable? = null
    override var params: HttpParams? = null
        set(value) {
            field = value
            ALog.e("RespStringLiveData now req network")
            disposable = Observable.create<String> {
                Thread.sleep(5000)
                it.onNext("123")
                it.onComplete()
            }
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe({ this@RespStringLiveData.value = Pair(it, null) }, { this@RespStringLiveData.value = Pair(null, it) })

        }

    override var url = ""

    override fun onInactive() {
        super.onInactive()
        if (disposable?.isDisposed?.not() ?: false) {
            disposable?.dispose()
        }
    }

}

可以将disposable的处理逻辑写到基类中去,我这里只是简单的延时5秒模拟网络请求。
至此,基本逻辑写完了!

3.测试

 fun testAAc(){
        var viewModel = DemoViewModel<String>()
        viewModel.setParams(HttpParams(),RespStringLiveData())
        viewModel.isLoadingLiveData.observe(this, Observer{ALog.e("aac当前正在加载:$it")})
        viewModel.reposLiveData.observe(this, Observer { ALog.e("aac成功了:$it") })
        viewModel.throwableLiveData.observe(this, Observer { ALog.e("aac失败了:$it") })
    }

看一下日志输出:
这里写图片描述
基本上完美,如果有更好的建议,虽然我不经常登录博客,也可以留言讨论,大家共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值