5

I am new to anko and coroutines so excuse me if I am asking something trivial :)

So what I am trying to do is have the user click a button and then I want to download a JSON from the internet, store it locally and parse it. Since both operations can take considerable time I thought to use anko coroutines.

So first question is:

1. Can I use nested doAsync calls, calling the 2nd doAsync in the UIThread of the first one? I tried it and it seems to work but it feels wrong so I was trying to find a more elegant way

Example:

doAsync {
            downloadFileFromUrl(fileUrl)

            uiThread {
                doAsync {
                    IOUtils.parseFile(context!!)
                    val database = AppDatabase.getInstance(context!!)
                    val results = database.resultsDao().all

                    uiThread {
                        //show Results
                    }
                }
            }
        }

2. While searching a solution for my problem I found doAsyncResult. If 1 it's not correct, is this is the correct approach? I tried already to use it but with Boolean I get errors. See below:

    private fun downloadFileFromUrl(fileUrl: String): Boolean {

        try{
        //Download file. No doAsync calls here.
        //The procedure just returns true if successful or false in case of any errors

            return true
        } catch (e: Exception) {
            Log.e("Error: ", e.message)
            return false
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        parseButton.setOnClickListener {
            try {
                val downloadFileResult: (AnkoAsyncContext<Boolean>.() -> Boolean) = {
                    ::downloadFileFromUrl.invoke(fileUrl)
                }

                val downloadFileResultFutureValue: Future<Boolean> = doAsyncResult(null, downloadFileResult)

                //Continue processing if downloadFileResultFutureValue is true
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }
    }

This line

val downloadFileResultFutureValue: Future<Boolean> = doAsyncResult(null, downloadFileResult)

does not compile with the following error which I don't understand how to fix:

Type inference failed: Cannot infer type parameter T in 

fun <T, R> T.doAsyncResult
(
exceptionHandler: ((Throwable) → Unit)? = ...,
task: AnkoAsyncContext<T>.() → R
)
: Future<R>
None of the following substitutions

receiver: Boolean
arguments:
(
((Throwable) → Unit)?,
AnkoAsyncContext<Boolean>.() → Boolean
)

receiver: BlankFragment
arguments:
(
((Throwable) → Unit)?,
AnkoAsyncContext<BlankFragment>.() → Boolean
)
can be applied to

receiver: BlankFragment
arguments:
(
Nothing?,
AnkoAsyncContext<Boolean>.() → Boolean
)

Thanks in advance

Ioannis I
  • 298
  • 3
  • 15

1 Answers1

5

Doing this:

doAsync {
   // 1. Something
   uiThread {
      // 2. Nothing
      doAsync {

Indeed doesn't make much sense, unless (2) is not nothing, and you just omitted some code.
If you didn't, you can just stay with this version:

doAsync {
   downloadFileFromUrl(fileUrl)
   IOUtils.parseFile(context!!)
   val database = AppDatabase.getInstance(context!!)
   val results = database.resultsDao().all

   uiThread {
      //show Results
   }
}

Since parseFile() depends on downloadFileFromUrl() anyway, and everything runs in a coroutine, you don't become more concurrent by adding this back-and-forth.

Alexey Soshin
  • 16,718
  • 2
  • 31
  • 40
  • Ok so if I understood correctly what you mean, whatever is in the doAsync runs sequentially. So first the file will be downloaded. After it is downloaded the file will be parsed and finally the database will be called to be shown on screen. Well this now makes much more sense :). Thank you – Ioannis I Aug 22 '18 at 19:48