Skip to content

Commit fe901e6

Browse files
Merge pull request #4 from oiyio/master
added sequence, channels, flow samples
2 parents f177ecd + bad6b20 commit fe901e6

File tree

57 files changed

+827
-153
lines changed

Some content is hidden

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

57 files changed

+827
-153
lines changed

Tutorial1-1CoroutinesBasics/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,4 +161,5 @@ dependencies {
161161
// Espresso
162162
androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
163163

164+
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
164165
}

Tutorial1-1CoroutinesBasics/src/main/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.smarttoolfactory.tutorial1_1basics">
44

5-
<uses-permission android:name="android.permission.INTERNET"/>
5+
<uses-permission android:name="android.permission.INTERNET" />
66

77
<application
88
android:allowBackup="true"
@@ -22,6 +22,7 @@
2222
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter1_basics.Activity1Basics" />
2323
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter2_scopes.Activity2CoroutineScope"/>
2424
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter3_lifecycle.Activity3CoroutineLifecycle" />
25+
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter3_lifecycle.Activity3LifecycleScope" />
2526
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter4_supervisorjob.Activity4SupervisorJob" />
2627
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter5_viewmodel.Activity5ViewModelScope" />
2728
<activity android:name="com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter5_viewmodel.Activity5ViewModelRxJava" />

Tutorial1-1CoroutinesBasics/src/main/java/com/smarttoolfactory/tutorial1_1coroutinesbasics/MainActivity.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import com.smarttoolfactory.tutorial1_1coroutinesbasics.adapter.ChapterSelection
1414
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter1_basics.Activity1Basics
1515
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter2_scopes.Activity2CoroutineScope
1616
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter3_lifecycle.Activity3CoroutineLifecycle
17+
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter3_lifecycle.Activity3LifecycleScope
1718
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter4_supervisorjob.Activity4SupervisorJob
1819
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter5_viewmodel.Activity5ViewModelRxJava
1920
import com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter5_viewmodel.Activity5ViewModelScope
@@ -42,6 +43,7 @@ class MainActivity : AppCompatActivity(), BaseAdapter.OnRecyclerViewItemClickLis
4243
activityClassModels.add(ActivityClassModel(Activity1Basics::class.java))
4344
activityClassModels.add(ActivityClassModel(Activity2CoroutineScope::class.java))
4445
activityClassModels.add(ActivityClassModel(Activity3CoroutineLifecycle::class.java))
46+
activityClassModels.add(ActivityClassModel(Activity3LifecycleScope::class.java))
4547
activityClassModels.add(ActivityClassModel(Activity4SupervisorJob::class.java))
4648
activityClassModels.add(ActivityClassModel(Activity5ViewModelScope::class.java))
4749
activityClassModels.add(ActivityClassModel(Activity5ViewModelRxJava::class.java))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package com.smarttoolfactory.tutorial1_1coroutinesbasics.chapter3_lifecycle
2+
3+
import android.os.Bundle
4+
import android.widget.Toast
5+
import androidx.appcompat.app.AlertDialog
6+
import androidx.appcompat.app.AppCompatActivity
7+
import androidx.lifecycle.lifecycleScope
8+
import com.smarttoolfactory.tutorial1_1basics.R
9+
import com.smarttoolfactory.tutorial1_1basics.databinding.Activity3LifecycleScopeBinding
10+
import com.smarttoolfactory.tutorial1_1coroutinesbasics.util.dataBinding
11+
import kotlinx.coroutines.delay
12+
import kotlinx.coroutines.launch
13+
14+
/*
15+
lifecycleScope.launch{} is an alternatie to Handler().postDelayed()
16+
17+
activity.lifecycleScope.launch {
18+
// scope bound to Activity Lifecycle
19+
}
20+
fragment.lifecycleScope.launch {
21+
// scope bound to Fragment Lifecycle
22+
}
23+
fragment.viewLifecycleOwner.launch{
24+
// scope bound to Fragment View
25+
}
26+
27+
Be aware that lifecycleScope is convenient when dealing with UI events like, for example, showing a tip for the user and hiding it after a small delay.
28+
lifecycleScope.launch {
29+
delay(5000)
30+
showTip()
31+
delay(5000)
32+
hideTip()
33+
}
34+
35+
Without using Coroutines and lifecycleScope, this would be:
36+
val DELAY = 5000
37+
Handler().postDelayed({
38+
showTip()
39+
Handler().postDelayed({
40+
hideTip()
41+
}, DELAY)
42+
}, DELAY)
43+
44+
LifecycleScope is bound to Dispatcher.Main. That means if you don’t change Dispatcher explicitly all the coroutines inside LifecycleScope will be executed on the main thread.
45+
46+
https://medium.com/corouteam/exploring-kotlin-coroutines-and-lifecycle-architectural-components-integration-on-android-c63bb8a9156f
47+
https://android.jlelse.eu/coroutine-in-android-working-with-lifecycle-fc9c1a31e5f3
48+
https://kotlin.christmas/2019/13
49+
* */
50+
51+
class Activity3LifecycleScope : AppCompatActivity(R.layout.activity3_lifecycle_scope) {
52+
53+
private val binding: Activity3LifecycleScopeBinding by dataBinding()
54+
55+
override fun onCreate(savedInstanceState: Bundle?) {
56+
super.onCreate(savedInstanceState)
57+
58+
val builder = AlertDialog.Builder(this)
59+
builder.setMessage("Mesajj")
60+
builder.setTitle("Titlee")
61+
val alertDialog = builder.create()
62+
63+
64+
binding.button1.setOnClickListener {
65+
binding.textViewResult.text = binding.textViewResult.text.toString() + "Clicked\n"
66+
lifecycleScope.launch {
67+
68+
binding.textViewResult.text =
69+
binding.textViewResult.text.toString() + "🤓 Delay 5 sn before showing dialog\n"
70+
delay(5000)
71+
72+
alertDialog.show()
73+
74+
binding.textViewResult.text =
75+
binding.textViewResult.text.toString() + "🥳 Delay 5 sn after showing dialog\n"
76+
delay(5000)
77+
78+
binding.textViewResult.text =
79+
binding.textViewResult.text.toString() + "Dismissed AlertDialog \n"
80+
Toast.makeText(baseContext, "Dismissed AlertDialog", Toast.LENGTH_SHORT).show()
81+
alertDialog.dismiss()
82+
}
83+
binding.textViewResult.text =
84+
binding.textViewResult.text.toString() + "🚗🚗🚗 Codes after lifecycleScope \n"
85+
}
86+
87+
}
88+
}

Tutorial1-1CoroutinesBasics/src/main/java/com/smarttoolfactory/tutorial1_1coroutinesbasics/chapter5_viewmodel/CoroutinesViewModel.kt

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,24 @@ class CoroutinesViewModel(private val viewModelDispatcher: CoroutineDispatcher)
4444

4545
fun getMockResult(timeMillis: Long = 2000) {
4646

47-
println("getMockResult() loading...")
47+
println("1 - getMockResult() loading...")
4848
result.value = "Loading..."
4949
enableResultButton.value = false
5050

5151
viewModelScope.launch {
5252

53-
println("🙄 getMockResult() START ViewModel scope: $this, thread: ${Thread.currentThread().name}")
53+
println("🙄 2 - getMockResult() START ViewModel scope: $this, thread: ${Thread.currentThread().name}")
5454

55-
result.value = generateMockNetworkResponseOrThrowException(timeMillis)
55+
result.value = generateMockNetworkResponseOrThrowException(timeMillis) // 4
5656
enableResultButton.value = true
5757

58-
println("getMockResult() ViewModel scope AFTER generateMockNetworkResponse() ${result.value}")
58+
println("5 - getMockResult() ViewModel scope AFTER generateMockNetworkResponse() ${result.value}")
5959

6060
}
6161

62-
println("getMockResult() END OF FUN")
62+
println("3 - getMockResult() END OF FUN")
6363

64-
/*
64+
/* 1 2 4 3 5
6565
Prints:
6666
I: getMockResult() loading...
6767
I: 🙄 getMockResult() ViewModel scope: StandaloneCoroutine{Active}@ef7c60d, thread: main
@@ -72,55 +72,45 @@ class CoroutinesViewModel(private val viewModelDispatcher: CoroutineDispatcher)
7272

7373
}
7474

75-
76-
/**
77-
* This method is for Unit-Testing exceptions
75+
/*
76+
Mock Response Functions
7877
*/
79-
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
80-
fun throwExceptionInAScope(coroutineContext: CoroutineContext) {
81-
82-
println("getMockResult() loading...")
8378

84-
// 🔥🔥
85-
viewModelScope.launch(coroutineContext) {
86-
87-
println("🙄 getMockResult() START ViewModel scope: $this, thread: ${Thread.currentThread().name}")
88-
89-
delay(2000)
90-
throw RuntimeException("Exception Occurred")
79+
private suspend fun generateMockNetworkResponseOrThrowException(timeMillis: Long = 2000): String {
9180

92-
}
81+
println("🥶 4 - generateMockNetworkResponse() thread: ${Thread.currentThread().name}")
9382

94-
println("getMockResult() END OF FUN")
83+
delay(timeMillis)
9584

85+
if (timeMillis > 2000) throw RuntimeException("Threw Network Exception")
9686

87+
return "Hello World"
9788
}
9889

99-
10090
fun getMockResultFromDispatcherThread(timeMillis: Long) {
10191

102-
println("getMockResult() loading...")
92+
println("1 - getMockResult() loading...")
10393
result.value = "Loading..."
10494
enableResultButton.value = false
10595

10696
viewModelScope.launch(Dispatchers.Default) {
10797

108-
println("🙄 getMockResult() ViewModel scope: $this, thread: ${Thread.currentThread().name}")
98+
println("🙄 3 - getMockResult() ViewModel scope: $this, thread: ${Thread.currentThread().name}")
10999

110100
withContext(Dispatchers.Main) {
111-
result.value = generateMockNetworkResponseOrThrowException(timeMillis)
101+
result.value = generateMockNetworkResponseOrThrowException(timeMillis) // 4
112102
enableResultButton.value = true
113103

114104
}
115105

116-
println("getMockResult() ViewModel scope AFTER")
106+
println("5 - getMockResult() ViewModel scope AFTER")
117107

118108
}
119109

120-
println("getMockResult() END OF FUN")
110+
println("2 - getMockResult() END OF FUN")
121111

122112
/*
123-
Prints:
113+
Prints: 1 3 2 4 5 or 1 2 3 4 5
124114
125115
*/
126116

@@ -155,9 +145,9 @@ class CoroutinesViewModel(private val viewModelDispatcher: CoroutineDispatcher)
155145
// longer than 2000 ms
156146
resultWithTimeout.value = generateMockNetworkResponseOrThrowException()
157147
} catch (exception: TimeoutCancellationException) {
158-
resultWithTimeout.value = exception.message
148+
resultWithTimeout.value = "1 - " + exception.message
159149
} catch (exception: Exception) {
160-
resultWithTimeout.value = exception.message
150+
resultWithTimeout.value = "2 - " + exception.message
161151
}
162152

163153
}
@@ -283,21 +273,6 @@ class CoroutinesViewModel(private val viewModelDispatcher: CoroutineDispatcher)
283273

284274
}
285275

