import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
private lateinit var textView: TextView
private val mDemoViewModel: DemoViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView = findViewById(R.id.textView)
lifecycleScope.launch {
//3.View层设置监听(VM层根据意图执行相应的逻辑后会主动触发该回调)
mDemoViewModel.mUiState.collect { uiState ->
when (uiState) {
is DemoUiState.loginSuccess -> {
textView.setText(uiState.success)
}
is DemoUiState.loginFail -> {
textView.setText("登录失败")
}
is DemoUiState.beforeLogin -> {
textView.setText(uiState.bengin)
}
}
}
}
}
//1.点击按钮模拟网络请求
fun login(view: View) {
lifecycleScope.launch {
//1.1.通过管道将意图传递给ViewModel层
mDemoViewModel.mChannel.send(DemoIntent.LoginIntent)
}
}
override fun onDestroy() {
super.onDestroy()
//Channel是一种协程资源['热'流],跨越不同的协程进行通信
//在使用完若不去关闭,会造成不必要的浪费
mDemoViewModel.mChannel.close()
}
}
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
/**
* 意图类
* 可以将意图类写在对应的ViewModel类中,不需要分开出去
* 好处:避免粒度分的过细,从而增加项目的复杂度
*/
sealed class DemoIntent {
//意图的个数根据实际的需求进行添加
object LoginIntent : DemoIntent()
}
class DemoViewModel : ViewModel() {
val mChannel = Channel<DemoIntent>()
private val mDemoUiState = MutableStateFlow<DemoUiState>(DemoUiState.beforeLogin("准备登录"))
//使用flow来监听
val mUiState: StateFlow<DemoUiState> = mDemoUiState
init {
handleIntentInfo()
}
private fun handleIntentInfo() {
viewModelScope.launch {
mChannel.consumeEach{//consumeEach:channel(管道)读数据推荐方案[直接使用receive是很容易出问题的]
//2.接收用户传输过来的意图
when(it){
//这里为什么要经过一个意图呢?而不是有通信即可,目的是为了便于管理,视图是为了V层跟VM层更好地解耦 以及代码扩展
is DemoIntent.LoginIntent -> getLoginData()
}
}
}
}
private fun getLoginData() {
viewModelScope.launch {
requestLogin.flowOn(Dispatchers.Default)
.catch { exception ->
mDemoUiState.value = DemoUiState.loginFail(exception)
}.collect { loginInfo ->
mDemoUiState.value = DemoUiState.loginSuccess(loginInfo)
}
}
}
private val requestLogin: Flow<String> = flow {
val loginInfo = "登录成功" //模拟请求登录接口
emit(loginInfo)
}
}
sealed class DemoUiState {
//为了降低复杂度,方法的参数都写定(实际项目中括号内部的参数建议封装成泛型)
data class beforeLogin(var bengin: String):DemoUiState()
data class loginSuccess(var success: String):DemoUiState()
data class loginFail(var exception: Throwable):DemoUiState()
}