【问题标题】:Retroift coroutines livedata called only first time改造协程 livedata 仅第一次调用
【发布时间】:2019-12-08 10:58:45
【问题描述】:

我刚接触 kotlin 协程。我刚刚创建了用于测试 livedata 的新项目,但我无法观察到数据变化。我不明白livedata的概念。什么时候触发?因为当我观察 ROOM 数据库(不是协程方式。我使用 MutableLiveData)时,它工作得很好。每当数据发生变化时,都会触发观察者。

我只是想清洁和现代的代码。我的期望:当我单击 btnLogin 按钮时(当用户使用另一个帐户登录时,或者您可以说数据更改时)livedata 必须触发。

这是我的例子:

改造界面:

interface RetroMainClient {

    @POST("login.php")
    suspend fun login(@Body model: UserLoginModel): Response<UserLoginModel>

    companion object {
        val getApi: RetroMainClient by lazy {
            Retrofit.Builder().baseUrl("https://example.com/")
                .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create())).build()
                .create(RetroMainClient::class.java)
        }
    }
}

我的仓库:

class Repository {
    suspend fun getLoginApi(model: UserLoginModel) = RetroMainClient.getApi.login(model)
}

我的视图模型:

class MainViewModel : ViewModel() {

    fun login(model: UserLoginModel) = liveData(IO) {
        try {
            emit(Repository().getLoginApi(model))
        } catch (e: Exception) {
            Log.e("exception", "${e.message}")
        }
    }
}

和我的 MainActivity:

class MainActivity : AppCompatActivity() {

    private lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProvider(this).get(MainViewModel::class.java)

        var model = UserLoginModel("user1", "123456")

        viewModel.login(model).observe(this, Observer {

            if (it.isSuccessful) {
                btnLogin.text = it.body()?.username
            }

        })

        btnLogin.setOnClickListener {
            model = UserLoginModel("user2", "123456")

            CoroutineScope(IO).launch {
                try {
                    Repository().getLoginApi(model)
                } catch (e: Exception) {
                    Log.e("exception:", "${e.message}")
                }
            }
        }
    }
}

【问题讨论】:

    标签: android kotlin android-livedata android-architecture-components kotlin-coroutines


    【解决方案1】:

    当您调用viewModel.login() 方法时,您会创建LiveData 类的新实例。为了在每次单击btnLogin 按钮后执行viewModel.login() 中的相应块,您需要为每个viewModel.login() 调用调用LiveData.observe() 方法。

    MainActivityonCreate方法中:

    btnLogin.setOnClickListener {
        model = UserLoginModel("user2", "123456")
        viewModel.login(model).observe(this, Observer { data ->
            if (it.isSuccessful) {
                btnLogin.text = data.body()?.username
            }
        })
    }
    

    另一种方法

    是在MainViewModel类中启动一个协程并手动更新LiveData字段:

    class MainViewModel : ViewModel() {
    
        val loginResponse: LiveData<Response<UserLoginModel>> = MutableLiveData<Response<UserLoginModel>>()
    
        fun login(model: UserLoginModel) = viewModelScope.launch(IO) {
            try {
                (loginResponse as MutableLiveData).postValue(Repository().getLoginApi(model))
            } catch (e: Exception) {
                Log.e("exception", "${e.message}")
            }
        }
    }
    
    
    class MainActivity : AppCompatActivity() {
    
        private lateinit var viewModel: MainViewModel
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            viewModel = ViewModelProvider(this).get(MainViewModel::class.java)
    
            var model = UserLoginModel("user1", "123456")
    
            viewModel.loginResponse.observe(this, Observer {
    
                if (it.isSuccessful) {
                    btnLogin.text = it.body()?.username
                }
    
            })
    
            btnLogin.setOnClickListener {
                model = UserLoginModel("user2", "123456")
    
                viewModel.login(model)
            }
        }
    }
    

    要在MainViewModel 类中使用viewModelScope,请将依赖项添加到 build.gradle 文件中:

    final LIFECYCLE_VERSION = "2.2.0-rc03" // 添加最新版本

    api "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION"

    【讨论】:

    • 我不知道该怎么感谢你。我研究了几个小时,我知道每次单击按钮时我都会创建新实例。但我不知道如何避免它。非常感谢。
    • 你救了我的命 :)
    猜你喜欢
    • 1970-01-01
    • 2018-10-02
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    相关资源
    最近更新 更多