как использовать сопрограмму для реконструкции / замены реализации обратного вызова - PullRequest
0 голосов
/ 03 июля 2019

Попытка заменить использование обратного вызова на сопрограммы. Имея реализацию, использующую обратный вызов, и не уверена, каков правильный подход, если сопрограммы могут помочь.

Это реализация с обратным вызовом. Он имеет класс repository для предоставления данных из локальной базы данных или удаленной сети.

    class Repository() {

        var callback = //callback is provided by the caller
        var isReady = false

        var data = null
        var firstimeCall = true  //only need to get from database at first time call

        fun getData(cb: ICallback) {

            callback = cb
            isReady = false

            if (firstimeCall) {
                firstimeCall = false
                data = doGetDataFromDatabase()  //sync call to get data from database
                isReady = true
                callback.onComplete(this)
            }

            isReady = false
            data = doGetDataFromNetwork() {// async call and lamda as the callback
                isReady = true
                saveToDatabase(data)
                callback.onComplete(this)
            }
        }
    }

repository.getData() можно вызывать несколько раз, только сначала он сначала вернет данные из базы данных, затем выход из сети и сохранение, затем вызовите callback.onComplete () для возврата данных.

В любое другое время он будет получать только из сети / сохранять / возвращать данные через обратный вызов.

варианты использования:

  1. напрямую, используя Repository, например
     repository.getData()  -- 1st time call
     repository.getData()  -- later call it again
  1. есть несколько repositories, данные из каждого будут объединены в окончательные данные.

для этого случая Aggregator содержит repositories и обеспечивает onComplete() обратный вызов для обработки данных, если все repositories готовы.

    class Aggregator {
        var repos = ArrayList<Repository>()

        fun getData() {

            for (r in repos) {
                Thread {
                    r.getData(callback)
                }.start()
            }
        }

        fun processData(data: ArrayList()) {
            ......
        }

        val callback = object ICallback (onComplete{repo->

            val hasAllComplete = repos.all {
                it.isReady
            }

            if (hasAllComplete) {
                var finalData = ArrayList<Data>()
                for (r in repos) {
                    finalData.add(r.data)
                }

                processData(finalData)
            }

        })
    }

, поэтому в случае, если у него два Repository, Aggregator.getData() будет получать данные из двух репозиториев. когда один Repository завершит свой getData() вызов, он обратится к onComplete () обратного вызова, где Aggregator проверит, готовы ли все repositories к обработке данных.

Тот же поток обратного вызова используется и для сетевого вызова.

Вопрос:

В этом случае, как изменить использование сопрограмм, чтобы только после получения данных из базы данных были завершены оба repositories, затем он начнет получать данные из сети, без использования обратных вызовов.

...