从 Android DataStore 中检索数据并保存到全局变量

Retrieve data from Android DataStore and save to global var

我正在制作 android 应用程序,我想在 Android DataStore 中保存配置。我创建了一个 class,EditText 中的值正确保存到 DataStore。我使用来自 YouTube 的教程:https://www.youtube.com/watch?v=hEHVn9ATVjY 我可以在配置视图中正确查看配置(textview 字段从数据存储中获取值):

private fun showConfigurationInForm(){
    mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
    mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
        binding.conMqttAddress.setText(mqqtAdress)
    }
}

此函数在 EditText 中显示实际配置,这很棒

但是我将用于连接到 MQTT 服务器的配置,如何将配置保存到 Varchar 并用于另一个功能? 我在 class:

中创建 var
class ConfigurationActivity : AppCompatActivity() {

    private lateinit var binding: ActivityConfigurationBinding

    private lateinit var mainViewModel: MainViewModel

    var variMqttAddress = ""
    (...)

在函数 getValueFromDatastoreAndSaveToVar 中,我想获取 DataStore 中的值并将其保存到变量 variMqttAddress

private fun getValueFromDatastoreAndSaveToVar(){
    mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
    mainViewModel.readMqttAddressFlow.observe(this) { mqqtAdress ->
        variMqttAddress = mqqtAdress
    }
}

但它不起作用。调试时我在 var

中有一个空值
 Log.d(TAG, "variMqttAddress:: $variMqttAddress")

___________

2021-02-16 12:42:20.524 12792-12792 D/DEBUG: variMqttAddress:: 

请帮忙

flowsDataStore 一起使用时,value 将被异步获取,这意味着您不会立即获得该值,请尝试在 observe 方法中打印日志,然后创建你的 MQttClient 和 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())
    }
}

另一种方法是在流上使用 collect/first 来阻止获取,但它需要在 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

更新

如果您有来自不同 LiveData 个实例的多个值,那么您可以创建一个类似于 validateParatmers() 的方法,该方法将在创建实例之前检查所有参数,例如

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  
}

感谢您的帮助

我之前没有补充,配置中除了MQQT服务器的地址外,还存储了端口、用户和密码。

我想我做错了什么,在每个 YouTube 教程中都展示了如何“下载”一个配置参数。我检索数据的函数现在如下所示:

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
        }
}

在存储库 class 中,我为每个值创建了一个流

    //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
        }

(.....)

现在的问题是我做对了吗? 现在如何仅当我在变量中包含所有参数时才创建 MQttClient?

可以让应该创建 MQQTClient 的函数休眠直到异步函数为变量赋值吗?