{"id":18014628,"url":"https://github.com/achep/bindin","last_synced_at":"2025-09-07T02:08:39.863Z","repository":{"id":146978443,"uuid":"340739649","full_name":"AChep/bindin","owner":"AChep","description":"Utility library for Android with Kotlin to help you to replace the LiveData with the Flow on the presentation layer.","archived":false,"fork":false,"pushed_at":"2021-05-30T16:38:36.000Z","size":102,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-24T15:11:29.180Z","etag":null,"topics":["android","flow","kotlin","livedata"],"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/AChep.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-20T19:47:29.000Z","updated_at":"2023-09-08T18:18:49.000Z","dependencies_parsed_at":"2023-05-23T11:30:11.064Z","dependency_job_id":null,"html_url":"https://github.com/AChep/bindin","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/AChep/bindin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AChep%2Fbindin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AChep%2Fbindin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AChep%2Fbindin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AChep%2Fbindin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AChep","download_url":"https://codeload.github.com/AChep/bindin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AChep%2Fbindin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273986629,"owners_count":25202708,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"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":["android","flow","kotlin","livedata"],"created_at":"2024-10-30T04:10:25.535Z","updated_at":"2025-09-07T02:08:39.812Z","avatar_url":"https://github.com/AChep.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# bindin\n\n[![](https://jitpack.io/v/AChep/bindin.svg)](https://jitpack.io/#AChep/bindin)\n[![Detekt](https://github.com/AChep/bindin/actions/workflows/detekt.yaml/badge.svg)](https://github.com/AChep/bindin/actions/workflows/detekt.yaml)\n\nUtility library for Android with Kotlin to help you to replace the `LiveData` with the `Flow` on the presentation layer.\n\n## Download\nGradle:\n```groovy\nrepositories {\n  maven { url 'https://jitpack.io' }\n}\n\ndependencies {\n  implementation 'com.github.AChep:bindin:${latestVersion}'\n}\n```\n\n## Usage\nLet's say you have an existing setup with the `LiveData`:\n```kotlin\nval liveData = MutableLiveData\u003cBoolean\u003e()\nliveData.observe(viewLifecycleOwner) {\n  println(it)\n}\n```\n\nto migrate it you would have to use the `bindIn` function:\n```kotlin\nval liveData = MutableLiveData\u003cBoolean\u003e()\nviewLifecycleOwner.bindIn(liveData) {\n  println(it)\n}\n```\n\nHuh. That looks almost identical, right? The _real_ benefit is that it works for `Flow`s with the exact same syntax!\n```kotlin\nval flow = MutableStateFlow\u003cBoolean\u003e(false)\nviewLifecycleOwner.bindIn(flow) {\n  println(it)\n}\n```\n\nIt's guaranteed that the block will only be called on the Main thread and the lifecycle will be in required state!\nYou can specify the minimum state using the `minimumLifecycleState` argument.\n\n### Suspending functions\n\nOkay, you noticed that the `pipe` argument is not suspending function. First of all, that's intended. Secondly, you probably don't need it. \n\nFine. _Make sure you read about its limitations below before you actually use it_.\n\n```kotlin\nval flow = MutableStateFlow\u003cBoolean\u003e(false)\nviewLifecycleOwner.bindInSuspending(flow) {\n  delay(100L)\n  println(it)\n}\n```\n\nWant to run a block each time the llifecycle is in the required state instead of collecting a flow?\n\n```kotlin\nviewLifecycleOwner.bindBlock {\n  delay(100L)\n  println(\"Hello world\")\n}\n```\n\nTo match the behaviour of the normal `bindIn` function, the suspending block is run on the `PausingDispatcher` (via `lifecycle.whenStateAtLeast(...)`) and hence guarantees that the lifecycle is in the required state. [However that all changes if you want to catch exceptions](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines.cancellation/-cancellation-exception/):\n\n```kotlin\nviewLifecycleOwner.bindBlock {\n  try {\n    delay(100L)\n    // state \u003e= Lifecycle.State.STARTED is guaranteed!\n    println(\"Hello world\")\n  } catch (e: IOException) {\n    // state \u003e= Lifecycle.State.STARTED is guaranteed!\n  } catch (e: Throwable) {\n    // state \u003e= Lifecycle.State.STARTED is not guaranteed!\n    // Check kotlin.coroutines.cancellation / CancellationException\n  } finally {\n    // state \u003e= Lifecycle.State.STARTED is not guaranteed!\n  }\n}\n```\n\n## Advanced usage\n\n### `InBinding`\n\nInvoking the `bindIn` function returns the `InBinding` object. To unbind, invoke its `unbind` lambda.\n```kotlin\nval flow = MutableStateFlow\u003cBoolean\u003e(false)\nval binding = viewLifecycleOwner.bindIn(flow) {\n  println(it)\n}\n// ...\nbinding.unbind()\n```\n\n### Two-way binding\n\nTo implement two way binding you may use the `bindOut` method of the `InBinding` class. An example\nusage:\n```kotlin\nval flow = MutableStateFlow\u003cBoolean\u003e(false)\nval binding = viewLifecycleOwner.bindIn(flow) {\n  button.isChecked = it\n}.bindOut(\n  observe = { observer -\u003e\n    button.setOnCheckedChangeListener { _, isChecked -\u003e\n      observer(isChecked)\n    }\n    // Returns a function that undos the subscription.\n    fun() {\n        button.setOnCheckedChangeListener(null)\n    }\n  },\n  pipe = {\n    flow.value = it\n  },\n)\n```\nfor some of the views there's already a `bindOut` function.\n```kotlin\nval flow = MutableStateFlow\u003cBoolean\u003e(false)\nval binding = viewLifecycleOwner.bindIn(flow) {\n  button.isChecked = it\n}.bindOut(button) {\n  flow.value = it\n}\n```\n\nYou may also want to pass `Flow` to the `bindOut` function.\n```kotlin\nval flow = MutableStateFlow\u003cBoolean\u003e(false)\nval binding = viewLifecycleOwner.bindIn(flow) {\n  button.isChecked = it\n}.bindOut(button.checked()) {\n  flow.value = it\n}\n```\n\n## Report a bug or request a feature\n\nBefore creating a new issue please make sure that same or similar issue is not already created by checking [open issues][2] and [closed issues][3] *(please note that there might be multiple pages)*. If your issue is already there, don't create a new one, but leave a comment under already existing one.\n\nChecklist for creating issues:\n\n- Keep titles short but descriptive.\n- For feature requests leave a clear description about the feature with examples where appropriate.\n- For bug reports leave as much information as possible about your device, android version, etc.\n- For bug reports also write steps to reproduce the issue.\n\n[Create new issue][1]\n\n## Versioning\n\nFor transparency in a release cycle and in striving to maintain backward compatibility, a project should be maintained under the Semantic Versioning guidelines. Sometimes we screw up, but we should adhere to these rules whenever possible.\n\nReleases will be numbered with the following format: `\u003cmajor\u003e.\u003cminor\u003e.\u003cpatch\u003e` and constructed with the following guidelines:\n- Breaking backward compatibility bumps the major while resetting minor and patch\n- New additions without breaking backward compatibility bumps the minor while resetting the patch\n- Bug fixes and misc changes bumps only the patch\n\nFor more information on SemVer, please visit http://semver.org/.\n\n## Build\n\nClone the project and come in:\n\n``` bash\n$ git clone git://github.com/AChep/bindin.git\n$ cd bindin/\n$ ./gradlew assemble\n```\n\n[1]: https://github.com/AChep/bindin/issues/new\n[2]: https://github.com/AChep/bindin/issues?state=open\n[3]: https://github.com/AChep/bindin/issues?state=closed\n[4]: https://github.com/AChep/bindin/tree/master/sample\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachep%2Fbindin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fachep%2Fbindin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fachep%2Fbindin/lists"}