diff --git a/leakcanary/leakcanary-android-release/src/main/java/leakcanary/ScreenOffTrigger.kt b/leakcanary/leakcanary-android-release/src/main/java/leakcanary/ScreenOffTrigger.kt index 60f8136d37..cfb48cd57f 100644 --- a/leakcanary/leakcanary-android-release/src/main/java/leakcanary/ScreenOffTrigger.kt +++ b/leakcanary/leakcanary-android-release/src/main/java/leakcanary/ScreenOffTrigger.kt @@ -9,7 +9,11 @@ import android.content.Intent.ACTION_SCREEN_ON import android.content.IntentFilter import android.os.Build import java.util.concurrent.Executor +import java.util.concurrent.Executors +import java.util.concurrent.ScheduledExecutorService +import java.util.concurrent.TimeUnit import leakcanary.internal.friendly.checkMainThread +import leakcanary.internal.friendly.checkNotMainThread import shark.SharkLog class ScreenOffTrigger( @@ -21,6 +25,16 @@ class ScreenOffTrigger( */ private val analysisExecutor: Executor, + /** + * The initial delay (in milliseconds) before the [analysisExecutor] starts + * + * If not specified, the default initial delay is set to 100 milliseconds. + */ + private val analysisExecutorDelayMillis: Long = + TimeUnit.SECONDS.toMillis( + INITIAL_EXECUTOR_DELAY_IN_MILLI + ), + /** * Called back with a [HeapAnalysisJob.Result] after the screen went off and a * heap analysis was attempted. This is called on the same thread that the analysis was @@ -34,6 +48,8 @@ class ScreenOffTrigger( }, ) { + private var delayedScheduledExecutorService: DelayedScheduledExecutorService? = null + @Volatile private var currentJob: HeapAnalysisJob? = null @@ -47,7 +63,8 @@ class ScreenOffTrigger( val job = analysisClient.newJob(JobContext(ScreenOffTrigger::class)) currentJob = job - analysisExecutor.execute { + delayedScheduledExecutorService?.schedule { + checkNotMainThread() val result = job.execute() currentJob = null analysisCallback(result) @@ -62,6 +79,7 @@ class ScreenOffTrigger( fun start() { checkMainThread() + initializeDelayedExecutor() val intentFilter = IntentFilter().apply { addAction(ACTION_SCREEN_ON) addAction(ACTION_SCREEN_OFF) @@ -76,6 +94,49 @@ class ScreenOffTrigger( fun stop() { checkMainThread() + shutDownDelayedExecutor() application.unregisterReceiver(screenReceiver) } + + private fun initializeDelayedExecutor(){ + if (delayedScheduledExecutorService == null) { + delayedScheduledExecutorService = DelayedScheduledExecutorService(analysisExecutor, analysisExecutorDelayMillis ) + } + } + + private fun shutDownDelayedExecutor(){ + delayedScheduledExecutorService?.shutdownNow() + delayedScheduledExecutorService = null + } + + private class DelayedScheduledExecutorService( + private val analysisExecutor: Executor, + private val analysisExecutorDelayMillis: Long + ) { + + private val scheduledExecutor: ScheduledExecutorService by lazy { + Executors.newScheduledThreadPool(1) + } + + /** + * Runs the specified [action] after an initial [analysisExecutorDelayMillis] + */ + fun schedule(action: Runnable) { + scheduledExecutor.schedule( + { + analysisExecutor.execute(action) + }, + analysisExecutorDelayMillis, + TimeUnit.MILLISECONDS + ) + } + + fun shutdownNow() { + scheduledExecutor.shutdownNow() + } + } + + private companion object { + private const val INITIAL_EXECUTOR_DELAY_IN_MILLI = 100L + } } diff --git a/leakcanary/leakcanary-android-release/src/main/java/leakcanary/internal/friendly/Friendly.kt b/leakcanary/leakcanary-android-release/src/main/java/leakcanary/internal/friendly/Friendly.kt index cf621fbfbb..e70a81a460 100644 --- a/leakcanary/leakcanary-android-release/src/main/java/leakcanary/internal/friendly/Friendly.kt +++ b/leakcanary/leakcanary-android-release/src/main/java/leakcanary/internal/friendly/Friendly.kt @@ -7,8 +7,9 @@ internal inline val mainHandler get() = leakcanary.internal.mainHandler internal inline fun checkMainThread() = leakcanary.internal.checkMainThread() +internal inline fun checkNotMainThread() = leakcanary.internal.checkNotMainThread() internal inline fun noOpDelegate(): T = leakcanary.internal.noOpDelegate() internal inline fun measureDurationMillis(block: () -> Unit) = - leakcanary.internal.measureDurationMillis(block) \ No newline at end of file + leakcanary.internal.measureDurationMillis(block)