😴 Lazy and fluent syntactic sugar of Kotlin for initializing Android lifecycle-aware property.

Overview

Lazybones

License API Build Status Profile Android Weekly Javadoc

😴 Lazy and fluent syntactic sugar of Kotlin for initializing Android lifecycle-aware property.

Ah... I'm a super lazy person.
I just want to declare initialization and disposition together.

Including in your project

Maven Central Jitpack

Gradle

Add below codes to your root build.gradle file (not your module build.gradle file).

allprojects {
    repositories {
        mavenCentral()
    }
}

And add a dependency code to your module's build.gradle file.

dependencies {
    implementation "com.github.skydoves:lazybones:1.0.2"
}

SNAPSHOT

Lazybones
Snapshots of the current development version of Lazybones are available, which track the latest versions.

repositories {
   maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
}

Usage

lifecycleAware

We can initialize a lifecycle-aware object lazily using the lifecycleAware keyword. The lifecycleAware functionality can be used to register & unregister listeners, clear something, show & dismiss, and dispose of disposable objects as lifecycle changes by the lifecycleOwner(Activity, Fragment). If we want to initialize an object lazily, we should use it with by keyword and lazy() method.

val myDialog: Dialog by lifecycleAware { getDarkThemeDialog(baseContext) }
    .onCreate { this.show() } // show the dialog when the lifecycle's state is onCreate.
    .onDestroy { this.dismiss() } // dismiss the dialog when the lifecycle's state is onDestroy.
    .lazy() // initlize the dialog lazily.

In the onCreate and onDestroy lambda function, we can omit the this keyword. In the below example, the MediaPlayer will be initialized and the start() will be invoked on the onCreate state of the lifecycle. And the pause(), stop(), or release() will be invoked based on the state of the lifecycle.

private val mediaPlayer: MediaPlayer by lifecycleAware {
  MediaPlayer.create(this, R.raw.bgm3)
}.onCreate {
  isLooping = true
  start()
}.onStop {
  pause()
}.onResume {
  start()
}.onDestroy {
  stop()
  release()
}.lazy()

The above code works the same as the below codes.

private val mediaPlayer: MediaPlayer by lazy { MediaPlayer.create(this, R.raw.bgm3) }

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  mediaPlayer.isLooping = true
  mediaPlayer.start()
}

override fun onPause() {
  super.onPause()
  mediaPlayer.pause()
}

override fun onStop() {
  super.onStop()
  mediaPlayer.pause()
}

override fun onResume() {
  super.onResume()
  mediaPlayer.start()
}

override fun onDestroy() {
  super.onDestroy()
  mediaPlayer.stop()
  mediaPlayer.release()
}

CompositeDisposable in RxJava2

Here is an example of CompositeDisposable in RxJava2.
At the same time as initializing lazily the CompositeDisposable, the dispose() method will be
invoked automatically when onDestroy.

val compositeDisposable by lifecycleAware { CompositeDisposable() }
    .onDestroy { dispose() } // call the dispose() method when onDestroy this activity.
    .lazy() // initialize a CompositeDisposable lazily.

Lifecycle related methods

We can invoke lambda functions as lifecycle changes and here are eight lifecycle-related methods of lifecycleAware.

.onCreate { } // the lambda will be invoked when onCreate.
.onStart { } // the lambda will be invoked when onStart.
.onResume { } // the lambda will be invoked when onResume.
.onPause { } // the lambda will be invoked when onPause.
.onStop { } // the lambda will be invoked when onStop.
.onDestroy { }  // the lambda will be invoked when onDestroy.
.onAny { } // the lambda will be invoked whenever the lifecycle state is changed.
.on(On.Create) { } // we can set the lifecycle state manually as an attribute.

Usages in the non-lifecycle owner class

The lifecycleAware is an extension of lifecycleOwner so it can be used on non- lifecycle-owner classes.

class MainViewModel(lifecycleOwner: LifecycleOwner) : ViewModel() {

  private val compositeDisposable by lifecycleOwner.lifecycleAware { CompositeDisposable() }
    .onDestroy { it.dispose() }
    .lazy()

   ...

LifecycleAwareProperty

If we don't need to initialize lazily, here is a more simple way. We can declare a LifecycleAwareProperty using the lifecycleAware keyword. The attribute value will not be initialized lazily. so we don't need to use it with by keyword and lazy() method.

private val lifecycleAwareProperty = lifecycleAware(CompositeDisposable())
    // observe lifecycle's state and call the dispose() method when onDestroy  
    .observeOnDestroy { dispose() }

And we can access the original property via the value field.

lifecycleAwareProperty.value.add(disposable)
lifecycleAwareProperty.value.dispose()

We can observe the lifecycle changes using observe_ method.

class MainActivity : AppCompatActivity() {

  private val lifecycleAwareProperty = lifecycleAware(DialogUtil.getDarkTheme())
    .observeOnCreate { show() }
    .observeOnDestroy { dismiss() }
    .observeOnAny { .. }
    .observeOn(On.CREATE) { .. }

    ...

Here is the kotlin DSL way.

private val lifecycleAwareProperty = lifecycleAware(getDarkThemeDialog())
    .observe {
      onCreate { show() }
      onResume { restart() }
      onDestroy { dismiss() }
    }

Using in the non-lifecycle owner class

The lifecycleAware is an extension of lifecycleOwner so it can be used on non- lifecycle-owner classes.

class MainViewModel(lifecycleOwner: LifecycleOwner) : ViewModel() {

  private val TAG = MainViewModel::class.java.simpleName
  private val lifecycleAwareProperty = lifecycleOwner.lifecycleAware(Rabbit())

 init {
    this.lifecycleAwareProperty
      .observeOnCreate { Log.d(TAG, "OnCreate: $this") }
      .observeOnStart { Log.d(TAG, "OnStart: $this") }
      .observeOnResume { Log.d(TAG, "OnResume: $this") }
      .observeOnPause { Log.d(TAG, "OnPause: $this") }
      .observeOnStop { Log.d(TAG, "OnStop: $this") }
      .observeOnDestroy { Log.d(TAG, "OnDestroy: $this") }
      .observeOnAny { }
      .observeOn(On.CREATE) { }
  }
  ...

Coroutines and Flow

Add a dependency code to your module's build.gradle file.

dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:$versions.lifecycle" // over the 2.4.0-alpha01
}

We can apply to the coroutines lifecycleScope for launching suspend functions. The Lifecycle-runtime-ktx supports launchWhenStarted, launchWhenCreated, and launchWhenResumed for the lifecycleScope. However those coroutines jobs will not be canceled automatically, so they must be canceled on a specific lifecycle. And we can declare canceling together with initialization like the below.

private val job: Job by lifecycleAware {
    lifecycleScope.launchWhenCreated {
      // call suspend
    }
  }.onDestroy {
    cancel() // cancel when the lifecycle is destroyed.
  }.lazy()

We can reduce the above codes like the below using the launchOnStarted, launchOnCreated, and launchOnResume.

private val job: Job by launchOnStarted {
    // call suspend
  }.onDestroy {
    cancel()
  }.lazy()

If we need to collect one flow on the coroutines lifecycle scope, we can use like the below.

private val job: Job by launchOnStarted(repository.fetchesDataFlow()) {
    // collected value from the repository.fetchesDataFlow()
  }.onDestroy {
    cancel()
  }.lazy()

addOnRepeatingJob

The addRepeatingJob extension has been added in the new version of the Lifecycle-runtime-ktx.

Launches and runs the given block in a coroutine when this LifecycleOwner's Lifecycle is at least at state. The launched coroutine will be canceled when the lifecycle state falls below the state.

We can collect a flow on the coroutines lifecycle scope and cancel it automatically if the lifecycle falls below that state, and will restart if it's in that state again.

private val job: Job by addOnRepeatingJob(Lifecycle.State.CREATED, simpleFlow()) {
    // collected value from the fetchesDataFlow()
  }.lazy()

Find this library useful? ❀️

Support it by joining stargazers for this repository. ⭐
And follow me for my next creations! 🀩

License

Copyright 2020 skydoves (Jaewoong Eum)

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 L
You might also like...
A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisation and okio

Store A tiny Kotlin multiplatform library that assists in saving and restoring objects to and from disk using kotlinx.coroutines, kotlinx.serialisatio

Bego Chat is chat application in Kotlin and Firebase with the following features: last seen , user status like typing ,online and last seen with MVVM pattern and clean architecture

Compose ChatApp(Bego Chat) Bego Chat is Compose chat application in Kotlin and Firebase with the following features: sending all file types and abilit

LifecycleMvp 1.2 0.0 Kotlin  is MVP architecture implementation with Android Architecture Components and Kotlin language features
LifecycleMvp 1.2 0.0 Kotlin is MVP architecture implementation with Android Architecture Components and Kotlin language features

MinSDK 14+ Download Gradle Add to project level build.gradle allprojects { repositories { ... maven { url 'https://jitpack.io' }

πŸ‘‹ A common toolkit (utils) βš’οΈ built to help you further reduce Kotlin boilerplate code and improve development efficiency. Do you think 'kotlin-stdlib' or 'android-ktx' is not sweet enough? You need this! 🍭

Toolkit [ 🚧 Work in progress ⛏ πŸ‘· πŸ”§οΈ 🚧 ] Snapshot version: repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots") }

Opinionated Redux-like implementation backed by Kotlin Coroutines and Kotlin Multiplatform Mobile

CoRed CoRed is Redux-like implementation that maintains the benefits of Redux's core idea without the boilerplate. No more action types, action creato

Provides Kotlin libs and some features for building Kotlin plugins
Provides Kotlin libs and some features for building Kotlin plugins

Kotlin Plugin Provides Kotlin libs and some features for building awesome Kotlin plugins. Can be used instead of CreeperFace's KotlinLib (don't use to

RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.
RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.

RoomJetpackCompose is an app written in Kotlin and shows a simple solution to perform CRUD operations in the Room database using Kotlin Flow in clean architecture.

The most complete and powerful data-binding library and persistence infra for Kotlin 1.3, Android & Splitties Views DSL, JavaFX & TornadoFX, JSON, JDBC & SQLite, SharedPreferences.

Lychee (ex. reactive-properties) Lychee is a library to rule all the data. ToC Approach to declaring data Properties Other data-binding libraries Prop

A Kotlin Multiplatform and Compose template that allows you to easily set up your project targeting: Android, Desktop, and Web

A Kotlin Multiplatform and Compose template that allows you to easily set up your project targeting: Android, Desktop, and Web

Releases(1.0.4)
  • 1.0.4(Feb 1, 2022)

    πŸŽ‰ Released a new version 1.0.4! πŸŽ‰

    What's Changed

    • Added Proguard Rules for lazybones-viewmodel by @skydoves in https://github.com/skydoves/Lazybones/pull/6

    Full Changelog: https://github.com/skydoves/Lazybones/compare/1.0.3...1.0.4

    Source code(tar.gz)
    Source code(zip)
  • 1.0.3(Jan 31, 2022)

    πŸŽ‰ A new version 1.0.3 has been released! πŸŽ‰

    Introduce

    Now Lazybones supports lifecycleAware for Jetpack ViewModel to track and observe the lifecycle changes of the ViewModel. Basically, Lazybones-ViewModel allows you to observe two lifecycle changes: Initialize and Clear.

    class MyViewModel : ViewModel() {
    
      private val lifecycleAwareCompositeDisposable = lifecycleAware { CompositeDisposable() }
        .onInitialize {
          Log.d(TAG, "ViewModel is initialized")
        }.onClear {
          Log.d(TAG, "ViewModel is cleared")
          dispose() // dispose CompositeDisposable when viewModel is getting cleared
        }
    }
    

    What's Changed

    • Migrate to Lifecycle 2.4.0 by @skydoves in https://github.com/skydoves/Lazybones/pull/3
    • New Feature: lazybones-viewmodel by @skydoves in https://github.com/skydoves/Lazybones/pull/4
    • Implement lazybones viewmodel extensions by @skydoves in https://github.com/skydoves/Lazybones/pull/5

    Full Changelog: https://github.com/skydoves/Lazybones/compare/1.0.2...1.0.3

    Source code(tar.gz)
    Source code(zip)
  • 1.0.2(Apr 19, 2021)

    πŸŽ‰ Released a new version 1.0.2! πŸŽ‰

    Coroutines and Flow

    Add a dependency code to your module's build.gradle file.

    dependencies {
        implementation "androidx.lifecycle:lifecycle-runtime-ktx:$versions.lifecycle" // over the 2.4.0-alpha01
    }
    

    We can apply to the coroutines lifecycleScope for launching suspend functions. The Lifecycle-runtime-ktx supports launchWhenStarted, launchWhenCreated, and launchWhenResumed for the lifecycleScope. However those coroutines jobs will not be canceled automatically, so they must be canceled on a specific lifecycle. And we can declare canceling together with initialization like the below.

    private val job: Job by lifecycleAware {
        lifecycleScope.launchWhenCreated {
          // call suspend
        }
      }.onDestroy {
        cancel() // cancel when the lifecycle is destroyed.
      }.lazy()
    

    We can reduce the above codes like the below using the launchOnStarted, launchOnCreated, and launchOnResume.

    private val job: Job by launchOnStarted {
        // call suspend
      }.onDestroy {
        cancel()
      }.lazy()
    

    If we need to collect one flow on the coroutines lifecycle scope, we can use like the below.

    private val job: Job by launchOnStarted(repository.fetchesDataFlow()) {
        // collected value from the repository.fetchesDataFlow()
      }.onDestroy {
        cancel()
      }.lazy()
    

    addOnRepeatingJob

    The addRepeatingJob extension has been added in the new version of the Lifecycle-runtime-ktx.

    Launches and runs the given block in a coroutine when this LifecycleOwner's Lifecycle is at least at state. The launched coroutine will be canceled when the lifecycle state falls below the state.

    We can collect a flow on the coroutines lifecycle scope and cancel it automatically if the lifecycle falls below that state, and will restart if it's in that state again.

    private val job: Job by addOnRepeatingJob(Lifecycle.State.CREATED, simpleFlow()) {
        // collected value from the fetchesDataFlow()
      }.lazy()
    
    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Jan 10, 2020)

    Released version 1.0.1.

    • The lifecycle related to lifecycleAware functionalities receives the parameter as applied. So we can omit the it receiver.
    Before
    private val balloon: Balloon by lifecycleAware { BalloonUtils.getProfileBalloon(baseContext) }
        .onCreate { it.showAlignTop(button) }
        .onDestroy { it.dismiss() }
        .lazy()
    
    After
    private val balloon: Balloon by lifecycleAware { BalloonUtils.getProfileBalloon(baseContext) }
        .onCreate { showAlignTop(button) }
        .onDestroy { dismiss() }
        .lazy()
    
    • Implemented LifecycleAwareProperty's kotlin dsl way for observing.
    private val lifecycleAwareProperty = lifecycleAware(getDarkThemeDialog())
        .observe {
          onCreate { show() }
          onResume { restart() }
          onDestroy { dismiss() }
        }
    
    Source code(tar.gz)
    Source code(zip)
    lazybones-1.0.1.aar(40.52 KB)
  • 1.0.0(Jan 9, 2020)

Owner
Jaewoong Eum
Android and open source software engineer.❀️ Digital Nomad. Love coffee, music, magic tricks, and writing poems. Coffee Driven Development
Jaewoong Eum
A property/method accessor library for the JVM, written in Kotlin

unlok - unlock your JVM a property/method accessor library for the JVM, written in Kotlin. how to import you can import unlok from maven central just

xtrm 2 Oct 27, 2022
Backing property explained - youtube video link in documnetation

backing property => Kotlin => Getter Setter and Backing Property Screenshot Inside android studio open a file press Alt+Shift+A and search for kotlin

Vishnu Sunilkumar 0 Nov 3, 2021
LifecycleAwareGitHubSearch - The Activity Lifecycle and the ViewModel Architecture

Lifecycle-Aware GitHub Search In this project, we'll modify our GitHub search ap

null 1 Feb 8, 2022
Android View Lifecycle Extensions

Android View Lifecycle Extensions Extensions for Android View class that let you access a view lifecycle without having to create a custom view (exten

Thomas Gorisse 22 Dec 6, 2022
This is an implementation of the Fragment Lifecycle CodeLabs.

AndroidTriviaNavigation - solution code This app is the solution code for Android Kotlin Fundamentals codelab 3.2: Define navigation paths. The app is

Emmanuel Muturia 0 Oct 31, 2021
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Practical Kotlin Multiplatform on the Web λ³Έ μ €μž₯μ†ŒλŠ” μ½”ν‹€λ¦° λ©€ν‹°ν”Œλž«νΌ 기반 μ›Ή ν”„λ‘œκ·Έλž˜λ° μ›Œν¬μˆ(κ°•μ’Œ)을 μœ„ν•΄ μž‘μ„±λœ ν…œν”Œλ¦Ώ ν”„λ‘œμ νŠΈκ°€ μžˆλŠ” κ³³μž…λ‹ˆλ‹€. μ›Œν¬μˆ κ³Όμ •μ—μ„œ μ½”ν‹€λ¦° λ©€ν‹°ν”Œλž«νΌμ„ 기반으둜 ν”„λ‘ νŠΈμ—”λ“œ(front-end)λŠ” Ko

SpringRunner 14 Nov 5, 2022
Create an application with Kotlin/JVM and Kotlin/JS, and explore features around code sharing, serialization, server- and client

Building a Full Stack Web App with Kotlin Multiplatform λ³Έ μ €μž₯μ†ŒλŠ” INFCON 2022μ—μ„œ μ½”ν‹€λ¦° λ©€ν‹°ν”Œλž«νΌ 기반 μ›Ή ν”„λ‘œκ·Έλž˜λ° ν•Έμ¦ˆμ˜¨λž©μ„ μœ„ν•΄ μž‘μ„±λœ ν…œν”Œλ¦Ώ ν”„λ‘œμ νŠΈκ°€ μžˆλŠ” κ³³μž…λ‹ˆλ‹€. ν•Έμ¦ˆμ˜¨ κ³Όμ •μ—μ„œ μ½”ν‹€λ¦° λ©€ν‹°ν”Œλž«νΌμ„

Arawn Park 19 Sep 8, 2022
Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in Kotlin with Jetpack Compose and a backed in Kotlin hosted on AppEngine.

Conferences4Hall Real life Kotlin Multiplatform project with an iOS application developed in Swift with SwiftUI, an Android application developed in K

GΓ©rard Paligot 98 Dec 15, 2022
Run Kotlin/JS libraries in Kotlin/JVM and Kotlin/Native programs

Zipline This library streamlines using Kotlin/JS libraries from Kotlin/JVM and Kotlin/Native programs. It makes it possible to do continuous deploymen

Cash App 1.5k Dec 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