Не всегда.
Если вы используете другие компоненты или библиотеки архитектуры Android, которые предоставляют хорошую поддержку, в большинстве случаев DataSource.Factory будет доставлен в результате вызова метода, как это делает база данных Room.
Если вы действительно хотите очень общий и у вас нет проблем с отражением:
class GenericFactory<K, R>(private val kClass: KClass<DataSource<K, R>>) : DataSource.Factory<K, R>() {
override fun create(): DataSource<K, R> = kClass.java.newInstance()
}
В вашем примере показана DataSource.Factory, которая представляет DataSource в качестве LiveData. Это просто необходимо в определенных случаях, например, когда DataSource содержит метод retry для вызова API. В других случаях ваш DataSource.Factory будет так же прост, как и еще 3 строки в вашем DataSource:
class MySimpleDataSource<R> : PageKeyedDataSource<String, R>() {
override fun loadBefore(params: LoadParams<String>,
callback: LoadCallback<String, R>) {
// do your thing
}
override fun loadAfter(params: LoadParams<String>,
callback: LoadCallback<String, R>) {
// do your thing
}
override fun loadInitial(params: LoadInitialParams<String>,
callback: LoadInitialCallback<String, R>) {
// do your thing
}
class Factory<R> : DataSource.Factory<String, R>() {
override fun create(): DataSource<String, R> = MySimpleDataSource<R>()
}
}
Я предполагаю, что наиболее распространенный случай для пользовательских DataSource.Factory - это разбитые на страницы вызовы REST API. В этом случае вы можете просто реализовать один общий DataSource и один DataSource.Factory, который получает объект запроса и ответный обратный вызов в виде лямбды.
data class MyCollection<R>(
var items: List<R>,
var nextPageToken: String
)
data class MyData(
var title: String = ""
)
abstract class SomeLibraryPagedClientRequest<R> {
abstract fun setNextPageToken(token: String?): SomeLibraryPagedClientRequest<R>
abstract fun enqueue(callback: (response: Response<R>) -> Unit): Unit
}
class MyRestApiDataSource(
private val request: SomeLibraryPagedClientRequest<MyData>,
private val handleResponse: (Response<R>) -> Unit
) : ItemKeyedDataSource<String, MyData>() {
var nextPageToken: String = ""
override fun getKey(item: MyData): String = nextPageToken
override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<MyData>) {
}
override fun loadInitial(params: LoadInitialParams<String>, callback: LoadInitialCallback<MyData>) {
request.setNextPageToken(params.requestedInitialKey).enqueue { data ->
nextPageToken = response.data.nextPageToken
if(response.isSucefull) callback.onResult(response.data.items)
handleResponse.invoke(response)
}
}
override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<MyData>) {
request.setNextPageToken(params.key).enqueue { response ->
nextPageToken = response.data.nextPageToken
if(response.isSucefull) callback.onResult(response.data.items)
handleResponse.invoke(response)
}
}
class Factory<R>(
private val request: SomeLibraryPagedClientRequest<MyData>,
private val handleResponse: (Response<R>) -> Unit
) : DataSource.Factory<String, R>() {
override fun create(): DataSource<String, R> = MySimpleDataSource<R>()
}
}