Skip to content

Commit 96a6a66

Browse files
committed
Added queue back off logic
1 parent 690decf commit 96a6a66

File tree

6 files changed

+100
-5
lines changed

6 files changed

+100
-5
lines changed

fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchHandlerImpl.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ class FetchHandlerImpl(private val namespace: String,
522522
}
523523

524524
private fun startPriorityQueueIfNotStarted() {
525+
priorityListProcessor.resetBackOffTime()
525526
if (priorityListProcessor.isStopped && !isTerminating) {
526527
priorityListProcessor.start()
527528
}

fetch2/src/main/java/com/tonyodev/fetch2/fetch/FetchModulesBuilder.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ object FetchModulesBuilder {
4747
val newModules = Modules(fetchConfiguration, newHandlerWrapper, newDatabaseManager,
4848
downloadManagerCoordinator, listenerCoordinator)
4949
holderMap[fetchConfiguration.namespace] = Holder(newHandlerWrapper, newDatabaseManager,
50-
downloadManagerCoordinator, listenerCoordinator)
50+
downloadManagerCoordinator, listenerCoordinator, newModules.networkInfoProvider)
5151
newModules
5252
}
5353
modules.handlerWrapper.incrementUsageCounter()
@@ -65,6 +65,7 @@ object FetchModulesBuilder {
6565
holder.listenerCoordinator.clearAll()
6666
holder.databaseManager.close()
6767
holder.downloadManagerCoordinator.clearAll()
68+
holder.networkInfoProvider.unregisterAllNetworkBroadcastReceivers()
6869
holderMap.remove(namespace)
6970
}
7071
}
@@ -74,7 +75,8 @@ object FetchModulesBuilder {
7475
data class Holder(val handlerWrapper: HandlerWrapper,
7576
val databaseManager: DatabaseManager,
7677
val downloadManagerCoordinator: DownloadManagerCoordinator,
77-
val listenerCoordinator: ListenerCoordinator)
78+
val listenerCoordinator: ListenerCoordinator,
79+
val networkInfoProvider: NetworkInfoProvider)
7880

7981
class Modules constructor(val fetchConfiguration: FetchConfiguration,
8082
val handlerWrapper: HandlerWrapper,

fetch2/src/main/java/com/tonyodev/fetch2/helper/PriorityListProcessor.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ interface PriorityListProcessor<out T> {
1616
fun pause()
1717
fun resume()
1818
fun getPriorityList(): List<T>
19+
fun resetBackOffTime()
1920

2021
interface Delegate {
2122

fetch2/src/main/java/com/tonyodev/fetch2/helper/PriorityListProcessorImpl.kt

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
package com.tonyodev.fetch2.helper
22

3+
import android.content.BroadcastReceiver
4+
import android.content.Context
5+
import android.content.Intent
36
import com.tonyodev.fetch2.*
47
import com.tonyodev.fetch2.downloader.DownloadManager
58
import com.tonyodev.fetch2core.HandlerWrapper
69
import com.tonyodev.fetch2.provider.DownloadProvider
710
import com.tonyodev.fetch2.provider.NetworkInfoProvider
8-
import com.tonyodev.fetch2.util.PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS
11+
import com.tonyodev.fetch2.util.DEFAULT_PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS
912
import com.tonyodev.fetch2.NetworkType
1013
import com.tonyodev.fetch2.fetch.ListenerCoordinator
1114
import com.tonyodev.fetch2core.Logger
1215
import com.tonyodev.fetch2core.isFetchFileServerUrl
16+
import java.util.concurrent.TimeUnit
1317

1418
class PriorityListProcessorImpl constructor(private val handlerWrapper: HandlerWrapper,
1519
private val downloadProvider: DownloadProvider,
@@ -33,10 +37,29 @@ class PriorityListProcessorImpl constructor(private val handlerWrapper: HandlerW
3337
private var stopped = true
3438
override val isStopped: Boolean
3539
get() = stopped
40+
@Volatile
41+
private var backOffTime = DEFAULT_PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS
42+
private val networkBroadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
43+
44+
override fun onReceive(context: Context?, intent: Intent?) {
45+
if (context != null && !stopped && !paused && networkInfoProvider.isNetworkAvailable
46+
&& backOffTime > DEFAULT_PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS) {
47+
resetBackOffTime()
48+
}
49+
}
50+
}
51+
52+
init {
53+
networkInfoProvider.registerNetworkBroadcastReceiver(networkBroadcastReceiver)
54+
}
55+
3656
private val priorityIteratorRunnable = Runnable {
3757
if (canContinueToProcess()) {
3858
if (downloadManager.canAccommodateNewDownload() && canContinueToProcess()) {
3959
val priorityList = getPriorityList()
60+
if (priorityList.isEmpty() || !networkInfoProvider.isNetworkAvailable) {
61+
increaseBackOffTime()
62+
}
4063
delegate?.onHasActiveDownloads(priorityList.isNotEmpty())
4164
for (index in 0..priorityList.lastIndex) {
4265
if (downloadManager.canAccommodateNewDownload() && canContinueToProcess()) {
@@ -70,6 +93,7 @@ class PriorityListProcessorImpl constructor(private val handlerWrapper: HandlerW
7093

7194
override fun start() {
7295
synchronized(lock) {
96+
resetBackOffTime()
7397
stopped = false
7498
paused = false
7599
delegate?.onHasActiveDownloads(true)
@@ -101,6 +125,7 @@ class PriorityListProcessorImpl constructor(private val handlerWrapper: HandlerW
101125

102126
override fun resume() {
103127
synchronized(lock) {
128+
resetBackOffTime()
104129
paused = false
105130
stopped = false
106131
registerPriorityIterator()
@@ -121,7 +146,7 @@ class PriorityListProcessorImpl constructor(private val handlerWrapper: HandlerW
121146

122147
private fun registerPriorityIterator() {
123148
if (downloadConcurrentLimit > 0) {
124-
handlerWrapper.postDelayed(priorityIteratorRunnable, PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS)
149+
handlerWrapper.postDelayed(priorityIteratorRunnable, backOffTime)
125150
}
126151
}
127152

@@ -135,4 +160,27 @@ class PriorityListProcessorImpl constructor(private val handlerWrapper: HandlerW
135160
return !stopped && !paused
136161
}
137162

163+
override fun resetBackOffTime() {
164+
synchronized(lock) {
165+
backOffTime = DEFAULT_PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS
166+
unregisterPriorityIterator()
167+
registerPriorityIterator()
168+
logger.d("PriorityIterator backoffTime reset to $backOffTime milliseconds")
169+
}
170+
}
171+
172+
private fun increaseBackOffTime() {
173+
backOffTime = if (backOffTime == DEFAULT_PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS) {
174+
ONE_MINUTE_IN_MILLISECONDS
175+
} else {
176+
backOffTime * 2L
177+
}
178+
val minutes = TimeUnit.MILLISECONDS.toMinutes(backOffTime)
179+
logger.d("PriorityIterator backoffTime increased to $minutes minute(s)")
180+
}
181+
182+
private companion object {
183+
private const val ONE_MINUTE_IN_MILLISECONDS = 60000L
184+
}
185+
138186
}

fetch2/src/main/java/com/tonyodev/fetch2/provider/NetworkInfoProvider.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,56 @@
11
package com.tonyodev.fetch2.provider
22

3+
import android.content.BroadcastReceiver
34
import android.content.Context
5+
import android.content.IntentFilter
6+
import android.net.ConnectivityManager
47
import com.tonyodev.fetch2.NetworkType
58
import com.tonyodev.fetch2core.isNetworkAvailable
69
import com.tonyodev.fetch2core.isOnWiFi
710

811

912
class NetworkInfoProvider constructor(private val context: Context) {
1013

14+
private val lock = Any()
15+
private val broadcastReceiverSet = mutableSetOf<BroadcastReceiver>()
16+
17+
fun registerNetworkBroadcastReceiver(broadcastReceiver: BroadcastReceiver) {
18+
synchronized(lock) {
19+
val intentFilter = IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
20+
try {
21+
broadcastReceiverSet.add(broadcastReceiver)
22+
context.registerReceiver(broadcastReceiver, intentFilter)
23+
} catch (e: Exception) {
24+
25+
}
26+
}
27+
}
28+
29+
fun unregisterNetworkBroadcastReceiver(broadcastReceiver: BroadcastReceiver) {
30+
synchronized(lock) {
31+
try {
32+
broadcastReceiverSet.remove(broadcastReceiver)
33+
context.unregisterReceiver(broadcastReceiver)
34+
} catch (e: Exception) {
35+
36+
}
37+
}
38+
}
39+
40+
fun unregisterAllNetworkBroadcastReceivers() {
41+
synchronized(lock) {
42+
val broadcastReceivers = broadcastReceiverSet.toList()
43+
broadcastReceivers.forEach { broadcastReceiver ->
44+
try {
45+
broadcastReceiverSet.remove(broadcastReceiver)
46+
context.unregisterReceiver(broadcastReceiver)
47+
} catch (e: Exception) {
48+
49+
}
50+
}
51+
}
52+
}
53+
1154
fun isOnAllowedNetwork(networkType: NetworkType): Boolean {
1255
if (networkType == NetworkType.WIFI_ONLY && context.isOnWiFi()) {
1356
return true

fetch2/src/main/java/com/tonyodev/fetch2/util/Defaults.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const val DEFAULT_UNIQUE_IDENTIFIER = 0L
1313
const val DEFAULT_DOWNLOAD_SPEED_REPORTING_INTERVAL_IN_MILLISECONDS = 1_000L
1414
const val DEFAULT_CONCURRENT_LIMIT = 1
1515
const val EMPTY_JSON_OBJECT_STRING = "{}"
16-
const val PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS = 500L
16+
const val DEFAULT_PRIORITY_QUEUE_INTERVAL_IN_MILLISECONDS = 500L
1717
const val DEFAULT_AUTO_START = true
1818
const val DEFAULT_RETRY_ON_NETWORK_GAIN = true
1919
const val DEFAULT_FILE_SLICE_NO_LIMIT_SET = -1

0 commit comments

Comments
 (0)