From babda2da273bc134d83a992e7a86cbfec7ac68d9 Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Fri, 26 Jul 2019 08:35:28 -0700 Subject: [PATCH 01/10] how to measure job time --- .../coroutineexamples/MainActivity.kt | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt index ac6828a..25ac26c 100644 --- a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt +++ b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt @@ -6,10 +6,12 @@ import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.Main +import kotlin.system.measureTimeMillis class MainActivity : AppCompatActivity() { + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -18,10 +20,11 @@ class MainActivity : AppCompatActivity() { setNewText("Click!") CoroutineScope(IO).launch { + println("debug: CoroutineScope") fakeApiRequest() } } - + } private fun setNewText(input: String){ @@ -34,33 +37,45 @@ class MainActivity : AppCompatActivity() { } } + /** + * Job1 and Job2 run in parallel as different coroutines + */ private suspend fun fakeApiRequest() { coroutineScope { - launch { - - val result1 = getResult1FromApi() // wait until job is done + val parentJob = launch { - if ( result1.equals("Result #1")) { - - setTextOnMainThread("Got $result1") - - val result2 = getResult2FromApi() // wait until job is done + val executionTime = measureTimeMillis { + val job1 = launch { + println("debug: launching job1 in thread: ${Thread.currentThread().name}") + val result1 = getResult1FromApi() + setTextOnMainThread("Got $result1") + } + job1.join() // join job1 to parent job (blocking until completion) - if (result2.equals("Result #2")) { + val job2 = launch { + println("debug: launching job2 in thread: ${Thread.currentThread().name}") + val result2 = getResult2FromApi() setTextOnMainThread("Got $result2") - } else { - setTextOnMainThread("Couldn't get Result #2") } - } else { - setTextOnMainThread("Couldn't get Result #1") + job2.join() // join job2 to parent job (blocking until completion) } + println("debug: job1 and job2 are complete. It took ${executionTime} ms") + } + // Separate job within the same coroutine context that runs independently of parentJob, Job1 and Job2 + launch { + for(delay in arrayOf(1, 2, 3, 4, 5, 6)){ + delay(500) + println("debug: is parent job active?: ${parentJob.isActive}") + } + } + + } } - private suspend fun getResult1FromApi(): String { delay(1000) // Does not block thread. Just suspends the coroutine inside the thread return "Result #1" From 9a16e1fbb46b71b75686fe9c3ce63ea47449e79c Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Fri, 26 Jul 2019 08:43:13 -0700 Subject: [PATCH 02/10] measure job time --- .../java/com/codingwithmitch/coroutineexamples/MainActivity.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt index 25ac26c..a632b46 100644 --- a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt +++ b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt @@ -37,9 +37,6 @@ class MainActivity : AppCompatActivity() { } } - /** - * Job1 and Job2 run in parallel as different coroutines - */ private suspend fun fakeApiRequest() { coroutineScope { From 15de7ae1726d75fee5700340c6592f18647e394b Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Sat, 27 Jul 2019 13:44:33 -0700 Subject: [PATCH 03/10] parallal coroutine jobs (example 2) --- .../coroutineexamples/MainActivity.kt | 99 +++++++++++-------- 1 file changed, 56 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt index a632b46..6788454 100644 --- a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt +++ b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt @@ -5,7 +5,6 @@ import android.os.Bundle import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO -import kotlinx.coroutines.Dispatchers.Main import kotlin.system.measureTimeMillis @@ -21,8 +20,10 @@ class MainActivity : AppCompatActivity() { CoroutineScope(IO).launch { println("debug: CoroutineScope") - fakeApiRequest() + val result = fakeApiRequest() + println("debug: result: ${result}") } + } } @@ -31,56 +32,68 @@ class MainActivity : AppCompatActivity() { val newText = text.text.toString() + "\n$input" text.text = newText } - private suspend fun setTextOnMainThread(input: String) { - withContext (Main) { - setNewText(input) - } - } - private suspend fun fakeApiRequest() { - coroutineScope { - - val parentJob = launch { - - val executionTime = measureTimeMillis { - val job1 = launch { - println("debug: launching job1 in thread: ${Thread.currentThread().name}") - val result1 = getResult1FromApi() - setTextOnMainThread("Got $result1") - } - job1.join() // join job1 to parent job (blocking until completion) - - val job2 = launch { - println("debug: launching job2 in thread: ${Thread.currentThread().name}") - val result2 = getResult2FromApi() - setTextOnMainThread("Got $result2") - } - job2.join() // join job2 to parent job (blocking until completion) + private suspend fun fakeApiRequest(): String{ + + + val time = measureTimeMillis { + coroutineScope{ + + val job1 = launch{ + println("debug: starting job 1") + delay(1000) + println("debug: done job 1") } - println("debug: job1 and job2 are complete. It took ${executionTime} ms") - } + val job2 = launch{ + println("debug: staring job 2") + delay(1500) + println("debug: done job 2") + } - // Separate job within the same coroutine context that runs independently of parentJob, Job1 and Job2 - launch { - for(delay in arrayOf(1, 2, 3, 4, 5, 6)){ - delay(500) - println("debug: is parent job active?: ${parentJob.isActive}") + val job3 = launch{ + println("debug: starting job 3") + delay(1000) + println("debug: done job 3") } + + job1.join() + job2.join() + job3.join() } + } + println("debug: elapsed time: ${time}") - } + return "All jobs are done." } - private suspend fun getResult1FromApi(): String { - delay(1000) // Does not block thread. Just suspends the coroutine inside the thread - return "Result #1" - } - private suspend fun getResult2FromApi(): String { - delay(1000) - return "Result #2" - } +} + + + + + + + + + + + + + + + + + + + + + + + + + + -} \ No newline at end of file From 07dde35cfb99bee6f7d95c1abcddc1d5aee2472b Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Sat, 27 Jul 2019 13:45:41 -0700 Subject: [PATCH 04/10] parallell coroutine jobs (example 2) --- .../java/com/codingwithmitch/coroutineexamples/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt index 6788454..593d82c 100644 --- a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt +++ b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt @@ -21,7 +21,7 @@ class MainActivity : AppCompatActivity() { CoroutineScope(IO).launch { println("debug: CoroutineScope") val result = fakeApiRequest() - println("debug: result: ${result}") + println("debug: result: ${result}") // waits until all jobs in coroutine scope are complete to return result } } From c3fa469a4a706ba5b887ea2258458d4a3e220810 Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Mon, 29 Jul 2019 11:28:34 -0700 Subject: [PATCH 05/10] parallel coroutine jobs (example 2) --- .../java/com/codingwithmitch/coroutineexamples/MainActivity.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt index 593d82c..3203937 100644 --- a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt +++ b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt @@ -57,9 +57,6 @@ class MainActivity : AppCompatActivity() { println("debug: done job 3") } - job1.join() - job2.join() - job3.join() } } println("debug: elapsed time: ${time}") From f4dd7b9fd3cb343933623df2be153ece940bdcee Mon Sep 17 00:00:00 2001 From: Mitch Tabian Date: Thu, 15 Aug 2019 10:07:56 -0700 Subject: [PATCH 06/10] completable job with cancellation --- .../coroutineexamples/MainActivity.kt | 99 ++++++++++++------- app/src/main/res/layout/activity_main.xml | 55 +++++++---- 2 files changed, 99 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt index 3203937..fae217b 100644 --- a/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt +++ b/app/src/main/java/com/codingwithmitch/coroutineexamples/MainActivity.kt @@ -2,69 +2,87 @@ package com.codingwithmitch.coroutineexamples import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.util.Log +import android.widget.ProgressBar import kotlinx.android.synthetic.main.activity_main.* import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.IO -import kotlin.system.measureTimeMillis +import kotlinx.coroutines.Dispatchers.Main class MainActivity : AppCompatActivity() { + private val TAG: String = "AppDebug" + + private val PROGRESS_MAX = 100 + private val PROGRESS_START = 0 + private val JOB_TIME = 4000 // ms + private lateinit var job: CompletableJob + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - button.setOnClickListener { - setNewText("Click!") - - CoroutineScope(IO).launch { - println("debug: CoroutineScope") - val result = fakeApiRequest() - println("debug: result: ${result}") // waits until all jobs in coroutine scope are complete to return result + job_button.setOnClickListener { + if(!::job.isInitialized){ + initjob() } - + job_progress_bar.startJobOrCancel(job) } - } - private fun setNewText(input: String){ - val newText = text.text.toString() + "\n$input" - text.text = newText + fun resetjob(){ + if(job.isActive || job.isCompleted){ + job.cancel(CancellationException("Resetting job")) + } + initjob() } - private suspend fun fakeApiRequest(): String{ - - - val time = measureTimeMillis { - coroutineScope{ - - val job1 = launch{ - println("debug: starting job 1") - delay(1000) - println("debug: done job 1") - } - - val job2 = launch{ - println("debug: staring job 2") - delay(1500) - println("debug: done job 2") - } + fun initjob(){ + job_button.setText("Start Job #1") + updateJobCompleteTextView("") + job = Job() + job.invokeOnCompletion { + Log.d(TAG, "${job}: invoke on completion called.") + it?.message.let{ + Log.e(TAG, "${job} was cancelled. Reason: ${it}") + } + } + job_progress_bar.max = PROGRESS_MAX + job_progress_bar.progress = PROGRESS_START + } + - val job3 = launch{ - println("debug: starting job 3") - delay(1000) - println("debug: done job 3") + fun ProgressBar.startJobOrCancel(job: Job){ + if(this.progress > 0){ + Log.d(TAG, "${job} is already active. Cancelling...") + resetjob() + } + else{ + job_button.setText("Cancel Job #1") + CoroutineScope(IO + job).launch{ + Log.d(TAG, "coroutine ${this} is activated with job ${job}.") + + for(i in PROGRESS_START..PROGRESS_MAX){ + delay((JOB_TIME / PROGRESS_MAX).toLong()) + this@startJobOrCancel.progress = i } - + updateJobCompleteTextView("Job is complete!") } } - println("debug: elapsed time: ${time}") - + } - return "All jobs are done." + private fun updateJobCompleteTextView(text: String){ + GlobalScope.launch (Main){ + job_complete_text.setText(text) + } } + override fun onDestroy() { + super.onDestroy() + job.cancel() + } } @@ -88,6 +106,11 @@ class MainActivity : AppCompatActivity() { + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 6fa9380..55f1e11 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -5,28 +5,49 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".MainActivity"> + tools:context=".MainActivity" + android:padding="10dp"> -