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/>.