Skip to content

Commit df6b209

Browse files
Merge branch 'master' into coroutines_course_complete
# Conflicts: # app/src/test/java/com/lukaslechner/coroutineusecasesonandroid/usecases/coroutines/usecase4/VariableAmountOfNetworkRequestsViewModelTest.kt
2 parents 404263c + 7bbb4d6 commit df6b209

File tree

100 files changed

+1733
-391
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+1733
-391
lines changed

.github/workflows/build_and_test.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: Android Build and Test
2+
3+
on: [push,pull_request]
4+
5+
jobs:
6+
build:
7+
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- uses: actions/checkout@v1
12+
13+
- name: Set Up JDK
14+
uses: actions/setup-java@v1
15+
with:
16+
java-version: 1.8
17+
18+
- name: Run Tests
19+
run: ./gradlew test
20+
21+
- name: Build Project
22+
run: ./gradlew assemble

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ proguard/
3737
captures/
3838

3939
# IntelliJ
40+
/.idea/**/*
4041
*.iml
4142
.idea/workspace.xml
4243
.idea/tasks.xml

.idea/codeStyles/Project.xml

Lines changed: 0 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/runConfigurations.xml

Lines changed: 0 additions & 12 deletions
This file was deleted.

README.md

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,16 @@ Android version.
2323

2424
Unit Tests exist for most use cases.
2525

