Task Handling library for Kotlin and Android.
This library is based on Kotlin Coroutine and Thread
Why CoTask
- Pause CoTask
- Resume CoTask
- Publish progress to main thread
- Error handling and Other callbacks
Contents:
1. Setup
1.1 Kotlin DSL
1.2 Groovy DSL
2. Usage
2.1 CoTask (Recommended)
2.2 ThreadTask
2.3 JTask
3. License
Step 1: Project level build.gradle / settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven {
url = uri("https://jitpack.io")
}
}
}
Step 2: Module level build.gradle
dependencies {
implementation("com.github.Bhuvaneshw.task:$module:$version")
}
Replace $module with cotask, threadtask or jtask
Replace $version with latest version
Latest Version:
Example:
dependencies {
implementation("com.github.Bhuvaneshw.task:cotask:2.0.0")
implementation("com.github.Bhuvaneshw.task:threadtask:2.0.0")
implementation("com.github.Bhuvaneshw.task:jtask:2.0.0")
}
Step 1: Project level build.gradle / settings.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Step 2: Module level build.gradle
dependencies {
implementation 'com.github.Bhuvaneshw.task:$module:$version'
}
Simple CoTask
CoTask { // Default dispatcher will be Dispatchers.Default
delay(1000) // Your expensive task
}
Using Coroutine Functions
CoTask { // Task<Unit,Nothing>:CoroutineScope
delay(1000)
launch { // from coroutine library
delay(1000)
}
val job = async { // from coroutine library
delay(1000)
}
job.await()
}
Using Dispatcher
CoTask(Dispatchers.IO) {
delay(1000L)
}
// Extensions
CoTask withIO {
}
// or
CoTask.withIO {
}
Callbacks
CoTask { // this: Task<String, Nothing> String => return type
delay(1000)
"My valuable result"
}.onPause {
appendStatus("CoTask1 Paused")
}.onResume {
appendStatus("CoTask1 Resumed")
}.onEnd {
appendStatus("CoTask1 completed")
}.onCancelled {
appendStatus("CoTask1 cancelled")
}.onResult { result: String ->
appendStatus("CoTask1 result $result")
}
Error Handling
CoTask {
delay(4000)
5 / 0 // Divide by zero
}.catch {
appendStatus("CoTask error $it")
}
// Or
CoTask {
delay(4000)
5 / 0 // Divide by zero
}.logError("CoTask")
Chaining Tasks
CoTask { // this: Task<String, Nothing> String => return type
delay(1000)
"500"
}.then { it: String -> // this: Task<Int, Nothing>, it:String => the previous return value
delay(2000)
it.toInt()
}.then { it: Int ->
it / 5f
}.onResult { result: Float ->
appendStatus("CoTask2 result $result")
}
Progressed CoTask
ProgressedCoTask { // this: Task<String, Int> String => return type, Int => Progress Type
delay(1000)
publishProgress(50)
delay(1000)
publishProgress(99)
"My valuable result"
}.onProgress { progress: Int ->
appendStatus("CoTask3 progress $progress")
}.onResult { result: String ->
appendStatus("CoTask3 result $result")
}
Cancelling Task
val task = ProgressedCoTask {
var i = 10
while (i-- > 0) {
ensureActive() // enabling that the task can be paused/cancelled here
publishProgress(10 - i)
}
}.onProgress {
appendStatus("CoTask4 progress $it")
}.onCancelled {
appendStatus("CoTask4 cancelled")
}
// Cancelling the task after 1.5 seconds
CoTask {
delay(1500)
task.cancel()
}
Pausing and Resuming
val task = ProgressedCoTask {
var i = 10
while (i-- > 0) {
ensureActive() // enabling that the task can be paused/cancelled here
publishProgress(10 - i)
}
// launchPausing { }.pause()
// asyncPausing { }.pause()
}.onProgress {
appendStatus("CoTask5 progress $it")
}.onPause {
appendStatus("CoTask5 paused")
}.onResume {
appendStatus("CoTask5 resumed")
}
// Pausing and Resuming the task after 1.5 seconds of break
CoTask {
delay(1500)
task.pause()
delay(1500)
task.resume()
}
Startable Tasks
StartableCoTask {
delay(1000)
}.onStart {
}.start()
StartableProgressedCoTask {
publishProgress(10)
delay(1000)
publishProgress(100)
}.start()
// If you return any data, then
StartableCoTask {
delay(1111)
"My value"
}.start { result: String -> // called before on result callback
appendStatus("Result $result")
}
Using with scopes, Extension functions
// You can use these extensions functions with coroutine scope
GlobalScope.coTask { }
GlobalScope.progressedCoTask { publishProgress(0) }
GlobalScope.startableCoTask { }
GlobalScope.startableProgressedCoTask { publishProgress(0) }
// Specifying Dispatcher
GlobalScope.coTask(Dispatchers.IO) { }
GlobalScope.progressedCoTask(Dispatchers.IO) { publishProgress(0) }
GlobalScope.startableCoTask(Dispatchers.IO) { }
GlobalScope.startableProgressedCoTask(Dispatchers.IO) { publishProgress(0) }
// "with" infix notation
CoTask withIO {
}
ProgressedCoTask withIO {
publishProgress(1)
}
// "with" can't be used as infix notation if you are accessing other functions like start, onCancel, logError, etc
StartableCoTask.withIO {
}.start()
CoTask.withIO {
}.logError()
Note: Pausing and Resuming is not available in ThreadTask
Simple Thread Task
ThreadTask {
delay(1000) // Your expensive task
}
Callbacks
ThreadTask { // this: Task<String, Nothing> String => return type
delay(1000)
"My valuable result"
}.onEnd {
appendStatus("ThreadTask1 completed")
}.onCancelled {
appendStatus("ThreadTask1 cancelled")
}.onResult { result: String ->
appendStatus("ThreadTask1 result $result")
}
Error Handling
ThreadTask {
delay(4000)
5 / 0 // Divide by zero
}.catch {
appendStatus("ThreadTask error $it")
}
// Or
ThreadTask {
delay(4000)
5 / 0 // Divide by zero
}.logError("ThreadTask")
Chaining Tasks
ThreadTask { // this: Task<String, Nothing> String => return type
delay(1000)
"500"
}.then { it: String -> // this: Task<Int, Nothing>, it:String => the previous return value
delay(2000)
it.toInt()
}.then { it: Int ->
it / 5f
}.onResult { result: Float ->
appendStatus("ThreadTask2 result $result")
}
ProgressedThreadTask
ProgressedThreadTask { // this: Task<String, Int> String => return type, Int => Progress Type
delay(1000)
publishProgress(50)
delay(1000)
publishProgress(99)
"My valuable result"
}.onProgress { progress: Int ->
appendStatus("ThreadTask3 progress $progress")
}.onResult { result: String ->
appendStatus("ThreadTask3 result $result")
}
Cancelling Task
val task = ProgressedThreadTask {
var i = 1
while (i <= 100) {
publishProgress(i)
ensureActive() // Mandatory for ThreadTask to check for cancellation and calling onCancelled callback
delay(1000)
i += 10
}
}.onProgress {
appendStatus("ThreadTask4 progress $it")
}.onCancelled {
appendStatus("ThreadTask4 cancelled")
}
// Cancelling the task after 1.5 seconds
ThreadTask {
delay(1500)
task.cancel()
}
Startable Tasks
StartableThreadTask {
delay(1000)
}.onStart{
}.start()
StartableProgressedThreadTask {
publishProgress(10)
delay(1000)
publishProgress(100)
}.start()
// If you return any data, then
StartableThreadTask {
delay(1111)
"My value"
}.start { result: String -> // called before on result callback
appendStatus("Result $result")
}
Simple JTask
JTask.with(task -> {
task.sleep(1000);
return "hello";
}).start();
Callbacks and Error handling
JTask.with(task -> {
int i = 0;
while (i < 10) {
task.ensureActive(); // Mandatory if you cancel the task!
task.publishProgress((i + 1) * 10);
i++;
}
return "hello";
}).onStart(() -> {
log("OnStart");
}).onEnd(() -> {
log("OnEnd");
}).onCancel(() -> {
log("OnCancel");
}).onError((error) -> {
log("OnError : " + error.getLocalizedMessage());
}).onProgress((progress) -> {
log("Progress: " + ((int) progress[0]));
}).onResult((result) -> {
log("Result: " + result);
}).start();
Chaining Tasks
new JTask<String>(task -> {
task.sleep(1000);
return "123";
}).then(result ->
new JTask<Integer>(task -> {
task.sleep(1000);
return Integer.parseInt(result);
}).onStart(() -> {
log("OnStart");
}).onResult(intResult -> {
log("Result: " + intResult);
})
).start();
Cancelling Task
JTask<?> task = JTask.with(t -> {
int i = 0;
while (i < 10) {
t.ensureActive(); // Mandatory if you cancel the task!
t.publishProgress((i + 1) * 10);
i++;
}
return "hello";
}).onCancel(() -> {
log("OnCancel");
});
task.start();
new Timer().schedule(new TimerTask() {
@Override
public void run() {
task.cancel();
}
}, 1000);
Task - Task Handling Library
Copyright (C) 2024 Bhuvaneshwaran
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.