Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Anko doAsyncResult coroutines

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

like image 593
Ioannis I Avatar asked Aug 21 '18 20:08

Ioannis I


Video Answer


1 Answers

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.

like image 78
Alexey Soshin Avatar answered Sep 25 '22 13:09

Alexey Soshin