В Activity / Fragment Как получить / дождаться возврата значения из операции сопрограмм ViewModel? - PullRequest
0 голосов
/ 27 января 2019

Следуя демонстрации codelab от Google ( ссылка ), я пытаюсь реорганизовать свой код в ViewModel + сопрограммы.У меня вопрос: вместо того, чтобы просто вставить данные ( исходный код ), я хочу дождаться результата от операции вставки, которая должна вернуть идентификатор, если вставка прошла успешно, затем сделать что-то на основе результата,Так как это сделать?

В настоящее время я отправляю метод в метод вставки ViewModel в качестве обратного вызова.Конечно, наблюдение за ViewModel является еще одним вариантом.Но есть ли лучшее решение?

Мой текущий код:

EventActivity:

viewModel.insert(Event("name"), {
    if (it == -1L) {
        Log.i("insert", "failure")
    } else {
        Log.i("insert", "success: $it")
    }
})

EventViewModel:

private val mEventDao: EventDao = AppDatabase.getDatabase(application).eventDao()
private val mJob = Job()
private val mScope = CoroutineScope(Dispatchers.Main + mJob)

fun insert(event: Event, callback: (id: Long) -> Unit) {
    mScope.launch(Dispatchers.IO) {
        val result =
            try {
                // just for testing delay situation
                delay(5000)
                val id = mEventDao.insertEvent(event)
                id
            } catch (e: Exception) {
                -1L
            }
        withContext(Dispatchers.Main) {
            callback(result)
        }
    }
}

EventDao:

@Dao
interface EventDao {
    fun insertEvent(event: Event): Long
}

Ответы [ 3 ]

0 голосов
/ 27 января 2019

@ rofie-sagara совершенно прав.Вы можете добавить suspend к вашей модели insert метод.Но необязательно использовать синтаксис suspendCoroutine.Вы можете написать в вашей модели

class ViewModel {
    private val job = Job()
    private val scope: CoroutineScope = CoroutineScope(Dispatchers.IO + job)
    private val dao = Dao()

    suspend fun insert(event: Event): Long =
        withContext(scope.coroutineContext) {
            try {
                // just for testing delay situation
                delay(5000)
                dao.insert(event)
            } catch (e: Exception) {
                -1L
            }
        }
}
0 голосов
/ 28 января 2019

Вы можете добавить LiveData объект к EventViewModel, обновить его после завершения вставки и подписаться на него в Activity:

class EventViewModel : ViewModel() {
    //...
    var insertionId = MutableLiveData<Long>()

    fun insert(event: String) {
        mScope.launch(Dispatchers.IO) {
            val result =
                    try {
                        // just for testing delay situation
                        delay(5000)
                        val id = mEventDao.insertEvent(event)
                        id
                    } catch (e: Exception) {
                        -1L
                    }

            insertionId.postValue(result)
        }
    }
}

И подписаться на EventActivity:

class EventActivity : AppCompatActivity() {

    lateinit var viewModel: EventViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        viewModel = ViewModelProviders.of(this).get(EventViewModel::class.java)
        viewModel.insertionId.observe(this, android.arch.lifecycle.Observer { id ->
            // Use `id` for example to update UI. 
        })

        // ...

        viewModel.insert(Event("name"))
    }
}
0 голосов
/ 27 января 2019
  suspend fun insert(data: String): String = suspendCoroutine { cont ->
    //put logic here
    cont.resume("Done")

    //if error use this
    cont.resumeWithException(Exception("Error"))
  }

я могу удалить обратный вызов в этой функции с помощью return и ждать возврата

  fun insertData(){
    GlobalScope.launch {
      val status = insert("This is Data!")

      if( status == "Done"){
      }else{
      }
    }
  }
...