Skip to content

Commit

Permalink
Avoid overloading ProviderChangedWorker with many changes
Browse files Browse the repository at this point in the history
Change ProviderChangedWorker.enqueueChanged() to use unique work with REPLACE to ensure there's only at most one pending Worker waiting to execute. Add an initial delay to avoid cases where many of these Workers stack up due to their immediate launch.

Changes handleProviderChange() to be more cautious on what enqueues it should be calling, avoiding cases where we could call both enqueuePeriodic() and enqueueNext(), which can lead to multiple calls to ProviderChangedWorker (as enqueuePeriodic() can cause work to immediately run).
  • Loading branch information
ianhanniballake committed Oct 30, 2018
1 parent 7217488 commit 196ee4b
Showing 1 changed file with 29 additions and 19 deletions.
Expand Up @@ -28,6 +28,7 @@ import android.util.Log
import androidx.core.content.edit
import androidx.core.net.toUri
import androidx.work.Constraints
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequestBuilder
import androidx.work.WorkManager
import androidx.work.Worker
Expand Down Expand Up @@ -63,19 +64,25 @@ class ProviderChangedWorker(
private const val PERSISTENT_CHANGED_TAG = "persistent_changed"
private const val EXTRA_CONTENT_URI = "content_uri"
private const val PREF_PERSISTENT_LISTENERS = "persistentListeners"
private const val PROVIDER_CHANGED_THROTTLE = 250L // quarter second

internal fun enqueueSelected() {
val workManager = WorkManager.getInstance()
// Cancel changed work for the old provider
workManager.cancelUniqueWork("changed")
workManager.enqueue(OneTimeWorkRequestBuilder<ProviderChangedWorker>()
.setInputData(workDataOf(TAG to "selected"))
.build())
}

internal fun enqueueChanged() {
val workManager = WorkManager.getInstance()
workManager.enqueue(OneTimeWorkRequestBuilder<ProviderChangedWorker>()
.setInputData(workDataOf(TAG to "changed"))
.build())
workManager.beginUniqueWork("changed", ExistingWorkPolicy.REPLACE,
OneTimeWorkRequestBuilder<ProviderChangedWorker>()
.setInitialDelay(PROVIDER_CHANGED_THROTTLE, TimeUnit.MILLISECONDS)
.setInputData(workDataOf(TAG to "changed"))
.build())
.enqueue()
}

@RequiresApi(Build.VERSION_CODES.N)
Expand Down Expand Up @@ -193,24 +200,27 @@ class ProviderChangedWorker(
client.query(contentUri)?.use { allArtwork ->
val providerManager = ProviderManager.getInstance(applicationContext)
val loadFrequencySeconds = providerManager.loadFrequencySeconds
val shouldSchedule = loadFrequencySeconds > 0
val overDue = shouldSchedule &&
System.currentTimeMillis() - lastLoadedTime >= TimeUnit.SECONDS.toMillis(loadFrequencySeconds)
val enqueueNext = overDue || !isCurrentArtworkValid(client, provider)
if (enqueueNext) {
// Schedule an immediate load
if (BuildConfig.DEBUG) {
Log.d(TAG, "Scheduling an immediate load")
var enqueued = false
if (tag == "changed" || tag == PERSISTENT_CHANGED_TAG) {
val overDue = loadFrequencySeconds > 0 &&
System.currentTimeMillis() - lastLoadedTime >= TimeUnit.SECONDS.toMillis(loadFrequencySeconds)
val enqueueNext = overDue || !isCurrentArtworkValid(client, provider)
if (enqueueNext) {
// Schedule an immediate load
if (BuildConfig.DEBUG) {
Log.d(TAG, "Scheduling an immediate load")
}
ArtworkLoadWorker.enqueueNext()
enqueued = true
}
ArtworkLoadWorker.enqueueNext()
}
if (shouldSchedule) {
} else if (loadFrequencySeconds > 0) {
// Schedule the periodic work
if (BuildConfig.DEBUG) {
Log.d(TAG, "Scheduling periodic load")
}
ArtworkLoadWorker.enqueuePeriodic(loadFrequencySeconds,
providerManager.loadOnWifi)
} else {
// Clear any existing recurring work as it isn't needed anymore
ArtworkLoadWorker.cancelPeriodic()
enqueued = true
}
// Update whether the provider supports the 'Next Artwork' button
var validArtworkCount = 0
Expand All @@ -227,12 +237,12 @@ class ProviderChangedWorker(
Log.d(TAG, "Found at least $validArtworkCount artwork for $provider")
}
database.providerDao().update(provider)
if (validArtworkCount <= 1 && !enqueueNext) {
if (validArtworkCount <= 1 && !enqueued) {
if (BuildConfig.DEBUG) {
Log.d(TAG, "Requesting a load from $provider")
}
// Request a load if we don't have any more artwork
// and haven't just called enqueueNext
// and haven't just called enqueueNext / enqueuePeriodic
client.call(ProtocolConstants.METHOD_REQUEST_LOAD)
}
return Result.SUCCESS
Expand Down

0 comments on commit 196ee4b

Please sign in to comment.