1

Trying to replace the using callback with coroutines. Having a implementation using callback and not sure what is the right approach if coroutines could help.

This is the implementation with callback. It has a class repository to provide data from either local database or network remote.

    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)
            }
        }
    }

the repository.getData() could be called multiple times, only first time it will return the data from database first, then getting from network and saving, then call callback.onComplete() to return the data.

Any other time, it will only do getting from network/save/return data through the callback.

the use case are:

  1. directly using Repository, like
     repository.getData()  -- 1st time call
     repository.getData()  -- later call it again
  1. there are multiple repositories, the data from each one will be aggregated into a final data.

for this case there is a Aggregator to hold the repositories, and provides onComplete() callback to process data if all repositories are ready.

    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)
            }

        })
    }

so in the case it has two Repository, the Aggregator.getData() will get data from the two repositories. when one Repository is complete its getData() call, it will callback to the callback's onComplete() where the Aggregator will check wether all repositories are ready for data to be processed.

The same callback flow is used for the network call aswell.

Question:

In this case how to change to use coroutines, so that only after getting data from the database are complete for both repositories, then it will start to get data from the network, without using callbacks.

1 Answer 1

1

I'm not sure if it's relevant anymore, but you could have a look at callbackFlow.

More info here: https://medium.com/@elizarov/callbacks-and-kotlin-flows-2b53aa2525cf#1aaf

I have a similar problem, and I think this might be the solution to it.

Make sure you also read more about Flow and its usage before actually using it, since there are some caveats with handling exceptions (exception transparency), etc.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.