[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-7406":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":19,"rankGlobal":10,"rankLanguage":10,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":23,"hasPages":21,"topics":24,"createdAt":10,"pushedAt":10,"updatedAt":34,"readmeContent":35,"aiSummary":36,"trendingCount":16,"starSnapshotCount":16,"syncStatus":37,"lastSyncTime":38,"discoverSource":39},7406,"Kotlin-Coroutines-and-Flow-UseCases-on-Android","LukasLechnerDev\u002FKotlin-Coroutines-and-Flow-UseCases-on-Android","LukasLechnerDev","🎓 Learning Kotlin Coroutines and Flows for Android by example. 🚀 Sample implementations for real-world Android use cases. 🛠 Unit tests included!","",null,"Kotlin",2873,476,85,3,0,1,5,61.04,"Apache License 2.0",false,"master",true,[25,26,27,28,29,30,31,32,33],"android","channels","coroutines","flow","kotlin","kotlin-channels","kotlin-coroutines","kotlin-flow","reactive","2026-06-12 04:00:33","![CoroutineUsecasesOnAndroid](documentation\u002Fimages\u002FLogo-new.png)\n\n# Kotlin Coroutines and Flow - Use Cases on Android\n\n🎓 Learning Kotlin Coroutines and Flows for Android Development by Example\n\n🚀 Sample implementations for real-world Android use cases \n\n🛠 Unit tests included!\n\nThis repository is intended to be a \"Playground Project\". You can quickly look up and play around with the different Coroutine and Flow Android implementations.\nIn the `playground` package you can play around with Coroutines and Flow examples that run directly on the JVM.\n\n## 🔧 Project Setup\n\nEvery use case is using its own `Activity` and `JetPack ViewModel`. The `ViewModel`s contain most of the interesting Coroutine-related code.\n`Activities` listen to `LiveData` or `StateFlow` events of the `ViewModel` and render received `UiState`s.\n\nThis project is using retrofit\u002Fokhttp together with a `MockNetworkInterceptor`. This lets you define how the API should behave.\nEverything can be configured: http status codes, response data and delays. Every use case defines a certain behaviour of the Mock API.\nThe API has 2 endpoints. One returns the names of the most recent Android versions and the other one returns the features of a certain\nAndroid version.\n\nUnit Tests exist for most use cases.\n\n## 🍿️ Related Videos\n* Kotlin Flow on Android Basics Playlist [[link](https:\u002F\u002Fyoutube.com\u002Fplaylist?list=PL-1MzrWZIYU3McdBOEic_1nsy8Rw48xIO)]\n* Kotlin Coroutines Fundamentals Playlist [[link](https:\u002F\u002Fwww.youtube.com\u002Fplaylist?list=PL-1MzrWZIYU2a4TGbSXeXzfet8Br3cya1)]\n* Kotlin Coroutines Exception Handling explained [[link](https:\u002F\u002Fyoutu.be\u002FPgek3_3vPU8)]\n* How to avoid 5 common mistakes when using Kotlin Coroutines [[link](https:\u002F\u002Fyoutu.be\u002Fcoq9XDMB-yU)]\n* Best Practices for using Kotlin Coroutines in Android Development [[link](https:\u002F\u002Fyoutu.be\u002FtVDCpjqQ1Ro)]\n\n## ✍️ Related blog posts\n* 7 Common Mistakes you might be making when using Kotlin Coroutines [[link](https:\u002F\u002Fwww.lukaslechner.com\u002F7-common-mistakes-you-might-be-making-when-using-kotlin-coroutines\u002F)]\n* Why exception handling with Kotlin Coroutines is so hard and how to successfully master it! [[link](https:\u002F\u002Fwww.lukaslechner.com\u002Fwhy-exception-handling-with-kotlin-coroutines-is-so-hard-and-how-to-successfully-master-it\u002F)]\n* Kotlin Coroutines exception handling cheat sheet [[link](https:\u002F\u002Fwww.lukaslechner.com\u002Fcoroutines-exception-handling-cheat-sheet\u002F)]\n* Understanding Kotlin Coroutines with this mental model [[link](https:\u002F\u002Fwww.lukaslechner.com\u002Funderstanding-kotlin-coroutines-with-this-mental-model\u002F)]\n* Do I need to call suspend functions of Retrofit and Room on a background thread? [[link](https:\u002F\u002Fwww.lukaslechner.com\u002Fdo-i-need-to-call-suspend-functions-of-retrofit-and-room-on-a-background-thread\u002F)]\n* Comparing Kotlin Coroutines with Callbacks and RxJava [[link](https:\u002F\u002Fwww.lukaslechner.com\u002Fcomparing-kotlin-coroutines-with-callbacks-and-rxjava\u002F)]\n* How to run an expensive calculation with Kotlin Coroutines on the Android Main Thread without freezing the UI [[link](https:\u002F\u002Fwww.lukaslechner.com\u002Fhow-to-run-an-expensive-calculation-with-kotlin-coroutines-on-the-android-main-thread-without-freezing-the-ui\u002F)]\n\nSign up to my [newsletter](https:\u002F\u002Fwww.lukaslechner.com\u002Fnewsletter\u002F) to never miss new content. I will publish new blog posts and videos about Coroutines and Flow on a regular basis.\n\n## 🎓 Online Course\n\nThis project is the foundation of a comprehensive Online Course about [Kotlin Coroutines and Flow for Android Development](https:\u002F\u002Flukaslechner.com\u002Fcoroutines-flow-android?source=github)\nIn the course, we are going to implement the use cases of this repository together, as well as talk about all the necessary concepts that you need to know. \n\n[![CourseCoroutinesOnAndroid](documentation\u002Fimages\u002Fcourse.png)](https:\u002F\u002Flukaslechner.com\u002Fcoroutines-flow-android?source=github)\n\n## 📢 Sharing is Caring \n\nIf you like this project, please tell other developers about it! ❤️\n\n[![Share on Twitter](documentation\u002Fimages\u002FTwitter_bird_logo.png)](https:\u002F\u002Ftwitter.com\u002Fintent\u002Ftweet?url=https%3A%2F%2Fgithub.com%2FLukasLechnerDev%2FKotlin-Coroutine-Use-Cases-on-Android&text=This%20awesome%20example%20project%20shows%20how%20to%20implement%20the%20most%20common%20use%20cases%20for%20using%20Kotlin%20Coroutines%20for%20Android%20Development%21%20By%20@LukasLechnerDev&hashtags=%23AndroidDev%20%23Kotlin%20%23Coroutines)\n\nIf you like, you can follow me on Twitter [**@LukasLechnerDev**](https:\u002F\u002Ftwitter.com\u002FLukasLechnerDev).\n\n## ⭐️ Coroutine Use Cases\n1. [Perform single network request](#1-perform-single-network-request)\n2. [Perform two sequential network requests](#2-perform-two-sequential-network-requests)\n3. [Perform several network requests concurrently](#3-perform-several-network-requests-concurrently)\n4. [Perform variable amount of network requests](#4-perform-variable-amount-of-network-requests)\n5. [Perform a network request with timeout](#5-perform-network-request-with-timeout)\n6. [Retrying network requests](#6-retrying-network-requests)\n7. [Network requests with timeout and retry](#7-network-requests-with-timeout-and-retry)\n8. [Room and Coroutines](#8-room-and-coroutines)\n9. [Debugging Coroutines](#9-debugging-coroutines)\n10. [Offload expensive calculation to background thread](#10-offload-expensive-calculation-to-background-thread)\n11. [Cooperative Cancellation](#11-cooperative-cancellation)\n12. [Offload expensive calculation to several Coroutines](#12-offload-expensive-calculation-to-several-coroutines)\n13. [Exception Handling](#13-exception-handling)\n14. [Continue Coroutine execution even when the user leaves the screen](#14-continue-coroutine-execution-when-the-user-leaves-the-screen)\n15. [Using WorkManager with Coroutines](#15-using-workmanager-with-coroutines)\n16. [Performance analysis of dispatchers, number of coroutines and yielding](#16-performance-analysis-of-dispatchers-number-of-coroutines-and-yielding)\n17. [Perform expensive calculation on Main Thread without freezing the UI](#17-perform-expensive-calculation-on-main-thread-without-freezing-the-ui)\n\n## ⭐ Flow Use Cases\n1. [Flow Basics](#1-flow-basics)\n2. [Basic Flow intermediate operators](#2-basic-flow-intermediate-operators)\n3. [Flow Exception Handling](#3-flow-exception-handling)\n4. [Exposing Flows in the ViewModel](#4-exposing-flows-in-the-viewmodel)\n\n## 📄 Coroutine Use Cases Description\n\n### 1. Perform single network request\n\nThis use case performs a single network request to get the latest Android Versions and displays them on the screen.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase1\u002FPerformSingleNetworkRequestViewModel.kt)]\n\n### 2. Perform two sequential network requests\n\nThis use case performs two network requests sequentially. First, it retrieves recent Android Versions and then it requests the features of the latest version.\n\nThere are also 2 alternative implementations included. One is using old-school [callbacks](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase2\u002Fcallbacks\u002FSequentialNetworkRequestsCallbacksViewModel.kt).\nThe other one uses [RxJava](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase2\u002Frx\u002FSequentialNetworkRequestsRxViewModel.kt). You can compare each implementation.\nIf you compare all three implementations, it is really interesting to see, in my opinion, how simple the Coroutine-based version actually is.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase2\u002FPerform2SequentialNetworkRequestsViewModel.kt)]\n\n### 3. Perform several network requests concurrently\n\nPerforms three network requests concurrently. It loads the feature information of the 3 most recent Android Versions. Additionally, an implementation\nthat performs the requests sequentially is included. The UI shows how much time each implementation takes to load the data so you can see that the network\nrequests in the concurrent version are indeed performed in parallel. The included unit test is also interesting, as it shows how you can use virtual time to\nverify that the concurrent version gets performed in parallel.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase3\u002FPerformNetworkRequestsConcurrentlyViewModel.kt)]\n\n### 4. Perform variable amount of network requests\n\nDemonstrates the simple usage of `map()` to perform a dynamic amount of network requests. At first, this use case performs a network request to load all Android versions.\nThen it performs a network request for each Android version to load its features. It contains an implementation that performs the network requests sequentially and another one that performs them concurrently.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase4\u002FVariableAmountOfNetworkRequestsViewModel.kt)]\n\n### 5. Perform network request with timeout\n\nThis use case uses the suspending function `withTimeout()` from the coroutines-core library. It throws a `TimeoutCancellationException` if the timeout was exceeded.\nYou can set the duration of the request in the UI and check the behaviour when the response time is bigger than the timeout.\n\nGeneral networking timeouts can also be [configured in the okhttp client](https:\u002F\u002Fsquare.github.io\u002Fokhttp\u002Frecipes\u002F#timeouts-kt-java).\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase5\u002FNetworkRequestWithTimeoutViewModel.kt)]\n\n### 6. Retrying network requests\n\nDemonstrates the usage of higher-order functions together with coroutines. The higher-order function `retry()` retries a certain suspending operation for a given amount of times.\nIt uses an exponential backoff for retries, which means that the delay between retries increases exponentially. The behavior of the Mock API is defined in a way that it responses\nwith 2 unsuccessful responses followed by a successful response.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase6\u002FRetryNetworkRequestViewModel.kt)]\n\nUnit tests verify the amount of requests that are performed in different scenarios. Furthermore, they check if the exponential backoff is working properly\nby asserting the amount of elapsed virtual time.\n\n### 7. Network requests with timeout and retry\n\nComposes higher level functions `retry()` and `withTimeout()`. Demonstrates how simple and readable code written with Coroutines can be.\nThe mock API first responds after the timeout and then returns an unsuccessful response. The third attempt is then successful.\n\nTake a look at the included [callback-based implementation](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase7\u002Fcallbacks\u002FTimeoutAndRetryCallbackViewModel.kt) to see how tricky this use case is to implement without Coroutines.\n\nI also implemented the use case with [RxJava](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase7\u002Frx\u002FTimeoutAndRetryRxViewModel.kt).\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase7\u002FTimeoutAndRetryViewModel.kt)]\n\n### 8. Room and Coroutines\n\nThis example stores the response data of each network request in a Room database. This is essential for any \"offline-first\" app.\nIf the `View` requests data, the `ViewModel` first checks if there is data available in the database. If so, this data is returned before performing\na network request to get fresh data.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase8\u002FRoomAndCoroutinesViewModel.kt)]\n\n### 9. Debugging Coroutines\n\nThis is not really a use case, but I wanted to show how you can add additional debug information about the Coroutine that is currently running to your logs.\nIt will add the Coroutine name next to the thread name when calling `Thread.currentThread.name()`\nThis is done by enabling Coroutine Debug mode by setting the property `kotlinx.coroutines.debug` to `true`.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase9\u002FDebuggingCoroutinesViewModel.kt)]\n\n### 10. Offload expensive calculation to background thread\n\nThis use case calculates the factorial of a number. The calculation is performed on a background thread using the default Dispatcher.\n\n**Attention: This use case does not support cancellation! UseCase#11 fixes this!**\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase10\u002FCalculationInBackgroundViewModel.kt)]\n\nIn the respective unit test, we have to pass the testDispatcher to the ViewModel, so that the calculation is not performed on a background thread but on the main thread.\n\n### 11. Cooperative cancellation\n\nUseCase#10 has a problem. It is not able to prematurely cancel the calculation because it is not cooperative regarding cancellation. This leads to wasted device resources and\nmemory leaks, as the calculation is not stopped and the ViewModel is retained longer than necessary. This use case now fixes this issue. The UI now also has a \"Cancel Calculation\"\nButton. Note: Only the calculation can be canceled prematurely but not the `toString()` conversion.\n\nThere are several ways to make your coroutines cooperative regarding cancellation: You can use either use `isActive()`, `ensureActive()` or `yield()`.\nMore information about cancellation can be found [here](https:\u002F\u002Fmedium.com\u002Fandroiddevelopers\u002Fexceptions-in-coroutines-ce8da1ec060c)\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase11\u002FCooperativeCancellationViewModel.kt)]\n\n### 12. Offload expensive calculation to several Coroutines\n\nThe factorial calculation here is not performed by a single coroutine, but by a number of coroutines that can be defined in the UI. Each coroutine calculates the factorial of a sub-range.\n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase12\u002FCalculationInSeveralCoroutinesViewModel.kt)]\n[[code factorial calculator](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase12\u002FFactorialCalculator.kt)]\n\n### 13. Exception Handling\n\nThis use case demonstrates different ways of handling exceptions using `try\u002Fcatch` and `CoroutineExceptionHandler`. It also demonstrates when you should use `supervisorScope{}`: In situations when you don't want a failing coroutine to cancel\nits sibling coroutines. In one implementation of this use case, the results of the successful responses are shown even though one response wasn't successful.\n\n[[code](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase13\u002FExceptionHandlingViewModel.kt)]\n\n### 14. Continue Coroutine execution when the user leaves the screen\n\nUsually, when the user leaves the screen, the `ViewModel` gets cleared and all the coroutines launched in `viewModelScope` get canceled. Sometimes, however, we want a certain coroutine operation to be continued\nwhen the user leaves the screen. In this use case, the network request keeps running and the results still get inserted into the database\ncache when the user leaves the screen. This makes sense in real-world applications as we don't want to cancel an already started background \"cache sync\".\n\n\nYou can test this behavior in the UI by clearing the database, then loading the Android version and instantly closing the screen. You will see in LogCat that the response\nstill gets executed and the result still gets stored. The respective unit test `AndroidVersionRepositoryTest` also verifies this behavior. Check out this [blogpost](https:\u002F\u002Fmedium.com\u002Fandroiddevelopers\u002Fcoroutines-patterns-for-work-that-shouldnt-be-cancelled-e26c40f142ad) for details of the implementation.\n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase14\u002FContinueCoroutineWhenUserLeavesScreenViewModel.kt)]\n[[code repository](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase14\u002FAndroidVersionRepository.kt)]\n\n### 15. Using WorkManager with Coroutines\n\nDemonstrates how you can use WorkManager together with Coroutines. When creating a subclass of `CoroutineWorker` instead of `Worker`,\nthe `doWork()` function is now a `suspend function` which means that we can now call other suspend functions. In this\nexample, we are sending an analytics request when the user enters the screen, which is a nice use case for using WorkManager.\n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase15\u002FWorkManagerViewModel.kt)]\n[[code worker](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fcoroutines\u002Fusecase15\u002FAnalyticsWorker.kt)]\n\n\n### 16. Performance analysis of dispatchers, number of coroutines and yielding\n\nThis is an extension of use case #12 (Offload expensive calculation to several coroutines). Here it is possible to additionally define the dispatcher type you want\nthe calculation to be performed on. Additionally, you can enable or disable the call to `yield()` during the calculation. A list of calculations is displayed on the bottom in order to be able to compare them in a convenient way.\n\n### 17. Perform expensive calculation on Main Thread without freezing the UI\n\nThis example shows how you can perform an expensive calculation on the main thread in a non-blocking fashion. It uses `yield()` for every step in the calculation so that other work, like drawing the UI, can be performed\non the main thread. It is more a \"showcase\" rather than a use case for a real application, because of performance reasons you should always perform expensive calculations on a background thread (See UseCase#10).\nSee [[this blog post](https:\u002F\u002Fwww.lukaslechner.com\u002Fhow-to-run-an-expensive-calculation-with-kotlin-coroutines-on-the-android-main-thread-without-freezing-the-ui\u002F)] for more information!\n\n\nYou can play around and check the performance of different configurations!\n\n## 📄 Flow Use Cases Description\n\n### 1. Flow Basics\n\nThis simple use case shows how to consume values from a `DataSource` that emits live stock information and how to display them in the UI. \n\nThe datasource exposes a `Flow` which is built with the `flow{}` flow builder. It fetches fresh stock information every 5 seconds from a mocked endpoint. \n\nA `LiveData` property that exposes the `UiState` in the `ViewModel` is created by using the `.asLiveData()` terminal operator.\nThis use case also shows how to use the `map` intermediate operator and the `onStart` lifecycle operator. \n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase1\u002FFlowUseCase1ViewModel.kt)]\n[[code datasource](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase1\u002FStockPriceDataSource.kt)]\n\n### 2. Basic Flow Intermediate Operators\n\nThe second use case is an extension of the first one. \nIt uses some basic intermediate operators, like `withIndex`, `map`, `take` and `filter`.\n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase2\u002FFlowUseCase2ViewModel.kt)]\n[[code datasource](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase2\u002FStockPriceDataSource.kt)]\n\n### 3. Flow Exception Handling\n\nThe third use case shows how to properly implement exception handling with flows. \n\nIt uses the `catch` operator to handle exceptions of our flow in the `ViewModel` and uses the `retry ` operator to retry failed network requests in the `DataSource`.\n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase3\u002FFlowUseCase3ViewModel.kt)]\n[[code datasource](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase3\u002FStockPriceDataSource.kt)]\n\n### 4. Exposing Flows in the ViewModel\n\nThis use case shows how to expose flows (a `StateFlow` to be precise) in the `ViewModel` instead of a `LiveData` property. \nThe `statIn` operator is used to convert the ordinary, cold `Flow` into a hot `StateFlow`.\n\nIn the `Activity`, the `repeadOnLifecycle` suspend function is used to collect emissions of the `StateFlow` in a lifecycle-aware manner. \n\n[[code viewmodel](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase4\u002FFlowUseCase4ViewModel.kt)]\n[[code datasource](app\u002Fsrc\u002Fmain\u002Fjava\u002Fcom\u002Flukaslechner\u002Fcoroutineusecasesonandroid\u002Fusecases\u002Fflow\u002Fusecase4\u002FStockPriceDataSource.kt)]\n\n## Author\n\n![LukasLechner](documentation\u002Fimages\u002Flukle.png)\n\n[Lukas Lechner](https:\u002F\u002Fwww.lukaslechner.com)\n\n[Twitter](https:\u002F\u002Ftwitter.com\u002FLukasLechnerDev) \n\n## License\n\nLicensed under the Apache License, Version 2.0 (the \"License\").\nYou may obtain a copy of the License at\n\n   http:\u002F\u002Fwww.apache.org\u002Flicenses\u002FLICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\nYou agree that all contributions to this repository, in the form of fixes, pull-requests, new examples etc. follow the above-mentioned license.\n","该项目通过实例展示了如何在Android开发中使用Kotlin协程和Flow。它提供了多种真实场景下的示例实现，包括网络请求、数据处理等，并且每个用例都配备了单元测试。项目采用JetPack ViewModel架构模式，使得UI状态管理和业务逻辑分离更加清晰。此外，还利用Retrofit\u002FOkHttp配合MockNetworkInterceptor来模拟API行为，便于开发者学习和调试。此资源非常适合希望深入了解Kotlin并发编程特性的Android开发者，尤其是在处理异步操作和流式数据时寻找最佳实践的学习者。",2,"2026-06-11 03:12:08","top_language"]