Skip to content

Instantly share code, notes, and snippets.

@vishalratna-microsoft
Last active June 28, 2022 07:27
Show Gist options
  • Save vishalratna-microsoft/22b601ee7b78c02922dbd3dbb9e58111 to your computer and use it in GitHub Desktop.
Save vishalratna-microsoft/22b601ee7b78c02922dbd3dbb9e58111 to your computer and use it in GitHub Desktop.
Code for LazyLifecycleManager base class
import android.app.Activity
import android.os.Handler
import android.os.Looper
import androidx.annotation.MainThread
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import *******.Closure
import *******.Once
import *******.LazyLifecycleManagerType.ViewBased
import java.lang.ref.WeakReference
/**
* Lazy lifecycle implementations could wait for draws, scenarios or some other events. Each of them
* or their combinations can represent a trigger.
* This is the general contract that needs to be adhered by all the managers.
*/
abstract class LazyLifecycleManager(owner: LifecycleOwner) {
protected val lifecycleOwner: WeakReference<LifecycleOwner> = WeakReference(owner)
private val executeLazyCreateOnce = Once()
/**
* When activate() is called, it installs a barrier at the point that guards the target code.
* This method is meant for lazy initialisations or calls that could be deferred.
* This is not meant for calls that are purely dependent on activity lifecycle transitions eg.
* registering broadcast receivers in onStart() and unregistering them in onStop(). These type
* of complimentary calls should NOT be added in lazy callbacks as we do not provide lazy versions of
* onPause() and onStop() and it is not needed too. It is always good to depend on android in these cases.
*/
@MainThread
fun activate() {
if (checkIfContractsValid()) {
lifecycleOwner.get()?.let {
setupLifecycleTrigger(it)
}
}
}
/**
* Implementation should add the actual code to fire the lazy lifecycle callbacks in this method.
* Default implementation of what happens after trigger is provided in [triggerLazyLifecycleCallbacks]
*/
abstract fun setupLifecycleTrigger(owner: LifecycleOwner)
/**
* If required, deactivates the lazy lifecycle callbacks. Can be used for cleanup of held objects too.
* Default implementation is a noop.
*/
open fun deactivate() {}
protected fun triggerLazyLifecycleCallbacks() {
this.lifecycleOwner.get()?.let { owner ->
if (owner.isVisible()) {
// Execute onLazyOnCreate() only once per instance.
with((owner as LazyLifecycleCallbacks)) {
executeLazyCreateOnce.run(object : Closure {
override fun invoke() {
// We use post instead of direct execution. executing directly might cause main thread to freeze.
uiHandler.post {
if (owner.isVisible()) {
onLazyCreate()
} else executeLazyCreateOnce.reset()
}
}
})
uiHandler.post {
if (owner.isVisible()) {
onLazyStart()
}
}
uiHandler.post {
if (owner.isVisible()) {
onLazyResume()
}
}
}
}
}
}
private fun checkIfContractsValid(): Boolean {
lifecycleOwner.get()?.let { owner ->
if (owner !is LazyLifecycleCallbacks || owner !is Activity) {
throw ClassCastException(
"Not able to cast LifeCycleOwner to LazyLifecycleCallbacks. " +
"Please implement LazyLifecycleCallbacks interface before calling activate()"
)
}
// Returns false, if the implementation does not support lazy lifecycle callbacks.
if (owner.supportsLazyLifecycleCallbacks().not()) {
return false
}
return true
}
return false
}
protected fun LifecycleOwner.isVisible(): Boolean = lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)
companion object {
private val uiHandler = Handler(Looper.getMainLooper())
}
}
// Add any new type of lifecycle manager here.
sealed class LazyLifecycleManagerType {
data class ViewBased @JvmOverloads constructor(val drawsCount: Int = 5, val timeout: Long = 6000) : LazyLifecycleManagerType()
// Add another implementations here
}
class LazyLifecycleManagerFactory constructor() {
private lateinit var lazyLifecycleCallbackManager: LazyLifecycleManager
@MainThread
fun get(owner: LifecycleOwner, type: LazyLifecycleManagerType): LazyLifecycleManager {
if (::lazyLifecycleCallbackManager.isInitialized.not()) {
lazyLifecycleCallbackManager = when (type) {
is ViewBased -> ViewBasedLazyLifecycleManager(owner, type.drawsCount, type.timeout)
}
}
return lazyLifecycleCallbackManager
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment