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") })
}
看一下日志输出:
基本上完美,如果有更好的建议,虽然我不经常登录博客,也可以留言讨论,大家共同进步。