Skip to content

Instantly share code, notes, and snippets.

@vishalratna-microsoft
Last active December 6, 2022 14:32
Show Gist options
  • Save vishalratna-microsoft/29595b266bd48a31ab2e06a325853d68 to your computer and use it in GitHub Desktop.
Save vishalratna-microsoft/29595b266bd48a31ab2e06a325853d68 to your computer and use it in GitHub Desktop.
ViewBased implementation of LazyLifecycleManager
import android.util.Log
import android.view.ViewTreeObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import ************.Barrier
import javax.inject.Inject
/**
* ViewBasedLazyLifecycleManager is small construct to ensure that we initialise not so necessary
* things required in onCreate()/onStart()/onResume() lazily. By default it watches on the number of draws
* on decor view or has an SLA of 4 seconds.
* While one execution is in flight, this construct prevents the subsequent calls to lazy methods.
* Implementor should implement [LazyLifecycleCallbacks] and override its methods.
* And [ViewBasedLazyLifecycleManager.activate] should be called in onResume().
*/
// Currently built for activities. Will do it for fragment once this is successful.
/////////////////////////////////////////////////////////////
// NOTE: Should always be a activity scoped singleton. /////
///////////////////////////////////////////////////////////
class ViewBasedLazyLifecycleManager(owner: LifecycleOwner, private val drawsToWait: Int, private val sla: Long) : LazyLifecycleManager(owner) {
private var state: State = State.Rest // Init with resting state
override fun setupLifecycleTrigger(owner: LifecycleOwner) {
if (state == State.Active) {
Log.d(TAG, "Execution is in flight already bailing out!")
return
}
val onPreDrawListener: ViewTreeObserver.OnPreDrawListener = object : ViewTreeObserver.OnPreDrawListener {
val lazyBarrier = Barrier.with(getCondition(owner, drawsToWait))
.withSLA(sla, true)
.runOnBreak {
val copyReference = this
with(owner as LazyLifecycleCallbacks) {
watchedView.viewTreeObserver.removeOnPreDrawListener(copyReference)
triggerLazyLifecycleCallbacks()
}
// Move to the next state.
state = state.next().also { Log.d(TAG, "Incrementing lazy lifecycle trigger state") }
}.startSLA()
override fun onPreDraw(): Boolean {
lazyBarrier.strike()
return true
}
}
(owner as LazyLifecycleCallbacks).watchedView.viewTreeObserver.addOnPreDrawListener(onPreDrawListener)
// Move to next state.
state = state.next()
}
private fun getCondition(owner: LifecycleOwner, drawsToWait: Int): Barrier.Condition {
return object : Barrier.Condition {
var drawCount = 1
val finalDrawsToWait = drawsToWait
override fun evaluate(): Boolean {
return if (owner.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
if (drawCount == finalDrawsToWait) {
true
} else {
if (drawCount > finalDrawsToWait) {
return true
}
drawCount++
false
}
} else false
}
}
}
companion object {
const val TAG = "ViewBasedLazyLifecycleCallbacks"
}
}
// Represents the state of the lifecycle callback trigger.
private enum class State {
Rest {
override fun next(): State = Active
},
Active {
override fun next(): State = Rest
};
abstract fun next(): State
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment