A Kotlin work manager library for Android with progress notifications and Hilt support.

Overview

Release  API  Android Arsenal  Awesome Kotlin Badge

Boot Laces

A kotlin work manager library for Android that includes notifications and Hilt support.

User Instructions

  1. Add the JitPack repository to your project's build.gradle
allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io' }
	}
}
  1. Add the kapt and hilt plugins to the top of your app's build.gradle file
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
  1. Add the dependencies for boot laces & hilt to your app's build.gradle
dependencies {
        implementation 'com.github.evilthreads669966:bootlaces:10.0'
        implementation "com.google.dagger:hilt-android:2.29.1-alpha"
        kapt "com.google.dagger:hilt-android-compiler:2.29.1-alpha"
}
  1. Add the Hilt plugin to your project's build.gradle dependencies
dependencies {
    ...
    classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
}
  1. Annotate your subclass of Application class
@HiltAndroidApp
class App: Application()
  1. Add name of your Application subclass to manifest
<application
    android:name=".App"
    ...
>
  1. Create your worker(s).
  • you can opt-in for having a progress notification that displays while Worker.doWork is active
    • the description for your worker is good practice and will be used for things like notifications if you choose to use them
  • you perform your work inside of doWork and Boot Laces will keep it running in the background until it has completed and reschedule as necessary
  • WorkerNine below demonstrates how to create a WorkReceiver
    • a WorkReceiver is created by passing in an action for it to subscribe to.
    • you can broadcast to this BroadcastReceiver from within your doWork function or anywhere else in your app
    • for now the WorkReceiver is only registered and subscribing to broadcast while you are performing work. Everytime doWork executes it registers the receiver & unregisters it after doWork completes
  • If you do not need a worker and just a BroadcastReceiver then you can use PersistentReceiver
    • PersistentReceivers only have a WorkReceiver and you don't need to override doWork function
class WorkerEight: Worker(8, "working for 2 hours", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(AlarmManager.INTERVAL_HOUR * 2)
    }
}

class WorkerOne: Worker(1, "performing database transactions for 2 minutes", true, Dispatchers.IO){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(120000)
    }
}

class WorkerTwo: Worker(2, "performing operations on files for 15 minutes", true, Dispatchers.IO){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(AlarmManager.INTERVAL_FIFTEEN_MINUTES)
    }
}

class WorkerThree: Worker(3, "working for 1 minute", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(60000)
    }
}

class WorkerFour: Worker(4, "working for 5 minutes", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(60000 * 5)
    }
}

class WorkerFive: Worker(5, "working for 45 seconds", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(45000)
    }
}

class WorkerSix: Worker(6, "working for 1 minute", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(60000)
    }
}

class WorkerSeven: Worker(7, "working for a minute and a half", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(90000L)
    }
}

class WorkerThirteen: Worker(13, "working for 20 seconds", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(20000)
    }
}

class WorkerTwelve: Worker(12, "working for 30 seconds", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(30000)
    }
}

class WorkerEleven: Worker(11, "working for 5 seconds", true){
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, description)
        delay(5000)
    }
}

class WorkerTen: Worker(10,"Worker Ten", true) {
    override suspend fun doWork(ctx: Context) {
        Log.d(tag, "working for 10 seconds")
        for(i in 1..10)
            delay(1000)
    }
}

class WorkerFourteen: Worker(14, "survives reboot and performs every hour", true){

    override val receiver: WorkReceiver?
        get() = object : WorkReceiver(Intent.ACTION_TIME_TICK) {

            override fun onReceive(ctx: Context?, intent: Intent?) {
                if(intent?.action?.equals(action) ?: false){
                    val date = DateUtils.formatDateTime(ctx, System.currentTimeMillis(),0)
                    Log.d(this.tag, date ?: "null")
                }
            }
        }

    override suspend fun doWork(ctx: Context) {
        while(true){
            Log.d(tag, "working for three minutes")
            delay(60000L * 3)
        }
    }
}

class ReceiverAtReboot: PersistentReceiver(18){
   override val receiver: WorkReceiver?
       get() = object : WorkReceiver(Intent.ACTION_AIRPLANE_MODE_CHANGED, Intent.ACTION_BATTERY_CHANGED){
           override fun onReceive(ctx: Context?, intent: Intent?) {
               super.onReceive(ctx, intent)
               goAsync().apply {
                   when(intent?.action){
                       Intent.ACTION_BATTERY_CHANGED -> Log.d(this@ReceiverAtReboot.tag, "battery level changed")
                       Intent.ACTION_AIRPLANE_MODE_CHANGED -> Log.d(this@ReceiverAtReboot.tag, "airplane mode changed")
                       else -> Log.d(this@ReceiverAtReboot.tag, "action not found")
                   }
               }.finish()
           }
       }
}
  1. Inject your WorkScheduler inside of an Android context
