Reputation: 17
I am making android app and I wants save configuration in Android DataStore
. I have created a class and the values from EditText
are correct save to DataStore
. I using tutorial from YouTube: https://www.youtube.com/watch?v=hEHVn9ATVjY
I can view the configuration in the config view correctly (textview fields get the value from the datastore):
private fun showConfigurationInForm(){
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
binding.conMqttAddress.setText(mqqtAdress)
}
}
This function show actual config in EditText
, and this is great
But the config I will use to connect to MQTT Server, and how can I save the config to Varchar and use to another function? I create var in class:
class ConfigurationActivity : AppCompatActivity() {
private lateinit var binding: ActivityConfigurationBinding
private lateinit var mainViewModel: MainViewModel
var variMqttAddress = ""
(...)
And in function getValueFromDatastoreAndSaveToVar
I want to get and save values from DataStore
to variable variMqttAddress
private fun getValueFromDatastoreAndSaveToVar(){
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
variMqttAddress = mqqtAdress
}
}
but it doesn't work. when debugging I have an empty value in var
Log.d(TAG, "variMqttAddress:: $variMqttAddress")
___________
2021-02-16 12:42:20.524 12792-12792 D/DEBUG: variMqttAddress::
Please help
Upvotes: 0
Views: 2683
Reputation: 12953
When using flows
with DataStore
, value
will be fetched asynchronously meaning you wont have the value right away, try printing log inside observe
method and then create your MQttClient
with the url
private fun getValueFromDatastoreAndSaveToVar(){
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
variMqttAddress = mqqtAdress
//varImqttAddress will be available at this point
Log.d(TAG, "variMqttAddress:: $variMqttAddress")
val mqttClient = MqttAsyncClient(varImqttAddress, clientId, MemoryPersistence())
}
}
other way is to use, collect/first
on flows for blocking get but it requires to be inside a coroutinescope
Quick Tip: I think you can initialise
mainViewModel
globally once and access it in all methods instead of reassigning them in each method. Seems redundant
UPDATE
If you have multiple values coming from different LiveData
instances, then you can create a method something like validateParatmers()
, which will have checks for all the parameters before creating instance like
private fun getValueFromDatastoreAndSaveToVar(){
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
variMqttAddress = mqqtAdress
Log.d(TAG, "variMqttAddress:: $variMqttAddress")
validateParametersAndInitMqtt() //add checks after observing ever livedata
}
mainViewModel.readMqttPortFlow.observe(this) {mqttPort ->
variMqttPass = mqttPort.toString()
validateParametersAndInitMqtt()
}
mainViewModel.readMqttUserFlow.observe(this) { mqttUser ->
variMqttUser = mqttUser
validateParametersAndInitMqtt()
}
mainViewModel.readMqttPassFlow.observe(this) { mqttPass ->
variMqttPass = mqttPass
validateParametersAndInitMqtt()
}
}
private fun validateParametersAndInitMqtt(){
if(variMqttAddress.isEmpty() || variMqttPass.isEmpty()
|| variMqttUser.isEmpty() || variMqttPass.isEmpty()){
//if any one is also empty, then don't proceed further
return
}
//create socket instance here, all your values will be available
}
Upvotes: 2
Reputation: 17
Thank you for your help
I did not add earlier that in addition to the address of the MQQT server in the configuration, it also stores the port, user and password.
I think I am doing something wrong, in every YouTube tutorial it is shown how to "download" one configuration parameter. My function that retrieves data now looks like this:
private fun getValueFromDatastoreAndSaveToVar(){
mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
variMqttAddress = mqqtAdress
Log.d(TAG, "variMqttAddress:: $variMqttAddress")
}
mainViewModel.readMqttPortFlow.observe(this) {mqttPort ->
variMqttPass = mqttPort.toString()
}
mainViewModel.readMqttUserFlow.observe(this) { mqttUser ->
variMqttUser = mqttUser
}
mainViewModel.readMqttPassFlow.observe(this) { mqttPass ->
variMqttPass = mqttPass
}
}
in the repository class, I create a flow for each value
//Create MQTT Address flow
val readMqttAddressFlow: Flow<String> = dataStore.data
.catch { exception ->
if(exception is IOException){
Log.d("DataStore", exception.message.toString())
emit(emptyPreferences())
}else {
throw exception
}
}
.map { preference ->
val mqqtAdress = preference[PreferenceKeys.CON_MQTT_ADDRESS] ?: "none"
mqqtAdress
}
//Create MQTT Port flow
val readMqttPortFlow: Flow<Int> = dataStore.data
.catch { exception ->
if(exception is IOException){
Log.d("DataStore", exception.message.toString())
emit(emptyPreferences())
}else {
throw exception
}
}
.map { preference ->
val mqqtPort = preference[PreferenceKeys.CON_MQTT_PORT] ?: 0
mqqtPort
}
(.....)
now the question is am I doing it right? now how to create MQttClient only when I have all parameters in variables?
can do some sleep of the function that is supposed to create the MQQTClient until the asychnronic function assigns values to variables?
Upvotes: 0