Reputation: 258
I'm just new with kotlin coroutines. I just created new project for testing livedata but i cant observe data changes. I didn't understand the concept of livedata. When it'll be trigger? Because when i observe ROOM database(Not the coroutines way. i used the MutableLiveData) it was working very well. Observer was always triggered whenever data changed.
I just wanted to clean and modern code. My expectations: when I click btnLogin button (when user login with another account or you can say when data changes) livedata must trigger.
Here is my example:
Retrofit interface:
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)
}
}
}
My repository:
class Repository {
suspend fun getLoginApi(model: UserLoginModel) = RetroMainClient.getApi.login(model)
}
My viewModel:
class MainViewModel : ViewModel() {
fun login(model: UserLoginModel) = liveData(IO) {
try {
emit(Repository().getLoginApi(model))
} catch (e: Exception) {
Log.e("exception", "${e.message}")
}
}
}
and my 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}")
}
}
}
}
}
Upvotes: 4
Views: 1543
Reputation: 30735
When you call viewModel.login()
method you create a new instance of LiveData
class. In order to execute corresponding block in viewModel.login()
after every click on btnLogin
button you need call LiveData.observe()
method for every viewModel.login()
call.
In MainActivity
's onCreate
method:
btnLogin.setOnClickListener {
model = UserLoginModel("user2", "123456")
viewModel.login(model).observe(this, Observer { data ->
if (it.isSuccessful) {
btnLogin.text = data.body()?.username
}
})
}
ANOTHER APPROACH:
is to launch a coroutine in MainViewModel
class and update LiveData
field manually:
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)
}
}
}
To use viewModelScope
in MainViewModel
class add dependency to build.gradle file:
final LIFECYCLE_VERSION = "2.2.0-rc03" // add most recent version
api "androidx.lifecycle:lifecycle-viewmodel-ktx:$LIFECYCLE_VERSION"
Upvotes: 6