具有与SQLite模型类不同的自定义模型类的分页库-Android

时间:2019-06-24 16:24:48

标签: android dao android-paging

我正在跟踪Android Developers的Paging Library Overview,它使用DataSource.Factory通过另一种方式从数据库中获取数据:

@Dao
interface ConcertDao {
    // The Int type parameter tells Room to use a PositionalDataSource
    // object, with position-based loading under the hood.
    @Query("SELECT * FROM Concerts ORDER BY date DESC")
    fun concertsByDate(): DataSource.Factory<Int, Concert>
}

但是,在我的情况下,我没有表Concert,但是表ConcertAA以不同的方式存储值。

例如,我的Concert类是:

data class Concert(val date: Long, val bands: List<Band>)

我的ConcertAA Active Android类是:

@Table(name = "Concerts")
class ConcertAA(): Model(){

    @Column(name = "Bands")
    var bands: String? = null

    @Column(name = "Date", index = true)
    var date: Long? = null

}

我将乐队另存为Json字符串的地方。

因此,我的问题是我如何拥有一个ConcertDao,在查询到数据库的那一刻,我将每个ConcertAA对象转换为一个Concert对象以供使用在列表中?由于查询SELECT * FROM Concerts ORDER BY date DESC将返回ConcertAA的列表,而不返回Concert的列表。

1 个答案:

答案 0 :(得分:0)

即使下一个问题可以回答我自己的问题,但对于数据可能发生突变的数据库网络逻辑而言,此解决方案还不够,因为它无法处理对已保存在数据库中的数据的更新。

请原谅抽象类的数量-我通常致力于扩展和可重用性。此外,还请原谅Java和Kotlin代码的混合。.由于某种原因,我的项目中使用Kotlin不能识别某些库,但在这种情况下可以随意使用Kotlin。

所以基本上我们需要创建一个新的DataSource

abstract class MyDataSource<Value>: PositionalDataSource<Value>() {

    override fun loadInitial(params: PositionalDataSource.LoadInitialParams, callback: PositionalDataSource.LoadInitialCallback<Value>) {
        callback.onResult(getDataFromDatabase(params.requestedLoadSize, params.requestedStartPosition)?: listOf(), 0)
    }

    override fun loadRange(params: PositionalDataSource.LoadRangeParams, callback: PositionalDataSource.LoadRangeCallback<Value>) {
        callback.onResult(getDataFromDatabase(params.loadSize, params.startPosition)?: listOf())
    }

    abstract fun getDataFromDatabase(limit: Int, offset: Int): List<Value>?
}

已实现的Concert数据类:

class ConcertDataSource : MyDataSource<Concert>() {

    override fun getDataFromDatabase(limit: Int, offset: Int): List<Concert>? {
        return ConcertAA.getConcerts(limit, offset)
    }
}

然后,我们需要一个DataSourceFactory来创建我们的DataSource实例:

abstract class MyDataSourceFactory<Key, Value> : DataSource.Factory<Key, Value>() {

    val mutableLiveData: MutableLiveData<DataSource<Key, Value>>? = null

    override fun create(): DataSource<Key, Value> {
        val dataSource = createDataSource()
        mutableLiveData?.postValue(dataSource)
        return dataSource
    }

    abstract fun createDataSource(): DataSource<Key, Value>
}

以及为ConcertDataSource实现的DataSourceFactory:

class ConcertDataSourceFactory : MyDataSourceFactory<Int, Concert>() {

    override fun createDataSource(): DataSource<Int, Concert> {
        return ConcertDataSource()
    }
}

然后将ViewModel的{​​{1}}用作我们的数据源:

PagedList

我们使用public class ConcertViewModel extends ViewModel { public final LiveData<PagedList<Concert>> concertList; private FetchCallback callback; private final int pageSize = 10 PagedList.BoundaryCallback<Concert> boundaryCallback = new PagedList.BoundaryCallback<Concert>(){ boolean frontLoaded =false; public void onZeroItemsLoaded() { // callback.fetch(...); } public void onItemAtFrontLoaded(@NonNull Concert itemAtFront) { if(!frontLoaded) { // callback.fetch(...); } frontLoaded = true; } public void onItemAtEndLoaded(@NonNull Concert itemAtEnd) { // callback.fetch(...); } }; public ConcertViewModel(FetchCallback callback) { this.callback = callback; ConcertDataSourceFactory dataSourceFactory = new ConcertDataSourceFactory(); PagedList.Config config = new PagedList.Config.Builder() .setPageSize(pageSize) .setInitialLoadSizeHint(pageSize) .setEnablePlaceholders(false) .build(); concertList = new LivePagedListBuilder<>(dataSourceFactory, config).setBoundaryCallback(boundaryCallback).build(); } public void refresh() { conertList.getValue().getDataSource().invalidate(); } } 进行监听,只要PagedList要求到达列表的任一侧并且在我们的数据库数据中没有存储任何额外数据时,就需要加载更多内容。这将使能够从服务器(或任何数据提供者)获取更多数据。使用自定义的回调调用提取:

BoundaryCallback

现在,由于我们需要将回调传递给interface FetchCallback{ fun fetch(limit: Int?, concertIdOffset: String?) } ,因此需要告诉ViewModel如何使用参数创建ViewModelProviders的新实例。这是通过ViewModel完成的:

ViewModelProvider.Factory

我们为音乐会实施了abstract class MyViewModelFactory( private val callback: FetchCallback) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { return createViewModel(callback) } abstract fun <T : ViewModel> createViewModel(callback: FetchCallback): T }

ViewModelFactory

最后,我们从视图(class ConcertViewModelFactory(callback: FetchCallback) : MyViewModelFactory(callback) { override fun <T : ViewModel> createViewModel(callback: FetchCallback): T { return ConcertViewModel(callback) as T } } ViewModel等)初始化Activity

Fragment

这将是我的问题的答案,但是请注意,(至少目前)Android的Paging库无法处理可变数据。例如,如果音乐会具有可以更改的乐队列表(例如,其中一个乐队无法进入音乐会),则逻辑无法更新数据库中保存的数据,因为它仅在请求时向服务器请求额外的数据到达数据库中存储的数据的两个边界(顶部或底部)。因此,出于我自己的目的,该库没有用。