Skip to content

Bhuvaneshw/Task

Repository files navigation

Task

Task Handling library for Kotlin and Android. This library is based on Kotlin Coroutine and Thread

Why CoTask

  1. Pause CoTask
  2. Resume CoTask
  3. Publish progress to main thread
  4. 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



1. Setup

1.1 Gradle - Kotlin DSL

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")
}

1.2 Gradle - Groovy DSL

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'
}


2. Usage

2.1 CoTask - Coroutine Task, for Kotlin

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()


2.2 ThreadTask - for Kotlin


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")
}


2.3 JTask - for Java

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);


3. License

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