¿Hay alguna forma de devolver valor desde un ámbito de rutina? por ejemplo asi:
suspend fun signUpUser(signUpData : SignUpUserRequest) : User { CoroutineScope(Dispatchers.IO).launch() { val response = retrofitInstance.socialSignUP(signUpData) if (response.success) { obj = response.data } else { obj = response.message } }.invokeOnCompletion { obj = response.message } return obj }el problema es tan pronto como se llama a la función signupUser, la declaración de suspensión obj de retorno se ejecuta de inmediato, no con el valor de respuesta ... no se ejecuta secuencialmente, lo que espero es que llegue la primera respuesta y luego la función devuelva obj pero no está sucediendo. ¿Por qué?
Intenté ejecutar el bloqueo, sirvió para el propósito, pero ¿hay un mejor enfoque para hacer la misma tarea sin ejecutar el bloqueo? o esta bien?
¡Gracias por adelantado!
Puede usar la función withContext para ejecutar un código en el subproceso de fondo y devolver algún resultado:
suspend fun signUpUser(signUpData : SignUpUserRequest): User = withContext(Dispatchers.IO) { val response = retrofitInstance.socialSignUP(signUpData) if (response.success) response.data else response.message }Si necesita ejecutar trabajos en paralelo, puede usar coroutineScope o funciones de generador de rutinas async . Sin embargo, en tu caso no tienes más que una petición y por lo tanto podría ser secuencial . Como se mencionó en la respuesta anterior, puede usar withContext . Aquí está la pequeña explicación de docs :
Llama al bloque de suspensión especificado con un contexto de rutina determinado, lo suspende hasta que se completa y devuelve el resultado.
suspend fun getUser(signUpData: SignUpUserRequest): User = withContext(Dispatchers.IO) { // do your network request logic here and return the result }Tenga en cuenta que, cuando trabaje con el cuerpo de una expresión con funciones, intente siempre anotar el tipo de retorno de forma explícita.
Las corrutinas usan la sintaxis habitual de Kotlin para manejar excepciones: try/catch o funciones auxiliares integradas como runCatching (que usa probar/atrapar internamente). Tenga cuidado con las excepciones no detectadas que siempre se lanzarán . Sin embargo, los diferentes constructores de rutinas tratan las excepciones de diferentes maneras. Siempre es bueno leerdocumentación oficial u otras fuentes (como esta ).
En el laboratorio de código de Google "Cargar y mostrar imágenes de Internet" , hay un ejemplo agradable y muy elegante con MutableLiveData.
Esquema:
El beneficio es que estos datos son conscientes del ciclo de vida y puede usar los valores devueltos con observadores.
class OverviewViewModel : ViewModel() { enum class MarsApiStatus { LOADING, ERROR, DONE } private val _status = MutableLiveData<MarsApiStatus>() val status: LiveData<MarsApiStatus> = _status private val _photos = MutableLiveData<List<MarsPhoto>>() val photos: LiveData<List<MarsPhoto>> = _photos /** * Call getMarsPhotos() on init so we can display status immediately. */ init { getMarsPhotos() } /** * Gets Mars photos information from the Mars API Retrofit service and updates the * [MarsPhoto] [List] [LiveData]. */ private fun getMarsPhotos() { viewModelScope.launch { _status.value = MarsApiStatus.LOADING Log.d(TAG, "loading") try { _photos.value = MarsApi.retrofitService.getPhotos() _status.value = MarsApiStatus.DONE Log.d(TAG, "done") } catch (e: Exception) { _status.value = MarsApiStatus.ERROR _photos.value = listOf() Log.d(TAG, "error") } } } }Puede usar los valores de estado o fotos observándolos o usándolos directamente en una vista como esta:
<androidx.recyclerview.widget.RecyclerView android:id="@+id/photos_grid" android:layout_width="0dp" android:layout_height="0dp" app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:listData="@{viewModel.photos}" app:spanCount="2" tools:itemCount="16" tools:listitem="@layout/grid_view_item" />...después de haber "registrado" y cableado todo en el f.ex. con respecto al fragmento, así:
override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { try { val binding = FragmentOverviewBinding.inflate(inflater) //val binding = GridViewItemBinding.inflate(inflater) // Allows Data Binding to Observe LiveData with the lifecycle of this Fragment binding.lifecycleOwner = this // Giving the binding access to the OverviewViewModel binding.viewModel = viewModel binding.photosGrid.adapter = PhotoGridAdapter() return binding.root } catch (e: Exception) { Log.e("OverviewFragment", "${e.localizedMessage}") } return null }