Skip to content

Instantly share code, notes, and snippets.

@hoc081098
Created January 10, 2023 10:10
Show Gist options
  • Save hoc081098/6e1856172f883ce53c859729ef699e4b to your computer and use it in GitHub Desktop.
Save hoc081098/6e1856172f883ce53c859729ef699e4b to your computer and use it in GitHub Desktop.
@HiltAndroidApp
class MyApp : Application(), ImageLoaderFactory {
@Inject
internal lateinit var activityTracker: TopResumedActivityTracker
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(activityTracker)
}
}
class RealAuthRepository @Inject constructor(
private val activityTracker: TopResumedActivityTracker,
) : AuthRepository {
fun signIn() {
val activity = activityTracker.topResumedActivity ?: return
// start other activity for signing in ... (via browser / chrome custom tab intent, eg. Auth0)
}
}
@Singleton
class TopResumedActivityTracker @Inject constructor(
appCoroutineScope: AppCoroutineScope,
) : Application.ActivityLifecycleCallbacks {
@Retention(value = AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS, AnnotationTarget.PROPERTY)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
annotation class Experimental
/**
* Keep the top resumed activity and its identity hashcode.
*/
private val _topResumedActivityStateFlow = MutableStateFlow<Pair<Activity, Int>?>(null)
init {
if (BuildConfig.DEBUG) {
_topResumedActivityStateFlow
.onEach { Timber.d("[topResumedActivityStateFlow] $it") }
.launchIn(appCoroutineScope)
}
}
@get:AnyThread
val topResumedActivity: Activity?
get() = _topResumedActivityStateFlow.value?.first
@Experimental
val topResumedActivityStateFlow: StateFlow<Activity?> =
_topResumedActivityStateFlow
.asStateFlow()
.map { it?.first }
.stateIn(
scope = appCoroutineScope,
started = SharingStarted.Eagerly,
initialValue = null
)
@Suppress("NOTHING_TO_INLINE")
private inline fun clearTopResumedActivity(activity: Activity) {
Timber.d("[clearMainActivity] activity=$activity, ref=${_topResumedActivityStateFlow.value}")
_topResumedActivityStateFlow.update { old ->
old?.let {
if (System.identityHashCode(activity) == it.second) {
null
} else {
it
}
}
}
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit
override fun onActivityStarted(activity: Activity) = Unit
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit
override fun onActivityResumed(activity: Activity) {
Timber.d("[onActivityResumed] activity=$activity, ref=${_topResumedActivityStateFlow.value}")
_topResumedActivityStateFlow.update { it ?: (activity to System.identityHashCode(activity)) }
}
override fun onActivityPaused(activity: Activity) = clearTopResumedActivity(activity)
override fun onActivityStopped(activity: Activity) = clearTopResumedActivity(activity)
override fun onActivityDestroyed(activity: Activity) = clearTopResumedActivity(activity)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment