1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.paging
18 
19 import androidx.annotation.VisibleForTesting
20 import androidx.paging.internal.ReentrantLock
21 import androidx.paging.internal.withLock
22 
23 /**
24  * Wrapper class for a [PagingSource] factory intended for usage in [Pager] construction.
25  *
26  * Calling [invalidate] on this [InvalidatingPagingSourceFactory] will forward invalidate signals to
27  * all active [PagingSource]s that were produced by calling [invoke].
28  *
29  * This class is thread-safe for concurrent calls to any mutative operations including both [invoke]
30  * and [invalidate].
31  *
32  * @param pagingSourceFactory The [PagingSource] factory that returns a PagingSource when called
33  */
34 public class InvalidatingPagingSourceFactory<Key : Any, Value : Any>(
35     private val pagingSourceFactory: () -> PagingSource<Key, Value>
36 ) : PagingSourceFactory<Key, Value> {
37     private val lock = ReentrantLock()
38 
39     private var pagingSources: List<PagingSource<Key, Value>> = emptyList()
40 
pagingSourcesnull41     @VisibleForTesting internal fun pagingSources() = pagingSources
42 
43     /**
44      * @return [PagingSource] which will be invalidated when this factory's [invalidate] method is
45      *   called
46      */
47     override fun invoke(): PagingSource<Key, Value> {
48         return pagingSourceFactory().also { lock.withLock { pagingSources = pagingSources + it } }
49     }
50 
51     /**
52      * Calls [PagingSource.invalidate] on each [PagingSource] that was produced by this
53      * [InvalidatingPagingSourceFactory]
54      */
invalidatenull55     public fun invalidate() {
56         val previousList = lock.withLock { pagingSources.also { pagingSources = emptyList() } }
57         for (pagingSource in previousList) {
58             if (!pagingSource.invalid) {
59                 pagingSource.invalidate()
60             }
61         }
62     }
63 }
64