[fenix] Pre: introduce a RunWhenReadyQueue
This replaces the StartupTaskManager we had with a more general class. New implementation is a thread-safe "gated task executor", which either runs the task right away if it's marked as 'ready', or queries it to be executed later on. This ability to either execute or queue a task will be useful later on in the commit series.pull/600/head
parent
e8cfeeb0a1
commit
ccb08070a7
@ -1,55 +0,0 @@
|
|||||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
||||||
|
|
||||||
package org.mozilla.fenix.utils
|
|
||||||
|
|
||||||
import org.mozilla.gecko.util.ThreadUtils
|
|
||||||
|
|
||||||
typealias StartupTask = () -> Unit
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A queue of tasks that are performed at specific points during Fenix startup.
|
|
||||||
*
|
|
||||||
* This queue contains a list of startup tasks. Each task in the queue will be started once Fenix
|
|
||||||
* is visually complete.
|
|
||||||
*
|
|
||||||
* This class is not thread safe and should only be called from the main thread.
|
|
||||||
*/
|
|
||||||
class StartupTaskManager {
|
|
||||||
private var tasks = mutableListOf<StartupTask>()
|
|
||||||
private var hasStarted = false
|
|
||||||
private set
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a task to the queue.
|
|
||||||
* Each task will execute on the main thread.
|
|
||||||
*
|
|
||||||
* @param task: The task to add to the queue.
|
|
||||||
*/
|
|
||||||
@Synchronized
|
|
||||||
fun add(task: StartupTask) {
|
|
||||||
ThreadUtils.assertOnUiThread()
|
|
||||||
if (hasStarted) {
|
|
||||||
throw IllegalStateException("New tasks should not be added because queue already " +
|
|
||||||
"started, and these newly added tasks will not execute.")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.add(task)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start all tasks in the queue. When all the tasks have been started,
|
|
||||||
* clear the queue.
|
|
||||||
*/
|
|
||||||
fun start() {
|
|
||||||
ThreadUtils.assertOnUiThread()
|
|
||||||
hasStarted = true
|
|
||||||
|
|
||||||
tasks.forEach { it.invoke() }
|
|
||||||
|
|
||||||
// Anything captured by the lambda will remain captured if we hold on to these tasks,
|
|
||||||
// which takes up more memory than we need to.
|
|
||||||
tasks.clear()
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,50 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A queue that acts as a gate, either executing tasks right away if the queue is marked as "ready",
|
||||||
|
* i.e. gate is open, or queues them to be executed whenever the queue is marked as ready in the
|
||||||
|
* future, i.e. gate becomes open.
|
||||||
|
*/
|
||||||
|
class RunWhenReadyQueue {
|
||||||
|
private val tasks = CopyOnWriteArrayList<() -> Unit>()
|
||||||
|
private val isReady = AtomicBoolean(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the [task] if this queue is marked as ready, or queues it for later execution.
|
||||||
|
* Task will be executed on the main thread.
|
||||||
|
*
|
||||||
|
* @param task: The task to run now if queue is ready or queue for later execution.
|
||||||
|
*/
|
||||||
|
fun runIfReadyOrQueue(task: () -> Unit) {
|
||||||
|
if (isReady.get()) {
|
||||||
|
CoroutineScope(Dispatchers.Main).launch { task.invoke() }
|
||||||
|
} else {
|
||||||
|
tasks.add(task)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark queue as ready. Pending tasks will execute, and all tasks passed to [runIfReadyOrQueue]
|
||||||
|
* after this point will be executed immediately.
|
||||||
|
*/
|
||||||
|
fun ready() {
|
||||||
|
// Make sure that calls to `ready` are idempotent.
|
||||||
|
if (!isReady.compareAndSet(false, true)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
tasks.forEach { it.invoke() }.also { tasks.clear() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue