Rafiul Islam
08/21/2021, 4:13 PMRafiul Islam
08/21/2021, 4:16 PMprivate val _loginResponse: MutableLiveData<Resource<LoginResponse>> = MutableLiveData()
val loginResponse: LiveData<Resource<LoginResponse>> = _loginResponse
And I am observing it in UI
val loginResponse by viewModel.loginResponse.observeAsState()
when (loginResponse) {
is Resource.Success -> {
Log.d("TAG", "Login: Success")
}
is Resource.Failure -> {
Log.d("TAG", "Login: Failed")
}
else -> {}
}
but the logs keep getting called even when I am typing in the username field in the login form.Zach Klippenstein (he/him) [MOD]
08/21/2021, 4:57 PMZach Klippenstein (he/him) [MOD]
08/21/2021, 4:57 PMRafiul Islam
08/21/2021, 5:25 PM@Composable
fun Login(navController: NavHostController, viewModel: LoginViewModel) {
val (username, onUsernameChange) = remember { mutableStateOf("") }
val (password, onPasswordChange) = remember { mutableStateOf("") }
val loginResponse by viewModel.loginResponse.observeAsState()
when (loginResponse) {
is Resource.Success -> {
Log.d("TAG", "Login: Success")
}
is Resource.Failure -> {
Log.d("TAG", "Login: Failed")
}
else -> {}
}
Column(
modifier = Modifier
.fillMaxSize()
.padding(25.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.Start
) {
TextField(
modifier = Modifier.fillMaxWidth(),
value = username,
onValueChange = onUsernameChange,
placeholder = {
Text("Username")
},
leadingIcon = {
Icon(Icons.Default.Person, null)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color(0xfff4f8f7),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
shape = RoundedCornerShape(10)
)
Spacer(Modifier.height(20.dp))
TextField(
modifier = Modifier.fillMaxWidth(),
value = password,
onValueChange = onPasswordChange,
placeholder = {
Text("Password")
},
leadingIcon = {
Icon(Icons.Default.Lock, null)
},
colors = TextFieldDefaults.textFieldColors(
backgroundColor = Color(0xfff4f8f7),
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent
),
shape = RoundedCornerShape(10),
visualTransformation = PasswordVisualTransformation()
)
Spacer(Modifier.height(20.dp))
Box(modifier = Modifier.fillMaxWidth()) {
Button(
onClick = {
viewModel.login(
username, password
)
},
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(14.dp)
) {
Text(
text = "Next",
color = Color.White
)
}
Icon(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(end = 16.dp),
imageVector = Icons.Default.ArrowForward,
contentDescription = "GoArrow"
)
}
}
}
Rafiul Islam
08/21/2021, 6:01 PMZach Klippenstein (he/him) [MOD]
08/21/2021, 6:30 PMstate: State<T>
, “reading” that state value means reading state.value
. When you use the state as a property delegate (i.e. by state
), then that uses a static method that looks something like fun State<T>.get(): T = value
, so in that case just reading the property itself reads the state. However, when you destructure a state
, it calls state.component1()
, which looks like fun component1():T = value
, which means it reads the state immediately.
To bring this back to your code, inside of Login
, when you do val (username, onUsernameChanged) = remember { mutableStateOf("") }
, that is both creating the state object and immediately reading it. This means that any time the username changes, the Login
function will be recomposed, and that recomposition is what’s triggering the extra log statements.Zach Klippenstein (he/him) [MOD]
08/21/2021, 6:32 PMRafiul Islam
08/21/2021, 6:53 PMZach Klippenstein (he/him) [MOD]
08/21/2021, 6:55 PMRafiul Islam
08/21/2021, 6:57 PMZach Klippenstein (he/him) [MOD]
08/21/2021, 8:33 PMRafiul Islam
08/22/2021, 3:23 AMZach Klippenstein (he/him) [MOD]
08/22/2021, 2:49 PMText
now, but all you need to do is add that composable in wherever you want to show it.