1 /* 2 * Copyright 2019 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.arch.core.util.Function 20 import java.util.IdentityHashMap 21 22 @Suppress("DEPRECATION") 23 internal class WrapperItemKeyedDataSource<K : Any, A : Any, B : Any>( 24 private val source: ItemKeyedDataSource<K, A>, 25 private val listFunction: Function<List<A>, List<B>> 26 ) : ItemKeyedDataSource<K, B>() { 27 28 private val keyMap = IdentityHashMap<B, K>() 29 addInvalidatedCallbacknull30 override fun addInvalidatedCallback(onInvalidatedCallback: InvalidatedCallback) { 31 source.addInvalidatedCallback(onInvalidatedCallback) 32 } 33 removeInvalidatedCallbacknull34 override fun removeInvalidatedCallback(onInvalidatedCallback: InvalidatedCallback) { 35 source.removeInvalidatedCallback(onInvalidatedCallback) 36 } 37 invalidatenull38 override fun invalidate() { 39 source.invalidate() 40 } 41 42 override val isInvalid 43 get() = source.isInvalid 44 convertWithStashedKeysnull45 fun convertWithStashedKeys(source: List<A>): List<B> { 46 val dest = convert(listFunction, source) 47 synchronized(keyMap) { 48 // synchronize on keyMap, since multiple loads may occur simultaneously. 49 // Note: manually sync avoids locking per-item (e.g. Collections.synchronizedMap) 50 for (i in dest.indices) { 51 keyMap[dest[i]] = this.source.getKey(source[i]) 52 } 53 } 54 return dest 55 } 56 loadInitialnull57 override fun loadInitial(params: LoadInitialParams<K>, callback: LoadInitialCallback<B>) { 58 source.loadInitial( 59 params, 60 object : LoadInitialCallback<A>() { 61 override fun onResult(data: List<A>, position: Int, totalCount: Int) { 62 callback.onResult(convertWithStashedKeys(data), position, totalCount) 63 } 64 65 override fun onResult(data: List<A>) { 66 callback.onResult(convertWithStashedKeys(data)) 67 } 68 } 69 ) 70 } 71 loadAfternull72 override fun loadAfter(params: LoadParams<K>, callback: LoadCallback<B>) { 73 source.loadAfter( 74 params, 75 object : LoadCallback<A>() { 76 override fun onResult(data: List<A>) { 77 callback.onResult(convertWithStashedKeys(data)) 78 } 79 } 80 ) 81 } 82 loadBeforenull83 override fun loadBefore(params: LoadParams<K>, callback: LoadCallback<B>) { 84 source.loadBefore( 85 params, 86 object : LoadCallback<A>() { 87 override fun onResult(data: List<A>) { 88 callback.onResult(convertWithStashedKeys(data)) 89 } 90 } 91 ) 92 } 93 getKeynull94 override fun getKey(item: B): K = 95 synchronized(keyMap) { 96 return keyMap[item]!! 97 } 98 } 99