CloudSDK login from ViewModel fails

I get Unknown error communicating with server when trying to log in from the ViewModel, using a coroutine.
A brief description of the scenario:

  1. ParticleCloudSDK.init(this) is called in the MainActivity
  2. AndroidManifest has:
  • <uses-permission android:name=“android.permission.INTERNET”
  • android:usesCleartextTraffic=“true”
  1. minSdkVersion = 23
  2. Dependencies: implementation ‘io.particle:cloudsdk:1.0.1’

From the ViewModel I try to log in like this:

    fun onLoginRequest(){
        viewModelScope.launch {
            try {
                ParticleCloudSDK.getCloud().logIn(“xxxxxxx@gmail.com”, “thePassword”)
                _sLoginResult.value = “Logged in!”
            } 
            catch (e: ParticleCloudException) {
                _sLoginResult.value = e.bestMessage
            }
        }
    }

I consistently get Unknown error communicating with server, whether using an emulator or a real phone. Logcat shows the following:

2022-06-15 06:52:14.315 485-485/? E/netmgr: qemu_pipe_open_ns:62: Could not connect to the ‘pipe:qemud:network’ service: Invalid argument
2022-06-15 06:52:14.315 485-485/? E/netmgr: Failed to open QEMU pipe ‘qemud:network’: Invalid argument
2022-06-15 06:52:16.715 493-493/? E/wifi_forwarder: qemu_pipe_open_ns:62: Could not connect to the ‘pipe:qemud:wififorward’ service: Invalid argument
2022-06-15 06:52:16.715 493-493/? E/wifi_forwarder: RemoteConnection failed to initialize: RemoteConnection failed to open pipe

I thought I had covered all bases based on what the forums recommend, but just cannot get this working. Can someone please help - schedule is suffering…

Is onLoginRequest called in response to a UI element?

The Cloud SDK calls, including logIn are blocking, so you can’t make them from the UI thread. You instead need make them async first.

Thanks for the response @rickkas7. Indeed, onLoginRequest is called in response to a button click, but a Kotlin coroutine is launched to call ParticleCloudSDK.getCloud().logIn within the braces of viewModelScope.launch{}.
Is this not achieving what you call making the call async ?

You know, I can kick myself sometimes (if I had enough dexterity). I solved the issue, thanks again @rickkas7 for your answer. The solution code:

     fun onLoginRequest(){
        _sLoginResult.value = "Logging in..."
        viewModelScope.launch {
            try {
                doLogIn()
                _sLoginResult.value = "Logged in!"
            } catch (e: ParticleCloudException) {
                _sLoginResult.value = e.bestMessage
            }
        }
    }
    fun doLogIn() = viewModelScope.async{
        ParticleCloudSDK.getCloud().logIn("myEmailAddress@gmail.com", "myPassword")
    }    
1 Like

I’m sorry @rickkas7, it looks like I was fooling myself. When I do this I still get the same Unknown error communicating with server exception:

fun onLoginRequest(){
        _sLoginResult.value = "Logging in..."
        viewModelScope.launch {
            doLogin()
        }
    }
    fun doLogin() = viewModelScope.async{
        try {
            ParticleCloudSDK.getCloud().logIn("myEmailAddress@gmail.com", "myPassword")
            _sLoginResult.value = "Logged in!"
        } catch (e: ParticleCloudException) {
            _sLoginResult.value = e.bestMessage
        }
    }

Interestingly, working from the MainActivity’s OnCreate, does work. Just not from the viewModel. Boggles my mind, any ideas ? The code is below:


override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: PlainActivityBinding =
            DataBindingUtil.setContentView(this, R.layout.plain_activity)
        binding.lifecycleOwner = this  // use Fragment.viewLifecycleOwner for fragments
        binding.viewmodel = viewModel
        ParticleCloudSDK.init(this)
        GlobalScope.launch(){
            try {
                ParticleCloudSDK.getCloud().logIn("email@gmail.com", "password")
                println("Logged in")
            }
            catch(e: ParticleCloudException){
                println(e.bestMessage)
            }
        }
        GlobalScope.launch(){
            try {
                val devices = ParticleCloudSDK.getCloud().getDevices()
                for (device in devices) {
                    println("${device.name} \n")
                }
            }
            catch(e: ParticleCloudException){
                println(e.bestMessage)
            }
        }
    }