26+
## 🍿️ Related Videos
27+
* Kotlin Coroutines Fundamentals Playlist [[link](https://www.youtube.com/playlist?list=PL-1MzrWZIYU2a4TGbSXeXzfet8Br3cya1)]
28+
* Kotlin Coroutines Exception Handling explained [[link](https://youtu.be/Pgek3_3vPU8)]
29+
* How to avoid 5 common mistakes when using Kotlin Coroutines [[link](https://youtu.be/coq9XDMB-yU)]
30+
* Best Practices for using Kotlin Coroutines in Android Development [[link](https://youtu.be/tVDCpjqQ1Ro)]
31+
2632
## ✍️ Related blog posts
33+
* 7 Common Mistakes you might be making when using Kotlin Coroutines [[link](https://www.lukaslechner.com/7-common-mistakes-you-might-be-making-when-using-kotlin-coroutines/)]
2734
* Why exception handling with Kotlin Coroutines is so hard and how to successfully master it! [[link](https://www.lukaslechner.com/why-exception-handling-with-kotlin-coroutines-is-so-hard-and-how-to-successfully-master-it/)]
35+
* Kotlin Coroutines exception handling cheat sheet [[link](https://www.lukaslechner.com/coroutines-exception-handling-cheat-sheet/)]
2836
* Understanding Kotlin Coroutines with this mental model [[link](https://www.lukaslechner.com/understanding-kotlin-coroutines-with-this-mental-model/)]
2937
* Do I need to call suspend functions of Retrofit and Room on a background thread? [[link](https://www.lukaslechner.com/do-i-need-to-call-suspend-functions-of-retrofit-and-room-on-a-background-thread/)]
3038
* Comparing Kotlin Coroutines with Callbacks and RxJava [[link](https://www.lukaslechner.com/comparing-kotlin-coroutines-with-callbacks-and-rxjava/)]
@@ -34,9 +42,17 @@ Sign up to my [newsletter](https://www.lukaslechner.com/newsletter/) to never mi
3442

3543
## 🎓 Online Course
3644

37-
This project is the foundation of a comprehensive Online Course about "Mastering Kotlin Coroutines for Android Development",on which I am currently working on.
45+
This project is the foundation of a comprehensive Online Course about [Mastering Kotlin Coroutines for Android Development](https://www.udemy.com/course/coroutines-on-android/?referralCode=EE8CCB9284B14877724C)
46+
47+
[![CourseCoroutinesOnAndroid](documentation/images/course.png)](https://www.udemy.com/course/coroutines-on-android/?referralCode=EE8CCB9284B14877724C)
48+
49+
## 📢 Sharing is Caring
50+
51+
If you like this project, please tell other developers about it! ❤️
52+
53+
[![Share on Twitter](documentation/images/Twitter_bird_logo.png)](https://twitter.com/intent/tweet?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)
3854

39-
Sign up to my [newsletter](https://www.lukaslechner.com/newsletter/) to get more information once it is released!
55+
If you like, you can follow me on Twitter [**@LukasLechnerDev**](https://twitter.com/LukasLechnerDev).
4056

4157
## ⭐️ Use Cases
4258
1. [Perform single network request](#1-perform-single-network-request)
@@ -151,7 +167,7 @@ In the respective unit test, we have to pass the testDispatcher to the ViewModel
151167
### 11. Cooperative cancellation
152168

153169
UseCase#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
154-
memory leaks, as the calculation is not stopped and ViewModel is retained longer than necessary. This use case now fixes this issue. The UI now also has a "Cancel Calculation"
170+
memory 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"
155171
Button. Note: Only the calculation can be cancelled prematurely but not the `toString()` conversion.
156172

157173
There are several ways to make your coroutines cooperative regarding cancellation: You can use either use `isActive()`, `ensureActive()` or `yield()`.

app/build.gradle

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ apply plugin: 'kotlin-kapt'
44
apply plugin: 'kotlin-parcelize'
55

66
android {
7-
compileSdkVersion 29
7+
compileSdkVersion 32
88
buildToolsVersion "29.0.2"
99

1010
defaultConfig {
1111
applicationId "com.lukaslechner.coroutineusecasesonandroid"
1212
minSdkVersion 21
13-
targetSdkVersion 29
13+
targetSdkVersion 32
1414
versionCode 1
1515
versionName "1.0"
1616

@@ -37,59 +37,71 @@ android {
3737
jvmTarget = JavaVersion.VERSION_1_8.toString()
3838
}
3939

40+
compileOptions {
41+
// Flag to enable support for the new language APIs
42+
coreLibraryDesugaringEnabled = true
43+
// Sets Java compatibility to Java 8
44+
sourceCompatibility = JavaVersion.VERSION_1_8
45+
targetCompatibility = JavaVersion.VERSION_1_8
46+
}
47+
4048
}
4149

4250
dependencies {
4351

44-
def lifecycle_version = "2.2.0"
45-
def coroutines_version = "1.3.9"
52+
def lifecycle_version = "2.4.1"
53+
def coroutines_version = "1.6.3"
4654

4755
implementation fileTree(dir: 'libs', include: ['*.jar'])
4856
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
4957

5058
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
5159
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
5260

53-
implementation 'androidx.appcompat:appcompat:1.1.0'
54-
implementation 'com.google.android.material:material:1.1.0'
61+
implementation 'androidx.appcompat:appcompat:1.4.2'
62+
implementation 'com.google.android.material:material:1.6.1'
5563

56-
implementation 'androidx.core:core-ktx:1.2.0'
57-
implementation "androidx.activity:activity-ktx:1.1.0"
64+
implementation 'androidx.core:core-ktx:1.8.0'
65+
implementation "androidx.activity:activity-ktx:1.4.0"
5866

5967
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
60-
implementation 'androidx.recyclerview:recyclerview:1.1.0'
68+
implementation 'androidx.recyclerview:recyclerview:1.2.1'
6169
implementation 'androidx.cardview:cardview:1.0.0'
6270

6371
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
6472
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
6573

66-
implementation 'com.squareup.retrofit2:retrofit:2.7.1'
74+
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
6775
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.7.1'
68-
implementation 'com.google.code.gson:gson:2.8.6'
69-
implementation 'com.squareup.retrofit2:converter-gson:2.7.1'
76+
implementation 'com.google.code.gson:gson:2.8.9'
77+
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
7078

7179
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
7280
implementation 'io.reactivex.rxjava2:rxjava:2.2.19'
7381
implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0'
7482

7583
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
7684

77-
def work_manager_version = "2.3.4"
85+
def work_manager_version = "2.7.1"
7886
implementation "androidx.work:work-runtime:$work_manager_version"
7987
implementation "androidx.work:work-runtime-ktx:$work_manager_version"
8088

81-
implementation 'com.jakewharton.timber:timber:4.7.1'
89+
implementation 'com.jakewharton.timber:timber:5.0.1'
8290

8391
def room_version = "2.4.2"
8492
implementation "androidx.room:room-runtime:$room_version"
8593
implementation "androidx.room:room-ktx:$room_version"
8694
kapt "androidx.room:room-compiler:$room_version"
8795

88-
testImplementation 'junit:junit:4.12'
96+
testImplementation project(path: ':app')
97+
98+
testImplementation 'junit:junit:4.13.2'
8999
testImplementation 'androidx.arch.core:core-testing:2.1.0'
90100
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
91101
testImplementation 'com.squareup.retrofit2:retrofit-mock:2.7.1'
92102

93-
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
94-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
103+
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
104+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
105+
106+
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.5")
95107
}

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
android:supportsRtl="true"
1212
android:theme="@style/AppTheme">
1313

14-
<activity android:name=".MainActivity">
14+
<activity android:name=".MainActivity" android:exported="true">
1515
<intent-filter>
1616
<action android:name="android.intent.action.MAIN" />
1717
<category android:name="android.intent.category.LAUNCHER" />

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/base/UseCase.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import com.lukaslechner.coroutineusecasesonandroid.usecases.coroutines.usecase7.
2525
import com.lukaslechner.coroutineusecasesonandroid.usecases.coroutines.usecase8.RoomAndCoroutinesActivity
2626
import com.lukaslechner.coroutineusecasesonandroid.usecases.coroutines.usecase9.DebuggingCoroutinesActivity
2727
import com.lukaslechner.coroutineusecasesonandroid.usecases.flow.usecase1.FlowUseCase1Activity
28-
import kotlinx.android.parcel.Parcelize
28+
import kotlinx.parcelize.Parcelize
2929

3030
@Parcelize
3131
data class UseCase(
@@ -171,7 +171,7 @@ private val flowUseCases =
171171
)
172172

173173
val useCaseCategories = listOf(
174-
coroutinesUseCases /*,
175-
channelsUseCases,
176-
flowUseCases */
174+
coroutinesUseCases,
175+
// channelsUseCases,
176+
flowUseCases
177177
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.channels
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.GlobalScope
5+
import kotlinx.coroutines.channels.consumeEach
6+
import kotlinx.coroutines.channels.produce
7+
import kotlinx.coroutines.delay
8+
import kotlinx.coroutines.launch
9+
import kotlin.random.Random
10+
11+
12+
fun main() {
13+
GlobalScope.launch {
14+
produceRandom().consumeEach { println(it) }
15+
println("All values consumed")
16+
}
17+
18+
println("main() finished")
19+
Thread.sleep(1000)
20+
}
21+
22+
// whereas flow() is a top level function => produce is defined on CoroutineScope
23+
private fun CoroutineScope.produceRandom() = produce {
24+
repeat(5) {
25+
delay(100)
26+
send(Random.nextInt())
27+
}
28+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.lukaslechner.coroutineusecasesonandroid.playground.channels
2+
3+
import kotlinx.coroutines.CoroutineScope
4+
import kotlinx.coroutines.channels.consumeEach
5+
import kotlinx.coroutines.channels.produce
6+
import kotlinx.coroutines.delay
7+
import kotlinx.coroutines.runBlocking
8+
import kotlin.random.Random
9+
10+
fun main() = runBlocking {
11+
12+
val getRandomIntsChannel = generateRandom()
13+
14+
delay(500)
15+
16+
getRandomIntsChannel.consumeEach {
17+
// with offer, we will only consume 5-6 offered items
18+
println("Random number $it consumed")
19+
}
20+
21+
println("Done!")
22+
}
23+
24+
// Return Type is ReceiveChannel
25+
private fun CoroutineScope.generateRandom() = produce {
26+
repeat(10) {
27+
delay(100)
28+
29+
// emit in flows or send in channels will suspend until someone can receive the item
30+
// send(Random.nextInt())
31+
trySend(Random.nextInt())
32+
}
33+
}

0 commit comments

Comments
 (0)