{"id":31574884,"url":"https://github.com/metalabdesign/asyncawait","last_synced_at":"2026-03-11T05:31:22.234Z","repository":{"id":143116781,"uuid":"66113573","full_name":"metalabdesign/AsyncAwait","owner":"metalabdesign","description":"async/await for Android built upon coroutines introduced in Kotlin 1.1","archived":false,"fork":false,"pushed_at":"2018-02-16T16:38:26.000Z","size":213,"stargazers_count":404,"open_issues_count":9,"forks_count":19,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-10-30T13:22:03.880Z","etag":null,"topics":["async","coroutines","kotlin","ui-thread"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/metalabdesign.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2016-08-19T21:29:43.000Z","updated_at":"2025-06-30T19:46:15.000Z","dependencies_parsed_at":"2024-01-07T04:48:11.917Z","dependency_job_id":null,"html_url":"https://github.com/metalabdesign/AsyncAwait","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/metalabdesign/AsyncAwait","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalabdesign%2FAsyncAwait","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalabdesign%2FAsyncAwait/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalabdesign%2FAsyncAwait/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalabdesign%2FAsyncAwait/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/metalabdesign","download_url":"https://codeload.github.com/metalabdesign/AsyncAwait/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/metalabdesign%2FAsyncAwait/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30372169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"online","status_checked_at":"2026-03-11T02:00:07.027Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","coroutines","kotlin","ui-thread"],"created_at":"2025-10-05T16:59:54.708Z","updated_at":"2026-03-11T05:31:22.193Z","avatar_url":"https://github.com/metalabdesign.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Async/Await\nA Kotlin library for Android to write asynchronous code in a simpler and more reliable way using `async`/`await` approach, like:\n\n```Kotlin\nasync {\n   progressBar.visibility = View.VISIBLE\n   // Release main thread and wait until text is loaded in background thread\n   val loadedText = await { loadFromServer() }\n   // Loaded successfully, come back in UI thread and show the result\n   txtResult.text = loadedText\n   progressBar.visibility = View.INVISIBLE\n}\n```\nAs you see in the example above, you can write asynchronous code in a imperative style, step by step. Calling `await` to run code in background doesn't lock the UI thread. And execution _continues_ in UI thread after background work is finished. There is no magic, see [how it works](#how-it-works).\n\n## Dependency\n```Groovy\ncompile 'co.metalab.asyncawait:asyncawait:1.0.0'\n```\n\n## Usage\n### `async`\n\nCoroutine code has to be passed as a lambda in `async` function\n```Kotlin\nasync {\n   // Coroutine body\n}\n```\n\n### `await`\n\nLong running code has to be passed as a lambda in `await` function\n```Kotlin\nasync {\n   val result = await {\n      //Long running code\n   }\n   // Use result\n}\n```\nYou may have many `await` calls inside `async` block, or have `await` in a loop\n\n```Kotlin \nasync {\n   val repos = await { github.getRepos() }\n   showList(repos)\n   repos.forEach { repo -\u003e\n      val stats = await { github.getStats(repo.name) }\n      showStats(repo, stats)\n   }\n}\n```\n\n### `awaitWithProgress`\n\nUse it to show loading progress, its second parameter is a progress handler.\n```Kotlin\nval loadedText = awaitWithProgress(::loadTextWithProgress) {\n         // Called in UI thread\n         progressBar.progress = it\n         progressBar.max = 100\n      }\n```\nA data loading function (like the `loadTextWithProgress` above) should have a functional parameter of type `(P) -\u003e Unit` which can be called in order to push progress value. For example, it could be like:\n```Kotlin\nprivate fun loadTextWithProgress(handleProgress: (Int) -\u003e Unit): String {\n   for (i in 1..10) {\n      handleProgress(i * 100 / 10) // in %\n      Thread.sleep(300)\n   }\n   return \"Loaded Text\"\n}\n```\n\n### Handle exceptions using `try/catch`\n\n```Kotlin\nasync {\n   try {\n      val loadedText = await {\n         // throw exception in background thread\n      }\n      // Process loaded text\n   } catch (e: Exception) {\n      // Handle exception in UI thread\n   }\n}\n```\n\n### Handle exceptions in `onError` block\n\nCould be more convenient, as resulting code has fewer indents. `onError` called only if exception hasn't been handled in `try/catch`.\n```Kotlin\nasync {\n   val loadedText = await {\n      // throw exception in background thread\n   }\n   // Process loaded text\n}.onError {\n   // Handle exception in UI thread\n}\n```\n\nUnhandled exceptions and exception delivered in `onError` wrapped by `AsyncException` with convenient stack trace to the place where `await` been called originally in UI thread \n\n### `finally` execution\n`finally` always executed after calling `onError` or when the coroutine finished successfully.\n```Kotlin\nasync {\n   // Show progress\n   await { }\n}.onError {\n   // Handle exception\n}.finally {\n   // Hide progress\n}\n```\n\n### Safe execution\n\nThe library has `Activity.async` and `Fragment.async` extension functions to produce more safe code. So when using `async` inside Activity/Fragment, coroutine won't be resumed if `Activity` is in finishing state or `Fragment` is detached.\n\n### Avoid memory leaks\n\nLong running background code referencing any view/context may produce memory leaks. To avoid such memory leaks, call `async.cancelAll()` when all running coroutines referencing current object should be interrupted, like\n```Kotlin\noverride fun onDestroy() {\n      super.onDestroy()\n      async.cancelAll()\n}\n```\nThe `async` is an extension property for `Any` type. So calling `[this.]async.cancelAll` intrerrupts only coroutines started by `[this.]async {}` function.\n\n### Common extensions\n\nThe library has a convenient API to work with Retrofit and rxJava.\n\n#### Retorift\n* `awaitSuccessful(retrofit2.Call)`\n\nReturns `Response\u003cV\u003e.body()` if successful, or throws `RetrofitHttpError` with error response otherwise.  \n```Kotlin\nasync {\n   reposList = awaitSuccessful(github.listRepos(userName))\n}\n```\n#### rxJava\n* await(Observable\u003cV\u003e)\n\nWaits until `observable` emits first value.\n```Kotlin\nasync {\n   val observable = Observable.just(\"O\")\n   result = await(observable)\n}\n```\n\n### How to create custom extensions\nYou can create your own `await` implementations. Here is example of rxJava extension to give you idea. Just return the result of calling `AsyncController.await` with your own lambda implementation. The code inside `await` block will be run on a background thread.\n```Kotlin\nsuspend fun \u003cV\u003e AsyncController.await(observable: Observable\u003cV\u003e): V = this.await {\n   observable.toBlocking().first()\n}\n```\n\n## How it works\n\nThe library is built upon [coroutines](https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md) introduced in [Kotlin 1.1](https://blog.jetbrains.com/kotlin/2017/03/kotlin-1-1/).\n\nThe Kotlin compiler responsibility is to convert _coroutine_ (everything inside `async` block) into a state machine, where every `await` call is a non-blocking suspension point. The library is responsible for thread handling, error handling and managing state machine. When background computation is done the library delivers result back into UI thread and resumes _coroutine_ execution.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetalabdesign%2Fasyncawait","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetalabdesign%2Fasyncawait","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetalabdesign%2Fasyncawait/lists"}