286-
/*
287-
Mock Response Functions
288-
*/
289-
290-
private suspend fun generateMockNetworkResponseOrThrowException(timeMillis: Long = 2000): String {
291-
292-
println("🥶 generateMockNetworkResponse() thread: ${Thread.currentThread().name}")
293-
294-
delay(timeMillis)
295-
296-
if (timeMillis > 2000) throw RuntimeException("Threw Network Exception")
297-
298-
return "Hello World"
299-
}
300-
301276
private suspend fun generateRandomCity(): String {
302277
val cityList = listOf("Berlin", "New York", "London", "Paris", "Istanbul")
303278

@@ -317,6 +292,27 @@ class CoroutinesViewModel(private val viewModelDispatcher: CoroutineDispatcher)
317292

318293
}
319294

295+
/**
296+
* This method is for Unit-Testing exceptions
297+
*/
298+
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
299+
fun throwExceptionInAScope(coroutineContext: CoroutineContext) {
300+
301+
println("getMockResult() loading...")
302+
303+
// 🔥🔥
304+
viewModelScope.launch(coroutineContext) {
305+
306+
println("🙄 getMockResult() START ViewModel scope: $this, thread: ${Thread.currentThread().name}")
307+
308+
delay(2000)
309+
throw RuntimeException("Exception Occurred")
310+
311+
}
312+
313+
println("getMockResult() END OF FUN")
314+
315+
}
320316
}
321317

322318
class CoroutinesViewModelFactory :
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2016-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
// This file was automatically generated from channels.md by Knit tool. Do not edit.
6+
package com.smarttoolfactory.tutorial1_1coroutinesbasics.playground
7+
8+
import kotlinx.coroutines.channels.Channel
9+
import kotlinx.coroutines.launch
10+
import kotlinx.coroutines.runBlocking
11+
12+
/*
13+
Rendezvous channel example
14+
*/
15+
16+
17+
fun main() = runBlocking {
18+
val channel = Channel<String>()
19+
20+
launch {
21+
println("Sending A1")
22+
channel.send("A1")
23+
println("Sending A2")
24+
channel.send("A2")
25+
println("A done")
26+
}
27+
28+
launch {
29+
println("Sending B1")
30+
channel.send("B1")
31+
println("B done")
32+
}
33+
34+
launch {
35+
repeat(3) {
36+
println("Calling receive()")
37+
val x = channel.receive()
38+
println("receive is done $x")
39+
}
40+
}
41+
42+
println("Done!")
43+
}
44+
45+
/*
46+
* Output :
47+
48+
Done!
49+
Sending A1
50+
Sending B1
51+
Calling receive()
52+
receive is done A1
53+
Calling receive()
54+
receive is done B1
55+
Calling receive()
56+
Sending A2
57+
A done
58+
B done
59+
receive is done A2
60+
61+
* */
Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,26 @@
66
package com.smarttoolfactory.tutorial1_1coroutinesbasics.playground
77

88
import kotlinx.coroutines.channels.Channel
9+
import kotlinx.coroutines.delay
910
import kotlinx.coroutines.launch
1011
import kotlinx.coroutines.runBlocking
1112

12-
fun main() = runBlocking {
13+
fun main() = runBlocking { // coroutine 1
14+
1315
val channel = Channel<Int>()
14-
launch {
16+
launch { // coroutine 2
1517
// this might be heavy CPU-consuming computation or async logic, we'll just send five squares
16-
for (x in 1..5) channel.send(x * x)
18+
for (x in 1..5) {
19+
println("send $x ")
20+
channel.send(x * x)
21+
}
22+
1723
}
1824
// here we print five received integers:
19-
repeat(5) { println(channel.receive()) }
25+
repeat(5) {
26+
delay(3000)
27+
println(channel.receive())
28+
}
2029
println("Done!")
2130
}
31+

0 commit comments

Comments
 (0)