Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
hoc081098 committed Aug 3, 2022
1 parent d56690e commit 62b9f0f
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,35 @@

package com.hoc081098.viewbindingdelegate.internal

import androidx.annotation.AnyThread
import androidx.annotation.MainThread
import androidx.collection.SimpleArrayMap
import androidx.viewbinding.ViewBinding
import java.lang.reflect.Method
import kotlin.LazyThreadSafetyMode.NONE

@MainThread
internal sealed interface MethodCache {
@MainThread
fun <T : ViewBinding> getOrPut(clazz: Class<T>): Method

operator fun <T : ViewBinding> get(clazz: Class<T>): Method?

@MainThread
fun putAll(pairs: List<Pair<Class<out ViewBinding>, Method>>)

@AnyThread
fun <T : ViewBinding> Class<T>.findMethod(): Method
}

@MainThread
private abstract class AbstractMethodCache : MethodCache {
private val cache = SimpleArrayMap<Class<out ViewBinding>, Method>()

init {
ensureMainThread()
}

override fun <T : ViewBinding> get(clazz: Class<T>): Method? = cache[clazz]

override fun <T : ViewBinding> getOrPut(clazz: Class<T>) =
cache[clazz] ?: clazz.findMethod().also { cache.put(clazz, it) }

Expand All @@ -56,15 +62,14 @@ private abstract class AbstractMethodCache : MethodCache {

private class BindMethodCache : AbstractMethodCache() {
override fun <T : ViewBinding> Class<T>.findMethod() =
measureTimeMillis("[findBindMethod]") { findBindMethod() }
measureTimeMillis("[BindMethodCache-findBindMethod]") { findBindMethod() }
}

private class InflateMethodCache : AbstractMethodCache() {
override fun <T : ViewBinding> Class<T>.findMethod() =
measureTimeMillis("[findInflateMethod]") { findInflateMethod() }
measureTimeMillis("[InflateMethodCache-findInflateMethod]") { findInflateMethod() }
}

@MainThread
internal object CacheContainer {
private val bindMethodCache by lazy(NONE) {
ensureMainThread()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ package com.hoc081098.viewbindingdelegate.internal

import android.content.Context
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import androidx.core.content.ContextCompat
import androidx.viewbinding.ViewBinding
import java.lang.reflect.Method
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadFactory
import java.util.concurrent.ThreadPoolExecutor
Expand Down Expand Up @@ -57,28 +55,36 @@ internal object PreloadMethods {
}

@MainThread
internal inline fun Context.preload(
internal fun Context.preload(
tag: String,
classes: Array<out KClass<out ViewBinding>>,
@WorkerThread crossinline func: Class<out ViewBinding>.() -> Method,
@MainThread crossinline onSuccess: (List<Pair<Class<out ViewBinding>, Method>>) -> Unit
kClasses: Array<out KClass<out ViewBinding>>,
cache: MethodCache
) {
if (classes.isEmpty()) return
if (kClasses.isEmpty()) {
log { "$tag empty kClasses" }
return
}
val classes = kClasses.mapNotNull { kClass ->
kClass.java.takeIf { cache[it] === null }
}
if (classes.isEmpty()) {
log { "$tag empty classes" }
return
}

val mainExecutor = ContextCompat.getMainExecutor(applicationContext)

ioExecutor.execute {
log { "$tag start... classes=${classes.map { it.simpleName }}" }
log { "$tag start... classes=${kClasses.map { it.simpleName }}" }

val methods = measureTimeMillis(tag) {
classes.map {
val clazz = it.java
clazz to clazz.func()
classes.map { clazz ->
clazz to cache.run { clazz.findMethod() }
}
}

mainExecutor.execute {
onSuccess(methods)
cache.putAll(methods)
log { "$tag done" }
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ package com.hoc081098.viewbindingdelegate.internal

import android.os.Looper
import android.util.Log
import kotlin.system.measureTimeMillis
import kotlin.system.measureNanoTime

@PublishedApi
internal fun ensureMainThread(): Unit = check(Looper.getMainLooper() == Looper.myLooper()) {
Expand All @@ -40,15 +40,15 @@ private const val DEBUG = true

internal inline fun log(crossinline message: () -> String) {
if (DEBUG) {
Log.d("ViewBinding", message())
Log.d("ViewBindingDelegate", message())
}
}

internal inline fun <T> measureTimeMillis(tag: String, crossinline block: () -> T): T =
if (DEBUG) {
val t: T
val time = measureTimeMillis { t = block() }
log { "$tag taken time=$time ms ~ ${time / 1_000.0} s" }
val time = measureNanoTime { t = block() }
log { "$tag taken time=$time ns ~ ${time / 1_000_000.0} ms" }
t
} else {
block()
Expand Down
14 changes: 4 additions & 10 deletions library/src/main/java/com/hoc081098/viewbindingdelegate/preload.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,19 @@ import kotlin.reflect.KClass
@MainThread
public fun Context.preloadBindMethods(vararg classes: KClass<out ViewBinding>): Unit =
PreloadMethods.run {
val bindMethodCache = CacheContainer.provideBindMethodCache()

preload(
tag = "[preloadBindMethods]",
classes = classes,
func = { bindMethodCache.run { findMethod() } },
onSuccess = { bindMethodCache.putAll(it) }
kClasses = classes,
cache = CacheContainer.provideBindMethodCache()
)
}

@MainThread
public fun Context.preloadInflateMethods(vararg classes: KClass<out ViewBinding>): Unit =
PreloadMethods.run {
val inflateMethodCache = CacheContainer.provideInflateMethodCache()

preload(
tag = "[preloadInflateMethods]",
classes = classes,
func = { inflateMethodCache.run { findMethod() } },
onSuccess = { inflateMethodCache.putAll(it) }
kClasses = classes,
cache = CacheContainer.provideInflateMethodCache()
)
}

0 comments on commit 62b9f0f

Please sign in to comment.