ViewModel+LiveData

前言:对比MVP架构,ViewModel+LiveData实现的MVVM架构代码更加简洁,同时由于ViewModel和Retrofit、Room均可使用Coroutine,简化了获取数据的订阅操作。(ViewModel替代P,LiveData替代V)

实现:

1、ViewModel基类封装

open class BaseViewModel : ViewModel() {
    val isShowLoadingLiveData = MutableLiveData()

    override fun onCleared() {
        super.onCleared()
        viewModelScope.cancel()
    }
}

2、Activity基类

通过抽象createViewModel()方法将创建ViewModel对象交给业务层,方便构造方法传参和activity与fragment共用同一个ViewModel,实现数据共享。

abstract class BaseMvvmActivity : BaseActivity() {
    lateinit var mViewModel: T
    private val mLoadingDialog: ProgressDialog by lazy { ProgressDialog(this) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mViewModel = creatViewModel()
        ViewModelProvider(this, ViewModelFactory(mViewModel)).get(mViewModel::class.java)//ViewMode添加生命周期能力
        mViewModel.isShowLoadingLiveData.observe(this, Observer {isShowLoading ->
            if (isShowLoading){
                mLoadingDialog.show()
            }else{
                mLoadingDialog.dismiss()
            }
        })
    }

    /*
      创建ViewMode
    */
    protected abstract fun creatViewModel(): T
}

3、ViewModel工厂类

class ViewModelFactory constructor(private val viewModel: ViewModel): ViewModelProvider.Factory{

    override fun  create(modelClass: Class): T {
        return viewModel as T
    }
}

4、业务层具体ViewModel

fun login(mobile: String, authCode: String){
    isShowLoadingLiveData.value = true
    viewModelScope.launch {
        kotlin.runCatching {
            mUserReapository.loginMvvm(LoginReq(mobile, authCode))
        }.onSuccess {
            isShowLoadingLiveData.value = false
            ARouter.getInstance().build(RouterPath.HualalaApp.PATH_HOME).navigation()
        }.onFailure {
            isShowLoadingLiveData.value = false
        }
    }
}

注:viewModelScope 默认使用 Dispatchers.Main,由于是主线程方便更新UI(如onSuccess和onFailure均在主线程执行)

5、数据层(suspend使用)

interface UserApi {

    @POST("login/rider")
    suspend fun loginMvvm(@Body req: LoginReq): BaseRespone
}
class UserReapository @Inject constructor() {
    private val mUserApi = RetrofitFactory.instance.create(BaseConstant.SERVICE_HOST).create(UserApi::class.java)

    suspend fun loginMvvm(loginReq: LoginReq): LoginRes{
        return mUserApi.loginMvvm(loginReq).convertMvvm()
    }
}
fun  BaseRespone.convertMvvm(): T{
    when(this.code){
        ResultCode.SUCCESS -> return this.data
        ResultCode.ACCESS_TOKEN_EXPIRE -> {
            AppPrefsUtils.remove(AppPrefsUtils.ACCESS_TOKEN)
            AppManager.instance.finishAllActivity()
            ARouter.getInstance().build(RouterPath.HualalaUser.PATH_LOGIN).navigation()
            throw Throwable(this.msg)
        }
        else -> throw Throwable(this.msg)
    }
}

6、登录页面

class LoginActivity : BaseMvvmActivity(){

    override fun creatViewModel(): LoginViewModel {
        return LoginViewModel()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        toHomeTv.setOnClickListener {
            mViewModel.login("18600881234", "123456")
        }
    }
}

7、ViewModel生命周期实现原理

FragmentActivity和Fragment中定义了存放ViewModel集合的ViewModelStore,通过ViewModelProvider将创建的ViewModel添加至ViewModelStore中,然后在FragmentActivity和Fragment生命周期中管理ViewModelStore从而实现生命周期

8、LiveData在fragment中注意点

最好不要直接将fragment作为LifecycleOwner使用。某些场景会导致重复订阅(如在onViewCreated()中进行订阅,而LiveData解绑是在fragment的onDestory中进行,在fragment复用场景,如viewpager中,复用fragment不会onDestory而再执行onViewCreated导致重复订阅,解绑和绑定生命周期不匹配导致的),所以我们可以使用fragment中的getViewLifecycleOwner()获取的LifecycleOwner对象进行订阅,该对象是在onDestroyView()方法中进行解绑,

你可能感兴趣的:(jetpack,ViewModel,livedata,mvvm)