@Inject lateinit var scheduler: WorkScheduler
  1. Your WorkScheduler instance provides you with a scoping function called WorkScheduler.use
  • it accepts a trailing lambda
  • within WorkScheduler.use scope you have access to scheduling functions that have a receiver type of Worker
    • This allows you to use your worker(s) instance(s) to call schedule on your worker
  1. Schedule your worker inside of WorkScheduler.use scope
  • you can pass four arguments to your worker's many available KTX schedule functions
    • surviveReboot
      • allows the worker to survive the phone rebooting
    • precision
      • ensures the worker executes at the exact time scheduled.
        • not using precision allows for the operating system to only execute the worker when there are not too many workers in the background.
    • repeating
      • sets whether the worker should be scheduled to repeat everytime the specified time passes
    • it's default value is false so you don't have to opt out of repeating
      • wakeUpIfIdle
    • sets whether you worker should wake up the device to perform work rather than wait for it stop sleeping
      • the default value for this is false
@AndroidEntryPoint
class LauncherActivity: AppCompatActivity(){
    @Inject lateinit var scheduler: WorkScheduler

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
              scheduler.use {
                   runBlocking {
                       WorkerSix().scheduleQuarterHour(surviveReboot = true, repeating =  true, allowWhileIdle = true, precision = true).await()
                       WorkerFive().scheduleHalfHour().await()
                   }
               }
               scheduler.use {
                   runBlocking {
                       WorkerFour().scheduleHour(surviveReboot = true, repeating =  true, allowWhileIdle = true, precision = true).await()
                       WorkerTwelve().scheduleFuture(60000L * 8, repeating = true, allowWhileIdle = true, precision = true).await()
                       WorkerEleven().scheduleFuture(60000L * 3, repeating = true, allowWhileIdle = true, precision = true).await()
                       WorkerThirteen().scheduleNow().await()
                       WorkerTwo().scheduleDay(surviveReboot = true, repeating =  true, allowWhileIdle = true, precision = true).await()
                       val fourtyFiveSeconds = 45000L
                       WorkerOne().scheduleFuture(fourtyFiveSeconds, repeating = true, allowWhileIdle = true).await()
                       WorkerThree().scheduleQuarterDay(repeating =  true, allowWhileIdle = true, precision = true).await()
                   }
               }
               scheduler.use {
                   runBlocking {
                       WorkerSeven().scheduleNow().await()
                       WorkerEight().scheduleHoursTwo(repeating =  true, allowWhileIdle = true, precision = true).await()
                       WorkerTen().scheduleHalfWeek(repeating =  true, allowWhileIdle = true, precision = true).await()
                       WorkerFourteen().scheduleHour(surviveReboot = true, repeating = true, allowWhileIdle = true, precision = true).await()
                       ReceiverAtReboot().scheduleReceiver().await()
                   }
               }
           }
    }
}

Important To Know

License

