Merge "Preserve backwards compatbility in how WorkManager task executors are configured in test mode." into androidx-master-dev
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index f0b9bf1..fd3836f 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -35,9 +35,8 @@
prebuilts(LibraryGroups.ARCH_CORE, "2.1.0-rc01")
prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, "1.0.0")
prebuilts(LibraryGroups.AUTOFILL, "1.0.0-alpha02")
- prebuilts(LibraryGroups.BENCHMARK, "benchmark", "1.0.0-alpha03")
- ignore(LibraryGroups.BENCHMARK.group, "benchmark-common")
ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
+ prebuilts(LibraryGroups.BENCHMARK, "1.0.0-alpha04")
prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.0.0-beta01")
prebuilts(LibraryGroups.BROWSER, "1.2.0-alpha07")
ignore(LibraryGroups.CAMERA.group, "camera-testing")
diff --git a/paging/common/api/3.0.0-alpha01.txt b/paging/common/api/3.0.0-alpha01.txt
index 684ff7e..cd5b0722 100644
--- a/paging/common/api/3.0.0-alpha01.txt
+++ b/paging/common/api/3.0.0-alpha01.txt
@@ -181,9 +181,11 @@
method public suspend Object buildAsync(kotlin.coroutines.Continuation<? super androidx.paging.PagedList<Value>> p);
method public androidx.paging.PagedList.Builder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
method public androidx.paging.PagedList.Builder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
- method public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setFetchDispatcher(kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
method public androidx.paging.PagedList.Builder<Key,Value> setInitialKey(Key? initialKey);
- method public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setNotifyDispatcher(kotlinx.coroutines.CoroutineDispatcher notifyDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
}
public abstract static class PagedList.Callback {
diff --git a/paging/common/api/current.txt b/paging/common/api/current.txt
index 684ff7e..cd5b0722 100644
--- a/paging/common/api/current.txt
+++ b/paging/common/api/current.txt
@@ -181,9 +181,11 @@
method public suspend Object buildAsync(kotlin.coroutines.Continuation<? super androidx.paging.PagedList<Value>> p);
method public androidx.paging.PagedList.Builder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
method public androidx.paging.PagedList.Builder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
- method public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setFetchDispatcher(kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
method public androidx.paging.PagedList.Builder<Key,Value> setInitialKey(Key? initialKey);
- method public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setNotifyDispatcher(kotlinx.coroutines.CoroutineDispatcher notifyDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
}
public abstract static class PagedList.Callback {
diff --git a/paging/common/api/restricted_3.0.0-alpha01.txt b/paging/common/api/restricted_3.0.0-alpha01.txt
index 9dab4f5..87c9156 100644
--- a/paging/common/api/restricted_3.0.0-alpha01.txt
+++ b/paging/common/api/restricted_3.0.0-alpha01.txt
@@ -140,9 +140,10 @@
}
public abstract class PagedList<T> extends java.util.AbstractList<T> {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public PagedList(kotlinx.coroutines.CoroutineScope coroutineScope, androidx.paging.PagedSource<?,T> pagedSource, androidx.paging.PagedStorage<T> storage, kotlinx.coroutines.CoroutineDispatcher notifyDispatcher, kotlinx.coroutines.CoroutineDispatcher backgroundDispatcher, androidx.paging.PagedList.BoundaryCallback<T>? boundaryCallback, androidx.paging.PagedList.Config config);
method public void addWeakCallback(java.util.List<? extends T>? previousSnapshot, androidx.paging.PagedList.Callback callback);
method public void addWeakLoadStateListener(kotlin.jvm.functions.Function3<? super androidx.paging.PagedList.LoadType,? super androidx.paging.PagedList.LoadState,? super java.lang.Throwable,kotlin.Unit> listener);
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final suspend <K, T> Object create(androidx.paging.PagedSource<K,T> p, kotlinx.coroutines.CoroutineScope pagedSource, java.util.concurrent.Executor coroutineScope, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, androidx.paging.PagedList.BoundaryCallback<T>? initialLoadExecutor, androidx.paging.PagedList.Config boundaryCallback, K? config, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> key);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final suspend <K, T> Object create(androidx.paging.PagedSource<K,T> p, kotlinx.coroutines.CoroutineScope pagedSource, kotlinx.coroutines.CoroutineDispatcher coroutineScope, kotlinx.coroutines.CoroutineDispatcher notifyDispatcher, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher, androidx.paging.PagedList.BoundaryCallback<T>? initialFetchDispatcher, androidx.paging.PagedList.Config boundaryCallback, K? config, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> key);
method public abstract void detach();
method public T? get(int index);
method public androidx.paging.PagedList.Config getConfig();
@@ -188,9 +189,11 @@
method public suspend Object buildAsync(kotlin.coroutines.Continuation<? super androidx.paging.PagedList<Value>> p);
method public androidx.paging.PagedList.Builder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
method public androidx.paging.PagedList.Builder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
- method public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setFetchDispatcher(kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
method public androidx.paging.PagedList.Builder<Key,Value> setInitialKey(Key? initialKey);
- method public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setNotifyDispatcher(kotlinx.coroutines.CoroutineDispatcher notifyDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
}
public abstract static class PagedList.Callback {
@@ -201,7 +204,7 @@
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class PagedList.Companion {
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public suspend <K, T> Object create(androidx.paging.PagedSource<K,T> pagedSource, kotlinx.coroutines.CoroutineScope coroutineScope, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, java.util.concurrent.Executor initialLoadExecutor, androidx.paging.PagedList.BoundaryCallback<T>? boundaryCallback, androidx.paging.PagedList.Config config, K? key, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> p);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public suspend <K, T> Object create(androidx.paging.PagedSource<K,T> pagedSource, kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.CoroutineDispatcher notifyDispatcher, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher, kotlinx.coroutines.CoroutineDispatcher initialFetchDispatcher, androidx.paging.PagedList.BoundaryCallback<T>? boundaryCallback, androidx.paging.PagedList.Config config, K? key, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> p);
}
public static final class PagedList.Config {
diff --git a/paging/common/api/restricted_current.txt b/paging/common/api/restricted_current.txt
index 9dab4f5..87c9156 100644
--- a/paging/common/api/restricted_current.txt
+++ b/paging/common/api/restricted_current.txt
@@ -140,9 +140,10 @@
}
public abstract class PagedList<T> extends java.util.AbstractList<T> {
+ ctor @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public PagedList(kotlinx.coroutines.CoroutineScope coroutineScope, androidx.paging.PagedSource<?,T> pagedSource, androidx.paging.PagedStorage<T> storage, kotlinx.coroutines.CoroutineDispatcher notifyDispatcher, kotlinx.coroutines.CoroutineDispatcher backgroundDispatcher, androidx.paging.PagedList.BoundaryCallback<T>? boundaryCallback, androidx.paging.PagedList.Config config);
method public void addWeakCallback(java.util.List<? extends T>? previousSnapshot, androidx.paging.PagedList.Callback callback);
method public void addWeakLoadStateListener(kotlin.jvm.functions.Function3<? super androidx.paging.PagedList.LoadType,? super androidx.paging.PagedList.LoadState,? super java.lang.Throwable,kotlin.Unit> listener);
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final suspend <K, T> Object create(androidx.paging.PagedSource<K,T> p, kotlinx.coroutines.CoroutineScope pagedSource, java.util.concurrent.Executor coroutineScope, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, androidx.paging.PagedList.BoundaryCallback<T>? initialLoadExecutor, androidx.paging.PagedList.Config boundaryCallback, K? config, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> key);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final suspend <K, T> Object create(androidx.paging.PagedSource<K,T> p, kotlinx.coroutines.CoroutineScope pagedSource, kotlinx.coroutines.CoroutineDispatcher coroutineScope, kotlinx.coroutines.CoroutineDispatcher notifyDispatcher, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher, androidx.paging.PagedList.BoundaryCallback<T>? initialFetchDispatcher, androidx.paging.PagedList.Config boundaryCallback, K? config, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> key);
method public abstract void detach();
method public T? get(int index);
method public androidx.paging.PagedList.Config getConfig();
@@ -188,9 +189,11 @@
method public suspend Object buildAsync(kotlin.coroutines.Continuation<? super androidx.paging.PagedList<Value>> p);
method public androidx.paging.PagedList.Builder<Key,Value> setBoundaryCallback(androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback);
method public androidx.paging.PagedList.Builder<Key,Value> setCoroutineScope(kotlinx.coroutines.CoroutineScope coroutineScope);
- method public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setFetchDispatcher(kotlinx.coroutines.CoroutineDispatcher fetchDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setFetchExecutor(java.util.concurrent.Executor fetchExecutor);
method public androidx.paging.PagedList.Builder<Key,Value> setInitialKey(Key? initialKey);
- method public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
+ method public androidx.paging.PagedList.Builder<Key,Value> setNotifyDispatcher(kotlinx.coroutines.CoroutineDispatcher notifyDispatcher);
+ method @Deprecated public androidx.paging.PagedList.Builder<Key,Value> setNotifyExecutor(java.util.concurrent.Executor notifyExecutor);
}
public abstract static class PagedList.Callback {
@@ -201,7 +204,7 @@
}
@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static final class PagedList.Companion {
- method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public suspend <K, T> Object create(androidx.paging.PagedSource<K,T> pagedSource, kotlinx.coroutines.CoroutineScope coroutineScope, java.util.concurrent.Executor notifyExecutor, java.util.concurrent.Executor fetchExecutor, java.util.concurrent.Executor initialLoadExecutor, androidx.paging.PagedList.BoundaryCallback<T>? boundaryCallback, androidx.paging.PagedList.Config config, K? key, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> p);
+ method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public suspend <K, T> Object create(androidx.paging.PagedSource<K,T> pagedSource, kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.CoroutineDispatcher notifyDispatcher, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher, kotlinx.coroutines.CoroutineDispatcher initialFetchDispatcher, androidx.paging.PagedList.BoundaryCallback<T>? boundaryCallback, androidx.paging.PagedList.Config config, K? key, kotlin.coroutines.Continuation<? super androidx.paging.PagedList<T>> p);
}
public static final class PagedList.Config {
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index 3920cb8..e6075be 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -32,7 +32,7 @@
compile("androidx.annotation:annotation:1.1.0")
compile(ARCH_CORE_COMMON)
api(KOTLIN_STDLIB)
- api(KOTLIN_COROUTINES)
+ api(KOTLIN_COROUTINES_CORE)
testCompile(JUNIT)
testCompile(MOCKITO_CORE)
@@ -40,6 +40,7 @@
exclude group: 'org.mockito' // to keep control on the mockito version
}
testImplementation project(':internal-testutils-common')
+ testImplementation project(':internal-testutils-ktx')
testImplementation(KOTLIN_TEST_COMMON)
testImplementation(TRUTH)
}
diff --git a/paging/common/src/main/kotlin/androidx/paging/ContiguousPagedList.kt b/paging/common/src/main/kotlin/androidx/paging/ContiguousPagedList.kt
index e583f30..223d698 100644
--- a/paging/common/src/main/kotlin/androidx/paging/ContiguousPagedList.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/ContiguousPagedList.kt
@@ -20,9 +20,8 @@
import androidx.annotation.RestrictTo
import androidx.paging.PagedSource.KeyProvider
import androidx.paging.PagedSource.LoadResult.Companion.COUNT_UNDEFINED
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.asCoroutineDispatcher
-import java.util.concurrent.Executor
/**
* @hide
@@ -31,17 +30,18 @@
open class ContiguousPagedList<K : Any, V : Any>(
pagedSource: PagedSource<K, V>,
coroutineScope: CoroutineScope,
- mainThreadExecutor: Executor,
- backgroundThreadExecutor: Executor,
+ notifyDispatcher: CoroutineDispatcher,
+ backgroundDispatcher: CoroutineDispatcher,
boundaryCallback: BoundaryCallback<V>?,
config: Config,
initialResult: PagedSource.LoadResult<K, V>,
lastLoad: Int
) : PagedList<V>(
+ coroutineScope,
pagedSource,
PagedStorage<V>(),
- mainThreadExecutor,
- backgroundThreadExecutor,
+ notifyDispatcher,
+ backgroundDispatcher,
boundaryCallback,
config
), PagedStorage.Callback, Pager.PageConsumer<V> {
@@ -75,8 +75,8 @@
coroutineScope,
config,
pagedSource,
- mainThreadExecutor.asCoroutineDispatcher(),
- backgroundThreadExecutor.asCoroutineDispatcher(),
+ notifyDispatcher,
+ backgroundDispatcher,
this,
initialResult,
storage
diff --git a/paging/common/src/main/kotlin/androidx/paging/InitialPagedList.kt b/paging/common/src/main/kotlin/androidx/paging/InitialPagedList.kt
index 4aa8792..7407055 100644
--- a/paging/common/src/main/kotlin/androidx/paging/InitialPagedList.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/InitialPagedList.kt
@@ -17,7 +17,7 @@
package androidx.paging
import androidx.annotation.RestrictTo
-import androidx.paging.futures.DirectExecutor
+import androidx.paging.futures.DirectDispatcher
import kotlinx.coroutines.CoroutineScope
/**
@@ -37,8 +37,8 @@
) : ContiguousPagedList<K, V>(
pagedSource,
coroutineScope,
- DirectExecutor,
- DirectExecutor,
+ DirectDispatcher,
+ DirectDispatcher,
null,
config,
PagedSource.LoadResult.empty(),
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagedList.kt b/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
index 6d56579..c0bde0e 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
@@ -28,10 +28,13 @@
import androidx.paging.PagedList.LoadState
import androidx.paging.PagedList.LoadType
import androidx.paging.PagedSource.KeyProvider
-import androidx.paging.futures.DirectExecutor
+import androidx.paging.futures.DirectDispatcher
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.asCoroutineDispatcher
+import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.lang.ref.WeakReference
@@ -45,10 +48,11 @@
*
* Used to observe the [LoadState] of any [LoadType] (REFRESH/START/END). For UI purposes (swipe
* refresh, loading spinner, retry button), this is typically done by registering a
- * [LoadStateListener] with the [PagedListAdapter] or [AsyncPagedListDiffer].
+ * [LoadStateListener] with the [androidx.paging.PagedListAdapter] or
+ * [androidx.paging.AsyncPagedListDiffer].
*
- * These calls will be dispatched on the executor defined by [Builder.setNotifyExecutor], which is
- * generally the main/UI thread.
+ * These calls will be dispatched on the executor defined by [PagedList.Builder.setNotifyExecutor],
+ * which is generally the main/UI thread.
*
* Called when the LoadState has changed - whether the refresh, prepend, or append is idle, loading,
* or has an error.
@@ -156,10 +160,10 @@
* thread,posting updates to the main thread.
*
* @param pagedSource [PagedSource] providing data to the [PagedList]
- * @param notifyExecutor Thread tat will use and consume data from the [PagedList].
- * Generally, this is the UI/main thread.
- * @param fetchExecutor Data loading will be done via this executor - should be a background
- * thread.
+ * @param notifyDispatcher [CoroutineDispatcher] that will use and consume data from the
+ * [PagedList]. Generally, this is the UI/main thread.
+ * @param fetchDispatcher Data loading jobs will be dispatched to this
+ * [CoroutineDispatcher] - should be a background thread.
* @param boundaryCallback Optional boundary callback to attach to the list.
* @param config [PagedList.Config], which defines how the [PagedList] will load data.
* @param K Key type that indicates to the [PagedSource] what data to load.
@@ -175,9 +179,9 @@
suspend fun <K : Any, T : Any> create(
pagedSource: PagedSource<K, T>,
coroutineScope: CoroutineScope,
- notifyExecutor: Executor,
- fetchExecutor: Executor,
- initialLoadExecutor: Executor,
+ notifyDispatcher: CoroutineDispatcher,
+ fetchDispatcher: CoroutineDispatcher,
+ initialFetchDispatcher: CoroutineDispatcher,
boundaryCallback: BoundaryCallback<T>?,
config: Config,
key: K?
@@ -195,15 +199,15 @@
config.pageSize
)
- val initialResult = withContext(initialLoadExecutor.asCoroutineDispatcher()) {
+ val initialResult = withContext(initialFetchDispatcher) {
pagedSource.load(params)
}
return ContiguousPagedList(
pagedSource,
coroutineScope,
- notifyExecutor,
- fetchExecutor,
+ notifyDispatcher,
+ fetchDispatcher,
boundaryCallback,
config,
initialResult,
@@ -270,7 +274,7 @@
/**
* Loading hit a retryable error.
*
- * @see .retry
+ * @see retry
*/
RETRYABLE_ERROR
}
@@ -278,7 +282,7 @@
/**
* Builder class for [PagedList].
*
- * [PagedSource], [Config], main thread and background executor must all be provided.
+ * [pagedSource], [config], [notifyDispatcher] and [fetchDispatcher] must all be provided.
*
* A [PagedList] queries initial data from its [PagedSource] during construction, to avoid empty
* PagedLists being presented to the UI when possible. It's preferred to present initial data,
@@ -295,8 +299,8 @@
private val pagedSource: PagedSource<Key, Value>
private val config: Config
private var coroutineScope: CoroutineScope = GlobalScope
- private var notifyExecutor: Executor? = null
- private var fetchExecutor: Executor? = null
+ private var notifyDispatcher: CoroutineDispatcher? = null
+ private var fetchDispatcher: CoroutineDispatcher? = null
private var boundaryCallback: BoundaryCallback<Value>? = null
private var initialKey: Key? = null
@@ -378,18 +382,37 @@
}
/**
- * The executor defining where page loading updates are dispatched.
+ * The [Executor] defining where page loading updates are dispatched.
*
- * @param notifyExecutor Executor that receives [PagedList] updates, and where [Callback]
+ * @param notifyExecutor [Executor] that receives [PagedList] updates, and where [Callback]
* calls are dispatched. Generally, this is the ui/main thread.
* @return this
*/
+ @Deprecated(
+ message = "Passing an executor will cause it get wrapped as a CoroutineDispatcher, " +
+ "consider passing a CoroutineDispatcher directly",
+ replaceWith = ReplaceWith(
+ "setNotifyDispatcher(fetchExecutor.asCoroutineDispatcher())",
+ "kotlinx.coroutines.asCoroutineDispatcher"
+ )
+ )
fun setNotifyExecutor(notifyExecutor: Executor) = apply {
- this.notifyExecutor = notifyExecutor
+ this.notifyDispatcher = notifyExecutor.asCoroutineDispatcher()
}
/**
- * The executor used to fetch additional pages from the [PagedSource].
+ * The [CoroutineDispatcher] defining where page loading updates are dispatched.
+ *
+ * @param notifyDispatcher [CoroutineDispatcher] that receives [PagedList] updates, and where
+ * [Callback] calls are dispatched. Generally, this is the ui/main thread.
+ * @return this
+ */
+ fun setNotifyDispatcher(notifyDispatcher: CoroutineDispatcher) = apply {
+ this.notifyDispatcher = notifyDispatcher
+ }
+
+ /**
+ * The [Executor] used to fetch additional pages from the [PagedSource].
*
* Does not affect initial load, which will be done immediately on whichever thread the
* [PagedList] is created on.
@@ -398,8 +421,30 @@
* thread pool for e.g. I/O or network loading.
* @return this
*/
+ @Deprecated(
+ message = "Passing an executor will cause it get wrapped as a CoroutineDispatcher, " +
+ "consider passing a CoroutineDispatcher directly",
+ replaceWith = ReplaceWith(
+ "setFetchDispatcher(fetchExecutor.asCoroutineDispatcher())",
+ "kotlinx.coroutines.asCoroutineDispatcher"
+ )
+ )
fun setFetchExecutor(fetchExecutor: Executor) = apply {
- this.fetchExecutor = fetchExecutor
+ this.fetchDispatcher = fetchExecutor.asCoroutineDispatcher()
+ }
+
+ /**
+ * The [CoroutineDispatcher] used to fetch additional pages from the [PagedSource].
+ *
+ * Does not affect initial load, which will be done immediately on whichever thread the
+ * [PagedList] is created on.
+ *
+ * @param fetchDispatcher [CoroutineDispatcher] used to fetch from [PagedSource]s,
+ * generally a background thread pool for e.g. I/O or network loading.
+ * @return this
+ */
+ fun setFetchDispatcher(fetchDispatcher: CoroutineDispatcher) = apply {
+ this.fetchDispatcher = fetchDispatcher
}
/**
@@ -444,25 +489,18 @@
* the [PagedList] will be immediately [detached][PagedList.isDetached], and you can retry
* construction (including setting a new [PagedSource]).
*
- * @throws IllegalArgumentException if [notifyExecutor] or [fetchExecutor] are not set.
+ * @throws IllegalArgumentException if [notifyDispatcher] or [fetchDispatcher] are not set.
*
* @return The newly constructed [PagedList]
*/
@WorkerThread
@Deprecated(
- "This method has no means of handling errors encountered during initial load, and" +
- " blocks on the initial load result. Use {@link #buildAsync()} instead."
+ message = "This method has no means of handling errors encountered during initial " +
+ "load, and blocks on the initial load result.",
+ replaceWith = ReplaceWith("buildAsync()")
)
- fun build(): PagedList<Value> {
- // TODO: define defaults, once they can be used in module without android dependency
- if (notifyExecutor == null) {
- throw IllegalArgumentException("MainThreadExecutor required")
- }
- if (fetchExecutor == null) {
- throw IllegalArgumentException("BackgroundThreadExecutor required")
- }
-
- return runBlocking { create(DirectExecutor) }
+ fun build(): PagedList<Value> = runBlocking {
+ create(DirectDispatcher)
}
/**
@@ -472,41 +510,35 @@
* [PagedSource.LoadType.INITIAL], and return a [PagedList] once it completes, triggering
* [loadStateListeners].
*
- * @throws IllegalArgumentException if [notifyExecutor] or [fetchExecutor] are not set.
+ * @throws IllegalArgumentException if [notifyDispatcher] or [fetchDispatcher] are not set.
*
* @return The newly constructed [PagedList]
*/
- @Suppress("unused")
+ @Suppress("unused") // Public API
suspend fun buildAsync(): PagedList<Value> {
- // TODO: define defaults, once they can be used in module without android dependency
- if (notifyExecutor == null) {
- throw IllegalArgumentException("MainThreadExecutor required")
- }
- if (fetchExecutor == null) {
- throw IllegalArgumentException("BackgroundThreadExecutor required")
- }
-
- return create(fetchExecutor!!)
+ return create(fetchDispatcher ?: Dispatchers.IO)
}
- private suspend fun create(initialFetchExecutor: Executor): PagedList<Value> =
- create(
+ private suspend fun create(initialFetchDispatcher: CoroutineDispatcher): PagedList<Value> {
+ return create(
pagedSource,
coroutineScope,
- notifyExecutor!!,
- fetchExecutor!!,
- initialFetchExecutor,
+ notifyDispatcher ?: Dispatchers.Main,
+ fetchDispatcher ?: Dispatchers.IO,
+ initialFetchDispatcher,
boundaryCallback,
config,
initialKey
)
+ }
}
/**
* Callback signaling when content is loaded into the list.
*
* Can be used to listen to items being paged in and out. These calls will be dispatched on
- * the executor defined by [Builder.setNotifyExecutor], which is generally the main/UI thread.
+ * the dispatcher defined by [Builder.setNotifyDispatcher], which is generally the main/UI
+ * thread.
*/
abstract class Callback {
/**
@@ -924,19 +956,21 @@
/**
* @hide
*/
- @RestrictTo(RestrictTo.Scope.LIBRARY)
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
constructor(
+ coroutineScope: CoroutineScope,
pagedSource: PagedSource<*, T>,
storage: PagedStorage<T>,
- mainThreadExecutor: Executor,
- backgroundThreadExecutor: Executor,
+ notifyDispatcher: CoroutineDispatcher,
+ backgroundDispatcher: CoroutineDispatcher,
boundaryCallback: BoundaryCallback<T>?,
config: Config
) : super() {
+ this.coroutineScope = coroutineScope
this.pagedSource = pagedSource
this.storage = storage
- this.mainThreadExecutor = mainThreadExecutor
- this.backgroundThreadExecutor = backgroundThreadExecutor
+ this.notifyDispatcher = notifyDispatcher
+ this.backgroundDispatcher = backgroundDispatcher
this.boundaryCallback = boundaryCallback
this.config = config
this.callbacks = ArrayList()
@@ -952,8 +986,9 @@
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) // protected otherwise
fun getStorage() = storage
- internal val mainThreadExecutor: Executor
- internal val backgroundThreadExecutor: Executor
+ internal val notifyDispatcher: CoroutineDispatcher
+ internal val backgroundDispatcher: CoroutineDispatcher
+
internal val boundaryCallback: BoundaryCallback<T>?
internal var refreshRetryCallback: Runnable? = null
@@ -978,6 +1013,8 @@
*/
open val config: Config
+ internal val coroutineScope: CoroutineScope
+
private val callbacks: MutableList<WeakReference<Callback>>
private val loadStateListeners: MutableList<WeakReference<LoadStateListener>>
@@ -1012,7 +1049,10 @@
* @throws IllegalStateException if this [PagedList] was instantiated without a
* [PagedSourceWrapper] wrapping a backing [DataSource]
*/
- @Deprecated("DataSource is deprecated and has been replaced by PagedSource")
+ @Deprecated(
+ message = "DataSource is deprecated and has been replaced by PagedSource",
+ replaceWith = ReplaceWith("pagedSource")
+ )
val dataSource: DataSource<*, T>
get() {
if (pagedSource is PagedSourceWrapper) return pagedSource.dataSource
@@ -1219,7 +1259,7 @@
if (deferEmpty || deferBegin || deferEnd) {
// Post to the main thread, since we may be on creation thread currently
- mainThreadExecutor.execute {
+ coroutineScope.launch(notifyDispatcher) {
// on is dispatched immediately, since items won't be accessed
if (deferEmpty) {
@@ -1258,7 +1298,9 @@
boundaryCallbackEndDeferred = false
}
if (post) {
- mainThreadExecutor.execute { dispatchBoundaryCallbacks(dispatchBegin, dispatchEnd) }
+ coroutineScope.launch(notifyDispatcher) {
+ dispatchBoundaryCallbacks(dispatchBegin, dispatchEnd)
+ }
} else {
dispatchBoundaryCallbacks(dispatchBegin, dispatchEnd)
}
@@ -1409,8 +1451,8 @@
* @param Value Type of items held and loaded by the [PagedList].
* @param dataSource [DataSource] the [PagedList] will load from.
* @param config Config that defines how the [PagedList] loads data from its [DataSource].
- * @param notifyExecutor Executor that receives [PagedList] updates, and where [PagedList.Callback]
- * calls are dispatched. Generally, this is the UI/main thread.
+ * @param notifyExecutor [Executor] that receives [PagedList] updates, and where
+ * [PagedList.Callback] calls are dispatched. Generally, this is the UI/main thread.
* @param fetchExecutor [Executor] used to fetch from [DataSource]s, generally a background thread
* pool for e.g. I/O or network loading.
* @param boundaryCallback [PagedList.BoundaryCallback] for listening to out-of-data events.
diff --git a/paging/common/src/main/kotlin/androidx/paging/SnapshotPagedList.kt b/paging/common/src/main/kotlin/androidx/paging/SnapshotPagedList.kt
index 5688543..a0b556b 100644
--- a/paging/common/src/main/kotlin/androidx/paging/SnapshotPagedList.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/SnapshotPagedList.kt
@@ -17,10 +17,11 @@
package androidx.paging
internal class SnapshotPagedList<T : Any>(private val pagedList: PagedList<T>) : PagedList<T>(
+ pagedList.coroutineScope,
pagedList.pagedSource,
pagedList.storage.snapshot(),
- pagedList.mainThreadExecutor,
- pagedList.backgroundThreadExecutor,
+ pagedList.notifyDispatcher,
+ pagedList.backgroundDispatcher,
null,
pagedList.config
) {
diff --git a/paging/common/src/main/kotlin/androidx/paging/futures/DirectDispatcher.kt b/paging/common/src/main/kotlin/androidx/paging/futures/DirectDispatcher.kt
new file mode 100644
index 0000000..436f49a
--- /dev/null
+++ b/paging/common/src/main/kotlin/androidx/paging/futures/DirectDispatcher.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.paging.futures
+
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * [CoroutineDispatcher] which immediately runs new jobs on the current thread.
+ */
+internal object DirectDispatcher : CoroutineDispatcher() {
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ block.run()
+ }
+}
diff --git a/paging/common/src/test/kotlin/androidx/paging/ContiguousPagedListTest.kt b/paging/common/src/test/kotlin/androidx/paging/ContiguousPagedListTest.kt
index a36c36f..292a305 100644
--- a/paging/common/src/test/kotlin/androidx/paging/ContiguousPagedListTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/ContiguousPagedListTest.kt
@@ -20,8 +20,8 @@
import androidx.paging.PagedList.LoadState.IDLE
import androidx.paging.PagedList.LoadState.LOADING
import androidx.paging.PagedList.LoadState.RETRYABLE_ERROR
-import androidx.paging.futures.DirectExecutor
-import androidx.testutils.TestExecutor
+import androidx.paging.futures.DirectDispatcher
+import androidx.testutils.TestDispatcher
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.reset
import com.nhaarman.mockitokotlin2.verify
@@ -39,8 +39,8 @@
@RunWith(Parameterized::class)
class ContiguousPagedListTest(private val placeholdersEnabled: Boolean) {
- private val mainThread = TestExecutor()
- private val backgroundThread = TestExecutor()
+ private val mainThread = TestDispatcher()
+ private val backgroundThread = TestDispatcher()
private class Item(position: Int) {
val pos: Int = position
@@ -179,7 +179,7 @@
GlobalScope,
mainThread,
backgroundThread,
- DirectExecutor,
+ DirectDispatcher,
boundaryCallback,
PagedList.Config.Builder()
.setPageSize(pageSize)
@@ -212,9 +212,9 @@
PagedList.create(
PagedSourceWrapper(ItemDataSource()),
GlobalScope,
- FailExecutor(),
- DirectExecutor,
- DirectExecutor,
+ FailDispatcher(),
+ DirectDispatcher,
+ DirectDispatcher,
null,
PagedList.Config.Builder().setPageSize(10).build(),
null
@@ -902,11 +902,10 @@
}
private fun drain() {
- var executed: Boolean
- do {
- executed = backgroundThread.executeAll()
- executed = mainThread.executeAll() || executed
- } while (executed)
+ while (backgroundThread.queue.isNotEmpty() || mainThread.queue.isNotEmpty()) {
+ backgroundThread.executeAll()
+ mainThread.executeAll()
+ }
}
companion object {
diff --git a/paging/common/src/test/kotlin/androidx/paging/FailExecutor.kt b/paging/common/src/test/kotlin/androidx/paging/FailDispatcher.kt
similarity index 69%
rename from paging/common/src/test/kotlin/androidx/paging/FailExecutor.kt
rename to paging/common/src/test/kotlin/androidx/paging/FailDispatcher.kt
index 1c2b0d5..9e41203 100644
--- a/paging/common/src/test/kotlin/androidx/paging/FailExecutor.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/FailDispatcher.kt
@@ -16,11 +16,15 @@
package androidx.paging
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Runnable
import org.junit.Assert.fail
-import java.util.concurrent.Executor
+import kotlin.coroutines.CoroutineContext
-class FailExecutor(val string: String = "Executor expected to be unused") : Executor {
- override fun execute(runnable: Runnable?) {
+class FailDispatcher(
+ val string: String = "Executor expected to be unused"
+) : CoroutineDispatcher() {
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
fail(string)
}
}
diff --git a/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt b/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt
index 4068366..36a6381 100644
--- a/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt
@@ -17,6 +17,7 @@
package androidx.paging
import androidx.paging.futures.DirectExecutor
+import androidx.paging.futures.DirectDispatcher
import com.nhaarman.mockitokotlin2.capture
import com.nhaarman.mockitokotlin2.mock
import kotlinx.coroutines.GlobalScope
@@ -291,9 +292,9 @@
PagedList.create(
PagedSourceWrapper(dataSource),
GlobalScope,
- FailExecutor(),
- DirectExecutor,
- DirectExecutor,
+ FailDispatcher(),
+ DirectDispatcher,
+ DirectDispatcher,
null,
PagedList.Config.Builder()
.setPageSize(10)
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt
index af58970..11b7cda 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt
@@ -16,11 +16,10 @@
package androidx.paging
-import androidx.paging.futures.DirectExecutor
-import androidx.testutils.TestExecutor
+import androidx.paging.futures.DirectDispatcher
+import androidx.testutils.TestDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
@@ -39,8 +38,8 @@
@RunWith(JUnit4::class)
class PageKeyedDataSourceTest {
- private val mainThread = TestExecutor()
- private val backgroundThread = TestExecutor()
+ private val mainThread = TestDispatcher()
+ private val backgroundThread = TestDispatcher()
internal data class Item(val name: String)
@@ -94,7 +93,7 @@
fun loadFullVerify() {
// validate paging entire ItemDataSource results in full, correctly ordered data
val testCoroutineScope = CoroutineScope(EmptyCoroutineContext)
- val pagedListJob = testCoroutineScope.async(backgroundThread.asCoroutineDispatcher()) {
+ val pagedListJob = testCoroutineScope.async(backgroundThread) {
PagedList.create(
PagedSourceWrapper(ItemDataSource()),
testCoroutineScope,
@@ -160,9 +159,9 @@
PagedList.create(
PagedSourceWrapper(dataSource),
GlobalScope,
- FailExecutor(),
- DirectExecutor,
- DirectExecutor,
+ FailDispatcher(),
+ DirectDispatcher,
+ DirectDispatcher,
null,
PagedList.Config.Builder()
.setPageSize(10)
@@ -260,16 +259,16 @@
@Suppress("UNCHECKED_CAST")
val boundaryCallback =
mock(PagedList.BoundaryCallback::class.java) as PagedList.BoundaryCallback<String>
- val executor = TestExecutor()
+ val dispatcher = TestDispatcher()
val testCoroutineScope = CoroutineScope(EmptyCoroutineContext)
- val pagedListJob = testCoroutineScope.async(executor.asCoroutineDispatcher()) {
+ val pagedListJob = testCoroutineScope.async(dispatcher) {
PagedList.create(
PagedSourceWrapper(dataSource),
testCoroutineScope,
- executor,
- executor,
- executor,
+ dispatcher,
+ dispatcher,
+ dispatcher,
boundaryCallback,
PagedList.Config.Builder()
.setPageSize(10)
@@ -278,14 +277,14 @@
)
}
- executor.executeAll()
+ dispatcher.executeAll()
val pagedList = runBlocking { pagedListJob.await() }
pagedList.loadAround(0)
verifyZeroInteractions(boundaryCallback)
- executor.executeAll()
+ dispatcher.executeAll()
// verify boundary callbacks are triggered
verify(boundaryCallback).onItemAtFrontLoaded("A")
@@ -322,16 +321,16 @@
@Suppress("UNCHECKED_CAST")
val boundaryCallback =
mock(PagedList.BoundaryCallback::class.java) as PagedList.BoundaryCallback<String>
- val executor = TestExecutor()
+ val dispatcher = TestDispatcher()
val testCoroutineScope = CoroutineScope(EmptyCoroutineContext)
- val pagedListJob = testCoroutineScope.async(executor.asCoroutineDispatcher()) {
+ val pagedListJob = testCoroutineScope.async(dispatcher) {
PagedList.create(
PagedSourceWrapper(dataSource),
testCoroutineScope,
- executor,
- executor,
- executor,
+ dispatcher,
+ dispatcher,
+ dispatcher,
boundaryCallback,
PagedList.Config.Builder()
.setPageSize(10)
@@ -339,14 +338,14 @@
""
)
}
- executor.executeAll()
+ dispatcher.executeAll()
val pagedList = runBlocking { pagedListJob.await() }
pagedList.loadAround(0)
verifyZeroInteractions(boundaryCallback)
- executor.executeAll()
+ dispatcher.executeAll()
// verify boundary callbacks are triggered
verify(boundaryCallback).onItemAtFrontLoaded("B")
@@ -516,7 +515,6 @@
private const val INIT_KEY: String = "key 2"
private val PAGE_MAP: Map<String, Page>
private val ITEM_LIST: List<Item>
- private val EXCEPTION = Exception()
init {
val map = HashMap<String, Page>()
@@ -537,10 +535,9 @@
}
private fun drain() {
- var executed: Boolean
- do {
- executed = backgroundThread.executeAll()
- executed = mainThread.executeAll() || executed
- } while (executed)
+ while (backgroundThread.queue.isNotEmpty() || mainThread.queue.isNotEmpty()) {
+ backgroundThread.executeAll()
+ mainThread.executeAll()
+ }
}
}
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagedListConfigBuilderTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagedListConfigBuilderTest.kt
index f162572..05faea4 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagedListConfigBuilderTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagedListConfigBuilderTest.kt
@@ -26,8 +26,8 @@
@Test
fun defaults() {
val config = PagedList.Config.Builder()
- .setPageSize(10)
- .build()
+ .setPageSize(10)
+ .build()
Assert.assertEquals(10, config.pageSize)
Assert.assertEquals(30, config.initialLoadSizeHint)
Assert.assertEquals(true, config.enablePlaceholders)
@@ -38,18 +38,18 @@
@Test(expected = IllegalArgumentException::class)
fun maxSizeTooSmall() {
PagedList.Config.Builder()
- .setPageSize(20)
- .setPrefetchDistance(15)
- .setMaxSize(49)
- .build()
+ .setPageSize(20)
+ .setPrefetchDistance(15)
+ .setMaxSize(49)
+ .build()
}
@Test
fun maxSizeAccepted() {
PagedList.Config.Builder()
- .setPageSize(20)
- .setPrefetchDistance(15)
- .setMaxSize(50)
- .build()
+ .setPageSize(20)
+ .setPrefetchDistance(15)
+ .setMaxSize(50)
+ .build()
}
}
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt
index e79ef38..3f4c9b9 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt
@@ -16,10 +16,10 @@
package androidx.paging
-import androidx.paging.futures.DirectExecutor
+import androidx.paging.futures.DirectDispatcher
+import androidx.testutils.TestDispatcher
import androidx.testutils.TestExecutor
import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
@@ -54,15 +54,15 @@
}
private val testCoroutineScope = CoroutineScope(EmptyCoroutineContext)
- private val mainThread = TestExecutor()
- private val backgroundThread = TestExecutor()
+ private val mainThread = TestDispatcher()
+ private val backgroundThread = TestDispatcher()
@Test
- fun createLegacy() = runBlocking {
+ fun createLegacy() {
@Suppress("DEPRECATION")
val pagedList = PagedList.Builder(ListDataSource(ITEMS), 100)
- .setNotifyExecutor(mainThread)
- .setFetchExecutor(backgroundThread)
+ .setNotifyExecutor(TestExecutor())
+ .setFetchExecutor(TestExecutor())
.build()
// if build succeeds without flushing an executor, success!
assertEquals(ITEMS, pagedList)
@@ -76,7 +76,7 @@
.build()
var success = false
- val job = testCoroutineScope.async(backgroundThread.asCoroutineDispatcher()) {
+ val job = testCoroutineScope.async(backgroundThread) {
val pagedList = PagedList.create(
PagedSourceWrapper(ListDataSource(ITEMS)),
testCoroutineScope,
@@ -116,7 +116,7 @@
.build()
var success = false
assertFails {
- val job = testCoroutineScope.async(backgroundThread.asCoroutineDispatcher()) {
+ val job = testCoroutineScope.async(backgroundThread) {
PagedList.create(
pagedSource,
testCoroutineScope,
@@ -140,8 +140,8 @@
@Test
fun defaults() = runBlocking {
val pagedList = PagedList.Builder(pagedSource, config)
- .setNotifyExecutor(DirectExecutor)
- .setFetchExecutor(DirectExecutor)
+ .setNotifyDispatcher(DirectDispatcher)
+ .setFetchDispatcher(DirectDispatcher)
.buildAsync()
assertEquals(pagedSource, pagedList.pagedSource)
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt
index d175169..fce6cbd 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagerTest.kt
@@ -22,10 +22,9 @@
import androidx.paging.PagedList.LoadType.END
import androidx.paging.PagedList.LoadType.START
import androidx.paging.PagedSource.LoadResult
-import androidx.paging.futures.DirectExecutor
+import androidx.paging.futures.DirectDispatcher
import androidx.testutils.TestExecutor
import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.asCoroutineDispatcher
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
@@ -131,8 +130,8 @@
GlobalScope,
PagedList.Config(2, 2, true, 10, PagedList.Config.MAX_SIZE_UNBOUNDED),
PagedSourceWrapper(ImmediateListDataSource(data)),
- DirectExecutor.asCoroutineDispatcher(),
- DirectExecutor.asCoroutineDispatcher(),
+ DirectDispatcher,
+ DirectDispatcher,
consumer,
initialResult
)
@@ -254,7 +253,7 @@
// Pager triggers an immediate empty response here, so we don't need to flush the executor
assertEquals(
listOf(
- Result(END, PagedSource.LoadResult.empty<Int, String>())
+ Result(END, LoadResult.empty<Int, String>())
), consumer.takeResults()
)
assertEquals(
@@ -274,7 +273,7 @@
// Pager triggers an immediate empty response here, so we don't need to flush the executor
assertEquals(
listOf(
- Result(START, PagedSource.LoadResult.empty<Int, String>())
+ Result(START, LoadResult.empty<Int, String>())
), consumer.takeResults()
)
assertEquals(
diff --git a/paging/runtime/api/3.0.0-alpha01.txt b/paging/runtime/api/3.0.0-alpha01.txt
index f035ad8..6822061 100644
--- a/paging/runtime/api/3.0.0-alpha01.txt
+++ b/paging/runtime/api/3.0.0-alpha01.txt
@@ -43,8 +43,8 @@
ctor public LivePagedListKt();
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
diff --git a/paging/runtime/api/current.txt b/paging/runtime/api/current.txt
index f035ad8..6822061 100644
--- a/paging/runtime/api/current.txt
+++ b/paging/runtime/api/current.txt
@@ -43,8 +43,8 @@
ctor public LivePagedListKt();
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
diff --git a/paging/runtime/api/restricted_3.0.0-alpha01.txt b/paging/runtime/api/restricted_3.0.0-alpha01.txt
index f035ad8..6822061 100644
--- a/paging/runtime/api/restricted_3.0.0-alpha01.txt
+++ b/paging/runtime/api/restricted_3.0.0-alpha01.txt
@@ -43,8 +43,8 @@
ctor public LivePagedListKt();
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
diff --git a/paging/runtime/api/restricted_current.txt b/paging/runtime/api/restricted_current.txt
index f035ad8..6822061 100644
--- a/paging/runtime/api/restricted_current.txt
+++ b/paging/runtime/api/restricted_current.txt
@@ -43,8 +43,8 @@
ctor public LivePagedListKt();
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
method @Deprecated public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(androidx.paging.DataSource.Factory<Key,Value>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
- method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, java.util.concurrent.Executor fetchExecutor = ArchTaskExecutor.getIOThreadExecutor());
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, androidx.paging.PagedList.Config config, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
+ method public static <Key, Value> androidx.lifecycle.LiveData<androidx.paging.PagedList<Value>> toLiveData(kotlin.jvm.functions.Function0<? extends androidx.paging.PagedSource<Key,Value>>, int pageSize, Key? initialLoadKey = null, androidx.paging.PagedList.BoundaryCallback<Value>? boundaryCallback = null, kotlinx.coroutines.CoroutineScope coroutineScope = GlobalScope, kotlinx.coroutines.CoroutineDispatcher fetchDispatcher = Dispatchers.IO);
}
public abstract class PagedListAdapter<T, VH extends androidx.recyclerview.widget.RecyclerView.ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 71033f7..e3719d7 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -18,7 +18,6 @@
import androidx.build.AndroidXExtension
import androidx.build.LibraryGroups
import androidx.build.LibraryVersions
-import androidx.build.AndroidXExtension
import androidx.build.Publish
import static androidx.build.dependencies.DependenciesKt.*
@@ -42,16 +41,20 @@
api(KOTLIN_COROUTINES)
androidTestImplementation project(':internal-testutils-common')
- androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+ androidTestImplementation project(':internal-testutils-ktx'), {
+ exclude group: 'com.google.truth'
+ }
androidTestImplementation(ANDROIDX_TEST_CORE)
+ androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
androidTestImplementation(ANDROIDX_TEST_RUNNER)
androidTestImplementation(ARCH_CORE_TESTING)
- androidTestImplementation(ESPRESSO_CORE)
+ androidTestImplementation(KOTLIN_COROUTINES_TEST)
androidTestImplementation(JUNIT)
androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
androidTestImplementation MOCKITO_KOTLIN, {
exclude group: 'org.mockito' // to keep control on the mockito version
+ exclude group: 'net.bytebuddy'
}
}
diff --git a/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt b/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
index 67ada15..2b4de35b 100644
--- a/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
+++ b/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
@@ -27,7 +27,13 @@
import androidx.paging.PagedList.LoadState.RETRYABLE_ERROR
import androidx.paging.PagedList.LoadType.REFRESH
import androidx.test.filters.SmallTest
+import androidx.testutils.TestDispatcher
import androidx.testutils.TestExecutor
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.setMain
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
@@ -43,6 +49,7 @@
@SmallTest
@RunWith(JUnit4::class)
class LivePagedListBuilderTest {
+ private val mainDispatcher = TestDispatcher()
private val backgroundExecutor = TestExecutor()
private val lifecycleOwner = object : LifecycleOwner {
private val lifecycle = LifecycleRegistry(this)
@@ -56,8 +63,10 @@
}
}
+ @ExperimentalCoroutinesApi
@Before
fun setup() {
+ Dispatchers.setMain(mainDispatcher)
ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) {
fail("IO executor should be overwritten")
@@ -74,10 +83,12 @@
lifecycleOwner.handleEvent(Lifecycle.Event.ON_START)
}
+ @ExperimentalCoroutinesApi
@After
fun teardown() {
lifecycleOwner.handleEvent(Lifecycle.Event.ON_STOP)
ArchTaskExecutor.getInstance().setDelegate(null)
+ Dispatchers.resetMain()
}
class MockDataSourceFactory {
@@ -126,8 +137,8 @@
@Test
fun executorBehavior() {
- // specify a background executor via builder, and verify it gets used for all loads,
- // overriding default arch IO executor
+ // specify a background dispatcher via builder, and verify it gets used for all loads,
+ // overriding default IO dispatcher
val livePagedList = LivePagedListBuilder(MockDataSourceFactory()::create, 2)
.setFetchExecutor(backgroundExecutor)
.build()
@@ -143,7 +154,7 @@
assertTrue(pagedListHolder[0] is InitialPagedList<*, *>)
// flush loadInitial, done with passed executor
- backgroundExecutor.executeAll()
+ drain()
val pagedList = pagedListHolder[0]
assertNotNull(pagedList)
@@ -151,7 +162,7 @@
// flush loadRange
pagedList!!.loadAround(2)
- backgroundExecutor.executeAll()
+ drain()
assertEquals(listOf("a", "b", "c", "d"), pagedList)
}
@@ -191,8 +202,8 @@
}
initPagedList.addWeakLoadStateListener(loadStateChangedCallback)
- // flush loadInitial, done with passed executor
- backgroundExecutor.executeAll()
+ // flush loadInitial, done with passed dispatcher
+ drain()
assertSame(initPagedList, pagedListHolder[0])
// TODO: Investigate removing initial IDLE state from callback updates.
@@ -208,7 +219,8 @@
assertSame(initPagedList, pagedListHolder[0])
// flush loadInitial, should succeed now
- backgroundExecutor.executeAll()
+ drain()
+
assertNotSame(initPagedList, pagedListHolder[0])
assertEquals(listOf("a", "b", null, null), pagedListHolder[0])
@@ -235,6 +247,14 @@
)
}
+ private fun drain() {
+ var executed: Boolean
+ do {
+ executed = backgroundExecutor.executeAll()
+ mainDispatcher.executeAll()
+ } while (executed || mainDispatcher.queue.isNotEmpty())
+ }
+
companion object {
val RETRYABLE_EXCEPTION = Exception("retryable")
}
diff --git a/paging/runtime/src/androidTest/java/androidx/paging/StringPagedList.kt b/paging/runtime/src/androidTest/java/androidx/paging/StringPagedList.kt
index 20c42d4..e9cdf9b 100644
--- a/paging/runtime/src/androidTest/java/androidx/paging/StringPagedList.kt
+++ b/paging/runtime/src/androidTest/java/androidx/paging/StringPagedList.kt
@@ -16,7 +16,8 @@
package androidx.paging
-import androidx.testutils.TestExecutor
+import androidx.testutils.TestDispatcher
+import kotlinx.coroutines.GlobalScope
class StringPagedList constructor(
leadingNulls: Int,
@@ -24,10 +25,11 @@
vararg items: String,
list: List<String> = items.toList()
) : PagedList<String>(
+ GlobalScope,
PagedSourceWrapper(ListDataSource(list)),
PagedStorage(),
- TestExecutor(),
- TestExecutor(),
+ TestDispatcher(),
+ TestDispatcher(),
null,
Config.Builder().setPageSize(1).build()
), PagedStorage.Callback {
diff --git a/paging/runtime/src/main/java/androidx/paging/LivePagedList.kt b/paging/runtime/src/main/java/androidx/paging/LivePagedList.kt
index ce6fcde6d..2a0a7e4 100644
--- a/paging/runtime/src/main/java/androidx/paging/LivePagedList.kt
+++ b/paging/runtime/src/main/java/androidx/paging/LivePagedList.kt
@@ -18,9 +18,11 @@
import androidx.arch.core.executor.ArchTaskExecutor
import androidx.lifecycle.LiveData
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
-import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.Executor
@@ -31,8 +33,8 @@
private val config: PagedList.Config,
private val boundaryCallback: PagedList.BoundaryCallback<Value>?,
private val pagedSourceFactory: PagedSourceFactory<Key, Value>,
- private val notifyExecutor: Executor,
- private val fetchExecutor: Executor
+ private val notifyDispatcher: CoroutineDispatcher,
+ private val fetchDispatcher: CoroutineDispatcher
) : LiveData<PagedList<Value>>() {
private var currentData: PagedList<Value>
private var currentJob: Job? = null
@@ -77,14 +79,14 @@
if (currentJob != null && !force) return
currentJob?.cancel()
- currentJob = coroutineScope.launch(fetchExecutor.asCoroutineDispatcher()) {
+ currentJob = coroutineScope.launch(fetchDispatcher) {
try {
val pagedList = createPagedList()
- withContext(notifyExecutor.asCoroutineDispatcher()) {
+ withContext(notifyDispatcher) {
onSuccess(pagedList)
}
} catch (throwable: Throwable) {
- withContext(notifyExecutor.asCoroutineDispatcher()) {
+ withContext(notifyDispatcher) {
onError(throwable)
}
}
@@ -100,16 +102,19 @@
val pagedSource = pagedSourceFactory()
currentData.pagedSource.unregisterInvalidatedCallback(callback)
pagedSource.registerInvalidatedCallback(callback)
- currentData.setInitialLoadState(PagedList.LoadState.LOADING, null)
+
+ withContext(notifyDispatcher) {
+ currentData.setInitialLoadState(PagedList.LoadState.LOADING, null)
+ }
@Suppress("UNCHECKED_CAST") // getLastKey guaranteed to be of 'Key' type
val lastKey = currentData.lastKey as Key?
return PagedList.create(
pagedSource,
coroutineScope,
- notifyExecutor,
- fetchExecutor,
- fetchExecutor,
+ notifyDispatcher,
+ fetchDispatcher,
+ fetchDispatcher,
boundaryCallback,
config,
lastKey
@@ -121,13 +126,13 @@
* Constructs a `LiveData<PagedList>`, from this `DataSource.Factory`, convenience for
* [LivePagedListBuilder].
*
- * No work (such as loading) is done immediately, the creation of the first PagedList is is
- * deferred until the LiveData is observed.
+ * No work (such as loading) is done immediately, the creation of the first [PagedList] is deferred
+ * until the [LiveData] is observed.
*
* @param config Paging configuration.
- * @param initialLoadKey Initial load key passed to the first PagedList/DataSource.
- * @param boundaryCallback The boundary callback for listening to PagedList load state.
- * @param fetchExecutor Executor for fetching data from DataSources.
+ * @param initialLoadKey Initial load key passed to the first [PagedList] / [PagedSource].
+ * @param boundaryCallback The boundary callback for listening to [PagedList] load state.
+ * @param fetchExecutor [Executor] for fetching data from [PagedSource]s.
*
* @see LivePagedListBuilder
*/
@@ -150,12 +155,12 @@
* Constructs a `LiveData<PagedList>`, from this `DataSource.Factory`, convenience for
* [LivePagedListBuilder].
*
- * No work (such as loading) is done immediately, the creation of the first PagedList is is
- * deferred until the LiveData is observed.
+ * No work (such as loading) is done immediately, the creation of the first [PagedList] is deferred
+ * until the [LiveData] is observed.
*
* @param pageSize Page size.
- * @param initialLoadKey Initial load key passed to the first PagedList/DataSource.
- * @param boundaryCallback The boundary callback for listening to PagedList load state.
+ * @param initialLoadKey Initial load key passed to the first [PagedList] / [PagedSource].
+ * @param boundaryCallback The boundary callback for listening to [PagedList] load state.
* @param fetchExecutor Executor for fetching data from DataSources.
*
* @see LivePagedListBuilder
@@ -179,13 +184,18 @@
* Constructs a `LiveData<PagedList>`, from this [PagedSourceFactory], convenience for
* [LivePagedListBuilder].
*
- * No work (such as loading) is done immediately, the creation of the first PagedList is is
- * deferred until the LiveData is observed.
+ * No work (such as loading) is done immediately, the creation of the first [PagedList] is deferred
+ * until the [LiveData] is observed.
*
* @param config Paging configuration.
- * @param initialLoadKey Initial load key passed to the first PagedList/PagedSource.
- * @param boundaryCallback The boundary callback for listening to PagedList load state.
- * @param fetchExecutor Executor for fetching data from PagedSources.
+ * @param initialLoadKey Initial load key passed to the first [PagedList] / [PagedSource].
+ * @param boundaryCallback The boundary callback for listening to [PagedList] load state.
+ * @param coroutineScope Set the [CoroutineScope] that page loads should be launched within. The
+ * set [coroutineScope] allows a [PagedSource] to cancel running load operations when the results
+ * are no longer needed - for example, when the containing activity is destroyed.
+ *
+ * Defaults to [GlobalScope].
+ * @param fetchDispatcher [CoroutineDispatcher] for fetching data from [PagedSource]s.
*
* @see LivePagedListBuilder
*/
@@ -193,26 +203,36 @@
config: PagedList.Config,
initialLoadKey: Key? = null,
boundaryCallback: PagedList.BoundaryCallback<Value>? = null,
- fetchExecutor: Executor = ArchTaskExecutor.getIOThreadExecutor()
+ coroutineScope: CoroutineScope = GlobalScope,
+ fetchDispatcher: CoroutineDispatcher = Dispatchers.IO
): LiveData<PagedList<Value>> {
- return LivePagedListBuilder(this, config)
- .setInitialLoadKey(initialLoadKey)
- .setBoundaryCallback(boundaryCallback)
- .setFetchExecutor(fetchExecutor)
- .build()
+ return LivePagedList(
+ coroutineScope,
+ initialLoadKey,
+ config,
+ boundaryCallback,
+ this,
+ Dispatchers.Main,
+ fetchDispatcher
+ )
}
/**
* Constructs a `LiveData<PagedList>`, from this [PagedSourceFactory], convenience for
* [LivePagedListBuilder].
*
- * No work (such as loading) is done immediately, the creation of the first PagedList is is
- * deferred until the LiveData is observed.
+ * No work (such as loading) is done immediately, the creation of the first [PagedList] is deferred
+ * until the [LiveData] is observed.
*
* @param pageSize Page size.
- * @param initialLoadKey Initial load key passed to the first PagedList/PagedSource.
- * @param boundaryCallback The boundary callback for listening to PagedList load state.
- * @param fetchExecutor Executor for fetching data from PagedSources.
+ * @param initialLoadKey Initial load key passed to the first [PagedList] / [PagedSource].
+ * @param boundaryCallback The boundary callback for listening to [PagedList] load state.
+ * @param coroutineScope Set the [CoroutineScope] that page loads should be launched within. The
+ * set [coroutineScope] allows a [PagedSource] to cancel running load operations when the results
+ * are no longer needed - for example, when the containing activity is destroyed.
+ *
+ * Defaults to [GlobalScope].
+ * @param fetchDispatcher [CoroutineDispatcher] for fetching data from [PagedSource]s.
*
* @see LivePagedListBuilder
*/
@@ -220,11 +240,16 @@
pageSize: Int,
initialLoadKey: Key? = null,
boundaryCallback: PagedList.BoundaryCallback<Value>? = null,
- fetchExecutor: Executor = ArchTaskExecutor.getIOThreadExecutor()
+ coroutineScope: CoroutineScope = GlobalScope,
+ fetchDispatcher: CoroutineDispatcher = Dispatchers.IO
): LiveData<PagedList<Value>> {
- return LivePagedListBuilder(this, Config(pageSize))
- .setInitialLoadKey(initialLoadKey)
- .setBoundaryCallback(boundaryCallback)
- .setFetchExecutor(fetchExecutor)
- .build()
+ return LivePagedList(
+ coroutineScope,
+ initialLoadKey,
+ PagedList.Config.Builder().setPageSize(pageSize).build(),
+ boundaryCallback,
+ this,
+ Dispatchers.Main,
+ fetchDispatcher
+ )
}
diff --git a/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.kt b/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.kt
index ae1c147..a374d4a 100644
--- a/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.kt
+++ b/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.kt
@@ -16,15 +16,16 @@
package androidx.paging
-import androidx.arch.core.executor.ArchTaskExecutor
import androidx.lifecycle.LiveData
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.asCoroutineDispatcher
import java.util.concurrent.Executor
/**
- * Builder for `LiveData<PagedList>`, given a [androidx.paging.DataSource.Factory] and a
- * [androidx.paging.PagedList.Config].
+ * Builder for `LiveData<PagedList>` for Java users, given a [androidx.paging.DataSource.Factory]
+ * and a [androidx.paging.PagedList.Config].
*
* The required parameters are in the constructor, so you can simply construct and build, or
* optionally enable extra features (such as initial load key, or BoundaryCallback).
@@ -32,6 +33,8 @@
* @param Key Type of input valued used to load data from the [DataSource]. Must be integer if
* you're using [PositionalDataSource].
* @param Value Item type being presented.
+ *
+ * @see toLiveData
*/
class LivePagedListBuilder<Key : Any, Value : Any> {
private val pagedSourceFactory: PagedSourceFactory<Key, Value>
@@ -39,7 +42,7 @@
private var coroutineScope: CoroutineScope = GlobalScope
private var initialLoadKey: Key? = null
private var boundaryCallback: PagedList.BoundaryCallback<Value>? = null
- private var fetchExecutor = ArchTaskExecutor.getIOThreadExecutor()
+ private var fetchDispatcher = Dispatchers.IO
/**
* Creates a [LivePagedListBuilder] with required parameters.
@@ -148,9 +151,9 @@
* Sets a [androidx.paging.PagedList.BoundaryCallback] on each PagedList created,
* typically used to load additional data from network when paging from local storage.
*
- * Pass a BoundaryCallback to listen to when the PagedList runs out of data to load. If this
- * method is not called, or `null` is passed, you will not be notified when each
- * DataSource runs out of data to provide to its PagedList.
+ * Pass a [PagedList.BoundaryCallback] to listen to when the PagedList runs out of data to load.
+ * If this method is not called, or `null` is passed, you will not be notified when each
+ * [PagedSource] runs out of data to provide to its [PagedList].
*
* If you are paging from a DataSource.Factory backed by local storage, you can set a
* BoundaryCallback to know when there is no more information to page from local storage.
@@ -169,15 +172,17 @@
}
/**
- * Sets executor used for background fetching of PagedLists, and the pages within.
+ * Sets [Executor] used for background fetching of [PagedList]s, and the pages within.
*
- * If not set, defaults to the Arch components I/O thread pool.
+ * The library will wrap this as a [kotlinx.coroutines.CoroutineDispatcher].
*
- * @param fetchExecutor Executor for fetching data from DataSources.
+ * If not set, defaults to [Dispatchers.IO].
+ *
+ * @param fetchExecutor [Executor] for fetching data from [PagedSource]s.
* @return this
*/
fun setFetchExecutor(fetchExecutor: Executor) = this.apply {
- this.fetchExecutor = fetchExecutor
+ this.fetchDispatcher = fetchExecutor.asCoroutineDispatcher()
}
/**
@@ -186,7 +191,7 @@
* No work (such as loading) is done immediately, the creation of the first PagedList is is
* deferred until the LiveData is observed.
*
- * @return The LiveData of PagedLists
+ * @return The [LiveData] of [PagedList]s
*/
fun build(): LiveData<PagedList<Value>> {
return LivePagedList(
@@ -195,8 +200,8 @@
config,
boundaryCallback,
pagedSourceFactory,
- ArchTaskExecutor.getMainThreadExecutor(),
- fetchExecutor
+ Dispatchers.Main,
+ fetchDispatcher
)
}
}
diff --git a/testutils-ktx/build.gradle b/testutils-ktx/build.gradle
index 357afcf..54e885b1 100644
--- a/testutils-ktx/build.gradle
+++ b/testutils-ktx/build.gradle
@@ -22,8 +22,9 @@
}
dependencies {
- compile(KOTLIN_STDLIB)
- compile(TRUTH)
+ api(TRUTH)
+ api(KOTLIN_STDLIB)
+ api(KOTLIN_COROUTINES)
}
androidx {
diff --git a/testutils-ktx/src/main/java/androidx/testutils/TestDispatcher.kt b/testutils-ktx/src/main/java/androidx/testutils/TestDispatcher.kt
new file mode 100644
index 0000000..127eaef
--- /dev/null
+++ b/testutils-ktx/src/main/java/androidx/testutils/TestDispatcher.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.testutils
+
+import kotlinx.coroutines.CoroutineDispatcher
+import java.util.concurrent.ConcurrentLinkedQueue
+import kotlin.coroutines.CoroutineContext
+
+/**
+ * [CoroutineDispatcher] which keeps track of all its queues jobs.
+ */
+class TestDispatcher : CoroutineDispatcher() {
+ val queue = ConcurrentLinkedQueue<Runnable>()
+
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ queue.add(block)
+ }
+
+ fun executeAll() {
+ while (queue.peek() != null) {
+ queue.poll()!!.run()
+ }
+ }
+}
diff --git a/viewpager2/build.gradle b/viewpager2/build.gradle
index 9de6aa7..9c933df 100644
--- a/viewpager2/build.gradle
+++ b/viewpager2/build.gradle
@@ -43,7 +43,9 @@
exclude group: 'androidx.viewpager2', module: 'viewpager2'
}
androidTestImplementation(KOTLIN_STDLIB)
- androidTestImplementation(project(":internal-testutils-ktx"))
+ androidTestImplementation(project(":internal-testutils-ktx"), {
+ exclude group: 'org.jetbrains.kotlinx'
+ })
}
android {
diff --git a/work/workmanager/api/2.3.0-alpha01.txt b/work/workmanager/api/2.3.0-alpha01.txt
index 0e3b058..d007563 100644
--- a/work/workmanager/api/2.3.0-alpha01.txt
+++ b/work/workmanager/api/2.3.0-alpha01.txt
@@ -80,7 +80,7 @@
method public long[]? getLongArray(String);
method public String? getString(String);
method public String![]? getStringArray(String);
- method public static byte[] toByteArray(androidx.work.Data);
+ method public byte[] toByteArray();
field public static final androidx.work.Data! EMPTY;
field public static final int MAX_DATA_BYTES = 10240; // 0x2800
}
diff --git a/work/workmanager/api/current.txt b/work/workmanager/api/current.txt
index 0e3b058..d007563 100644
--- a/work/workmanager/api/current.txt
+++ b/work/workmanager/api/current.txt
@@ -80,7 +80,7 @@
method public long[]? getLongArray(String);
method public String? getString(String);
method public String![]? getStringArray(String);
- method public static byte[] toByteArray(androidx.work.Data);
+ method public byte[] toByteArray();
field public static final androidx.work.Data! EMPTY;
field public static final int MAX_DATA_BYTES = 10240; // 0x2800
}
diff --git a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
index d44bdf5..780ee56 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/WorkDatabaseMigrationTest.java
@@ -307,8 +307,8 @@
contentValues.put("state", WorkTypeConverters.StateIds.ENQUEUED);
contentValues.put("worker_class_name", TestWorker.class.getName());
contentValues.put("input_merger_class_name", OverwritingInputMerger.class.getName());
- contentValues.put("input", Data.toByteArray(Data.EMPTY));
- contentValues.put("output", Data.toByteArray(Data.EMPTY));
+ contentValues.put("input", Data.EMPTY.toByteArray());
+ contentValues.put("output", Data.EMPTY.toByteArray());
contentValues.put("initial_delay", 0L);
contentValues.put("interval_duration", 0L);
contentValues.put("flex_duration", 0L);
diff --git a/work/workmanager/src/main/java/androidx/work/Data.java b/work/workmanager/src/main/java/androidx/work/Data.java
index 8febaf8..4fafd31 100644
--- a/work/workmanager/src/main/java/androidx/work/Data.java
+++ b/work/workmanager/src/main/java/androidx/work/Data.java
@@ -330,6 +330,20 @@
}
/**
+ * Converts this Data to a byte array suitable for sending to other processes in your
+ * application. There are no versioning guarantees with this byte array, so you should not
+ * use this for IPCs between applications or persistence.
+ *
+ * @return The byte array representation of the input
+ * @throws IllegalStateException if the serialized payload is bigger than
+ * {@link #MAX_DATA_BYTES}
+ */
+ @NonNull
+ public byte[] toByteArray() {
+ return Data.toByteArray(this);
+ }
+
+ /**
* @return The number of elements in this Data object.
* @hide
*/
@@ -345,8 +359,10 @@
* @param data The {@link Data} object to convert
* @return The byte array representation of the input
* @throws IllegalStateException if the serialized payload is bigger than
- * {@link #MAX_DATA_BYTES}
+ * {@link #MAX_DATA_BYTES}
+ * @hide
*/
+ @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@TypeConverter
public static @NonNull byte[] toByteArray(@NonNull Data data) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
diff --git a/work/workmanager/src/test/java/androidx/work/DataTest.java b/work/workmanager/src/test/java/androidx/work/DataTest.java
index 9bb2466..80740e8 100644
--- a/work/workmanager/src/test/java/androidx/work/DataTest.java
+++ b/work/workmanager/src/test/java/androidx/work/DataTest.java
@@ -47,7 +47,7 @@
public void testSerializeEmpty() {
Data data = Data.EMPTY;
- byte[] byteArray = Data.toByteArray(data);
+ byte[] byteArray = data.toByteArray();
Data restoredData = Data.fromByteArray(byteArray);
assertThat(restoredData, is(data));
@@ -62,7 +62,7 @@
.putString(KEY2, expectedValue2)
.build();
- byte[] byteArray = Data.toByteArray(data);
+ byte[] byteArray = data.toByteArray();
Data restoredData = Data.fromByteArray(byteArray);
assertThat(restoredData, is(data));