-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf(DependencyModule): removed
future
and replaced it with `resolv…
…edValueOf` to avoid reflection during startup and reduce the number of objects that need to be allocated
- Loading branch information
Showing
6 changed files
with
121 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 36 additions & 15 deletions
51
bugsnag-android-core/src/main/java/com/bugsnag/android/internal/dag/DependencyModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,37 +1,58 @@ | ||
package com.bugsnag.android.internal.dag | ||
|
||
import androidx.annotation.WorkerThread | ||
import com.bugsnag.android.BackgroundTaskService | ||
import com.bugsnag.android.TaskType | ||
import java.util.concurrent.Callable | ||
|
||
internal abstract class DependencyModule { | ||
|
||
private val properties = mutableListOf<Lazy<*>>() | ||
@Volatile | ||
internal var dependenciesResolved = false | ||
|
||
/** | ||
* Creates a new [Lazy] property that is marked as an object that should be resolved off the | ||
* main thread when [resolveDependencies] is called. | ||
*/ | ||
fun <T> future(initializer: () -> T): Lazy<T> { | ||
val lazy = lazy { | ||
initializer() | ||
inline fun <R> resolvedValueOf(value: () -> R): R { | ||
synchronized(this) { | ||
while (!dependenciesResolved) { | ||
// The probability that we actually need to wait for the dependencies to be resolved | ||
// is quite low, so we don't want the overhead (especially during startup) or a | ||
// ReentrantLock. Instead we want to use the Java wait() and notify() methods | ||
// so we can leverage monitor locks, which (at time of writing) typically have | ||
// no allocation cost (until there is contention) | ||
// https://android.googlesource.com/platform/art/+/master/runtime/monitor.cc#57 | ||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") | ||
(this as Object).wait() | ||
} | ||
} | ||
properties.add(lazy) | ||
return lazy | ||
|
||
return value() | ||
} | ||
|
||
@WorkerThread | ||
protected open fun resolveDependencies() { | ||
} | ||
|
||
/** | ||
* Blocks until all dependencies in the module have been constructed. This provides the option | ||
* for modules to construct objects in a background thread, then have a user block on another | ||
* thread until all the objects have been constructed. | ||
*/ | ||
fun resolveDependencies(bgTaskService: BackgroundTaskService, taskType: TaskType) { | ||
kotlin.runCatching { | ||
open fun resolveDependencies(bgTaskService: BackgroundTaskService, taskType: TaskType) { | ||
try { | ||
bgTaskService.submitTask( | ||
taskType, | ||
Runnable { | ||
properties.forEach { it.value } | ||
// Callable<Unit> avoids wrapping the Runnable in a Callable | ||
Callable { | ||
synchronized(this) { | ||
dependenciesResolved = true | ||
resolveDependencies() | ||
|
||
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") | ||
(this as Object).notifyAll() | ||
} | ||
} | ||
).get() | ||
) | ||
} catch (exception: Exception) { | ||
// ignore failures | ||
} | ||
} | ||
} |