Copyright 2019 Chris Basinger

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Comments
  • Disabling App Icon

    Disabling App Icon

    Okay so I was gonna disable the app icon before I dissapeared but here is what my research brought. I've only been at this for 10 minutes. I spent the last 2 days straight working with jetpack. Soo if we disable the launcher activity which disables the icon in the launcher... then we can't start that activity to lock the screen... meaning we must have a second activity for locking the screen that way we can disable the launcher activity and still be able to lock the screen I am working on this right before I go back to working on my core skill set and updating my knowledge of android libraries for the next 6-8 months.

    opened by evilthreads669966 19
  • hourly, monthly, & yearly workers

    hourly, monthly, & yearly workers

    2020-12-31 20:35:20.074 4776-4853/com.candroid.lacedboots D/Hourly worker: working hourly 2020-12-31 20:35:20.085 4776-4850/com.candroid.lacedboots D/Hourly worker: working hourly 2020-12-31 20:35:20.125 4776-4845/com.candroid.lacedboots D/Hourly worker: working hourly

    bug 
    opened by evilthreads669966 12
  • Multiple Persistent Workers

    Multiple Persistent Workers

    • multiple persistent workers are not working
      • only the first one scheduled makes it to doWork inside of assignWork in WorkService
      • I have tested with two
        • it makes it into the database and the flow is triggering when collecting from the query on the table
          • assignWorker never gets called on it though
    bug 
    opened by evilthreads669966 5
  • HAHAHA

    HAHAHA

    I'm laying in bed like just finishing writing that function and I check my git log and it goes back like 30 merges haha. Wow. I've never felt like this bad before. Like right as my body begins to feel weary and my eyes are burning from the excessive screen exposure and lack off sleep...i guess it feels better though because the end result. makes my eyes lay easier

    opened by evilthreads669966 3
  • Persistent Workers

    Persistent Workers

    I was playing with my phone off to the side and I Restarted and my persistent hourly worker didn't run after reboot so I kicked the system clock up and kept trying and kind of forgot but now I am really going to check all these while I do something else

    opened by evilthreads669966 1
  • Remove Internal Access Modifiers on Functions In Internal Class Files

    Remove Internal Access Modifiers on Functions In Internal Class Files

    • not a bug but I marked the functions internal before the classes
      • I was under the impression that if you use @Inject on a class public constructor that it had to be made public
      • I have no idea why I was under the impression that classes with injectable constructors in Hilt had to be public
        • made me wonder what the benefit of Hilt is in a library
    opened by evilthreads669966 1
  • Fix Persistent Work Query Bug

    Fix Persistent Work Query Bug

    • change return type of getPersistentWork from Flow to Flow<List>
    • non persistent work channel doesn't use processWork ktx anymore due to receiver type
    • mark classes, properties, and functions internal or private where possible
    • add second persistent worker with WorkReceiver for testing WorkerFourteen
    opened by evilthreads669966 1
  • Starting Service in BootReceiver

    Starting Service in BootReceiver

    • need to check whether there is persistent work scheduled before starting the service in BootReceiver
      • after adding periodic work feature it gives the BootReceiver more responsibility
        • The BootReceiver component may be enabled without the need for the work service to be started.
        • Whenever an alarm is triggered it will broadcast to the same receiver and it will make a work request which starts the service when needed
      • This will prevent the service from being started everytime the phone reboots in the event that we have periodic work and not persistent work
    • this is more of a optimization than a bug
    bug 
    opened by evilthreads669966 1
  • Release Version 10.0

    Release Version 10.0

    • update documentation
      • sorry I am lazy and just don't feel like it right now. But, I mean.. it says what it does.
      • increment release version to 10.0
    opened by evilthreads669966 0
  • Move Rescheduling to BOOT_COMPLETE BroadcastReceiver

    Move Rescheduling to BOOT_COMPLETE BroadcastReceiver

    • move rescheduling functionality to BroadcastReceiver registered with BOOT_COMPLETE filter from WorkService.kt
    • rename BootReceiver.kt to ReschedulingReceiver.kt
    • remove Actions.ACTION_RESCHEDULE
    • remove createReschedulingIntent function in IntentFactory.kt
    • use goAsync in ReschedulingReceiver.kt inside of onReceive
    • remove IntentFactory from ReschedulingReceiver.kt
    • inject CoroutineScope in ReschedulingReceiver.kt
    opened by evilthreads669966 0
  • Multiple Actions For WorkReceiver

    Multiple Actions For WorkReceiver

    • change Worker.WorkReceiver action field from val to vararg val
    • delete unregisterReceiver & registerReceiver in Worker
    • add registerWorkReceiver function to WorkService
      • change logic from previous function to handle vararg action
    • add a second action to ReceiverAtReboot for demo app
      • Intent.ACTION_AIRPLANE_MODE_CHANGED
    opened by evilthreads669966 0
Releases(10.0.2)
A beautiful Fashion Store like Android App Mock built on Jetpack Compose with compose navigation, hilt, dark theme support and google's app architecture found on uplabs Here

A beautiful Fashion Store like Android App Mock built on Jetpack Compose with compose navigation, hilt, dark theme support and google's app architecture found on uplabs Here

Puncz 87 Nov 30, 2022
A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

A somewhat copy past of Jetbrain's code from the kotlin plugin repo to make it humanly possible to test Intellij IDEA kotlin plugins that work on kotlin

common sense OSS 0 Jan 20, 2022
The AppMetrica Push SDK is a set of libraries for working with push notifications.

Flutter AppMetrica Push AppMetrica Push SDK — это набор библиотек для работы с push-уведомлениями. Подключив AppMetrica Push SDK, вы можете создать и

Mad Brains 6 Oct 12, 2022
Reapp is everything you need to build amazing apps with React: a collection of packages that work together, our UI kit, and a CLI that scaffolds your app and includes a server and build system.

What is it? Reapp is everything you need to build amazing apps with React: a collection of packages that work together, our UI kit, and a CLI that sca

reapp 3.4k Nov 20, 2022
A set of extension properties on Int, Long, Double, and Duration, that makes it easier to work with Kotlin Duration

Kotlin Duration Extensions Gradle Groovy repositories { mavenCentral() } implementation 'com.eygraber:kotlin-duration-extensions:1.0.1' Kotlin rep

Eliezer Graber 8 Nov 8, 2022
Dots indicator that shows the current position on a View Pager. It does all the work for you with a few customisations.

Dots What is Dots? Dots is a library that helps in implementing a simple yet effective dots indicator for the View Pagers used in your android code. I

Deepan 23 Feb 16, 2022
Location Service Manager for Kotlin Multiplatform Mobile iOS and android

Location Service Manager for Kotlin Multiplatform Mobile iOS and android Features Provides simple permission settings Dramatically reduce the amount o

LINE 55 Dec 10, 2022
Android Ad Manager Works with Admob, Mopup, Facebook- Bidding and Audience Networks

AndroidAdManager Works with Admob, Mopup, Facebook- Bidding and Audience Networks. Added ad types are NativeBanner, NativeAdvanced, Interstitial and B

Hashim Tahir 11 May 18, 2022
Dependency Injection library for Kotlin Multiplatform, support iOS and Android

Multiplatform-DI library for Kotlin Multiplatform Lightweight dependency injection framework for Kotlin Multiplatform application Dependency injection

Anna Zharkova 32 Nov 10, 2022
Workout Journal is a mobile app based on Multi-Module and Clean Architecture for those who want to track their progress over a workout and a calendar period.

Workout-Journal Workout Journal is a mobile app for those who want to track their progress over a workout and a calendar period. The app allows you to

Maxim Smolyakov 4 Oct 23, 2022
Carousel Recyclerview let's you create carousel layout with the power of recyclerview by creating custom layout manager.

Carousel Recyclerview Create carousel effect in recyclerview with the CarouselRecyclerview in a simple way. Including in your project Gradle Add below

Jack and phantom 514 Jan 8, 2023
An easy to use package manager for Fabric Minecraft mods.

pacmc pacmc is a package manager for Fabric Minecraft mods. The aim of this project is to massively reduce the effort you have to put in to installing

Jakob K 109 Dec 30, 2022
Strong-bax - An open source password manager project

What is strong-bax? Strong-bax is an open source password manager project. Stron

null 1 Feb 6, 2022
Sample application to demonstrate Multi-module Clean MVVM Architecture and usage of Android Hilt, Kotlin Flow, Navigation Graph, Unit tests etc.

MoneyHeist-Chars Sample application to demonstrate Multi-module Clean MVVM Architecture and usage of Android Hilt, Kotlin Flow, Navigation Graph, Room

Hisham 20 Nov 19, 2022
Delish, a Food Recipes App in Jetpack Compose and Hilt based on modern Android tech-stacks and MVVM clean architecture.

Delish Screens Tech stack & Open-source libraries 100% Kotlin based + Coroutines + Flow for asynchronous. Dagger Hilt 2.37 Accompanist JetPack Jetpack

Mohamed Elbehiry 305 Dec 12, 2022
Clean MVVM with eliminating the usage of context from view models by introducing hilt for DI and sealed classes for displaying Errors in views using shared flows (one time event), and Stateflow for data

Clean ViewModel with Sealed Classes Following are the purposes of this repo Showing how you can remove the need of context in ViewModels. I. By using

Kashif Mehmood 22 Oct 26, 2022
An example of a test task for creating a simple currency converter application for the Android platform. The app is developed using Kotlin, MVI, Dagger Hilt, Retrofit, Jetpack Compose.

Simple Currency Converter Simple Currency Converter Android App by Isaev Semyon An example of a test task for creating a simple currency converter app

Semyon Isaev 1 Nov 8, 2021
🍭 GithubSearchKMM - Github Repos Search - Android - iOS - Kotlin Multiplatform Mobile using Jetpack Compose, SwiftUI, FlowRedux, Coroutines Flow, Dagger Hilt, Koin Dependency Injection, shared KMP ViewModel, Clean Architecture

GithubSearchKMM Github Repos Search - Kotlin Multiplatform Mobile using Jetpack Compose, SwiftUI, FlowRedux, Coroutines Flow, Dagger Hilt, Koin Depend

Petrus Nguyễn Thái Học 50 Jan 7, 2023
Jetpack Compose, Kotlin, MVVM, Navigation Component, Hilt, Retrofit2

Jetpack-Compose-Blueprint Jetpack Compose, Kotlin, MVVM, Navigation Component, Hilt, Retrofit2 Apps Packages data : It contains all the data accessing

Jai Khambhayta 14 Dec 15, 2022