Search code examples
kotlinandroid-roomkotlin-coroutinesglobal-scope

get data from coroutine globalScope in Room database kotlin


I want to fill the ProductList in the code below but it's always null. do you have any solution?

fun nameValidation(name: TextInputEditText, cactusDao: CactusDao): String? {

            val nameText = name.text.toString()
            var productList = listOf<String>()
            GlobalScope.launch(Dispatchers.IO) {
                productList = cactusDao.getAllProductNames()
            }

            if (productList.contains(nameText)) {
                return "Product already Exists!"
            }


            if (nameText.isNullOrEmpty() || nameText.isNullOrBlank()) {
                return "Field is Empty!"
            }

            return null
        }

i expected it fills the ProductList, but nothing happened. ProductList is still null and the condition doesn't work

UPDATE(doe to request of darjow):

i used that nameValidation here:

productName.setOnFocusChangeListener { _, focused ->
            if (!focused) {
                productNameContainer.helperText =
                    ProductValidator.nameValidation(productName, cactusDao)
            }
        }

which is inside of AlertDialog class that handles alertDialogs.

and im using this AlertDialog class in a floatingActionButton.setOnClickListener{}


Solution

  • See this question for an explanation of what your issue is.

    The correct way to solve this is to turn this into a suspend function that directly calls the suspend function in the DAO:

    suspend fun nameValidation(name: TextInputEditText, cactusDao: CactusDao): String? {
    
        val nameText = name.text.toString()
        val productList = cactusDao.getAllProductNames()
    
        if (productList.contains(nameText)) {
            return "Product already Exists!"
        }
    
        if (nameText.isNullOrEmpty() || nameText.isNullOrBlank()) {
            return "Field is Empty!"
        }
    
        return null
    }
    

    Then the function that calls this function should also be turned into a suspend function, and so on up the chain until you get to the beginning of your logic flow, which might be inside a lifecycle method like onCreate() or inside a click listener, etc. At this location, launch a coroutine that handles all the sequential logic you have inside a single launch { } block.

    And don't use GlobalScope! Use lifecycleScope, or if you're in a Fragment, use viewLifecycleOwner.lifecycleScope.


    Based on your comment, this is how you should call it if this code is in an Activity:

    productName.setOnFocusChangeListener { _, focused ->
        lifecycleScope.launch {
            if (!focused) {
                productNameContainer.helperText =
                    ProductValidator.nameValidation(productName, cactusDao)
            }       
        }
    }