参考资料:
源码:https://mp.weixin.qq.com/s/aoBAuiuSRvfyCpnHGYrpwA
设计思路:https://mp.weixin.qq.com/s/QoKwTm0x6hssCzocnDp_1A
如果没有现在这么爱较真的心情,直接查看以上地址完全能够理解,而且写得也很好,以下也是参考这篇文章的。(我就是个搬代码的瓦匠工,如有雷同,时间在我前都算我借鉴的,以下字是我一行行敲的)
非常重要的原理图(网上拷贝)以及源码结构(自行剪切)
原理图基本上说明了paging分页的工作原理。源码确实类名比较多,根据原理图以及实际操作来按顺序讲解。
类介绍
这里先不做介绍,按照PagingWithNetworkSample demo走一遍,这个有的手机因为某些你懂得原因访问网络失败,那就重新找个demo,或者用pagingsample demo将就下。
PagingWithNetWorkSample案例:( kotlin编写的代码)
这里面有三个:
1.network only(by item)以这条为主线进行讲解
2.network only (by page)不讲,雷同by item
3.db+network( roomdatabase)作为晋级来讲;
(1) network only(by item)
用户点击 NETWORK ONLY(BY ITEM) 按钮引发的血案…(我网络请求失败了,大爷的,那咱直接分析代码):
默认输入KEY_SUBREDDIT 值导致调用repository.postsOfSubreddit(it, 30)方法
SubRedditViewModel.kt:
companion object {
const val KEY_SUBREDDIT = "subreddit"
const val DEFAULT_SUBREDDIT = "androiddev"
}
init {
if (!savedStateHandle.contains(KEY_SUBREDDIT)) {
savedStateHandle.set(KEY_SUBREDDIT, DEFAULT_SUBREDDIT)
}
}
private val repoResult = savedStateHandle.getLiveData<String>(KEY_SUBREDDIT).map {
repository.postsOfSubreddit(it, 30) *注释①*
}
repository.postsOfSubreddit方法逻辑如下
先SubRedditViewModel 方法调用val repo = ServiceLocator.instance(this@RedditActivity).getRepository(repoType);
然后在ServiceLocator类中instance方法实例化DefaultServiceLocator(继承ServiceLocator)并且getRepository()方法,根据type调用InMemoryByItemRepository,其实以上代码注释①调用的就是这里的postsOfSubreddit方法。
RedditActivity.kt:
private val model: SubRedditViewModel by viewModels {
object : AbstractSavedStateViewModelFactory(this, null) {
override fun <T : ViewModel?> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
val repoTypeParam = intent.getIntExtra(KEY_REPOSITORY_TYPE, 0)
val repoType = RedditPostRepository.Type.values()[repoTypeParam]
val repo = ServiceLocator.instance(this@RedditActivity)
.getRepository(repoType)
@Suppress("UNCHECKED_CAST")
return SubRedditViewModel(repo, handle) as T
}
}
}
ServiceLocator.kt:
fun instance(context: Context): ServiceLocator {
synchronized(LOCK) {
if (instance == null) {
instance = DefaultServiceLocator(
app = context.applicationContext as Application,
useInMemoryDb = false)
}
return instance!!
}
}
...
override fun getRepository(type: RedditPostRepository.Type): RedditPostRepository {
return when (type) {
RedditPostRepository.Type.IN_MEMORY_BY_ITEM -> InMemoryByItemRepository(
redditApi = getRedditApi(),
networkExecutor = getNetworkExecutor())
RedditPostRepository.Type.IN_MEMORY_BY_PAGE -> InMemoryByPageKeyRepository(
redditApi = getRedditApi(),
networkExecutor = getNetworkExecutor())
RedditPostRepository.Type.DB -> DbRedditPostRepository(
db = db,
redditApi = getRedditApi(),
ioExecutor = getDiskIOExecutor())
}
}
InMemoryByItemRepository.kt:
@MainThread
override fun postsOfSubreddit(subReddit: String, pageSize: Int): Listing<RedditPost> {
val sourceFactory = SubRedditDataSourceFactory(redditApi, subReddit, networkExecutor)
// We use toLiveData Kotlin ext. function here, you could also use LivePagedListBuilder
val livePagedList = sourceFactory.toLiveData(
// we use Config Kotlin ext. function here, could also use PagedList.Config.Builder
config = Config(
pageSize = pageSize,
enablePlaceholders = false,
initialLoadSizeHint = pageSize * 2),
// provide custom executor for network requests, otherwise it will default to
// Arch Components' IO pool which is also used for disk access
fetchExecutor = networkExecutor)
...
}
Config是配置文件:这里配置每页请求个数,占位符为false(一般都为false,这个对我而言目前用不上,而且用起来不复杂,这里不表),首次请求为page*2
(源码)PagedListConfig.kt
@Suppress("FunctionName")
fun Config(
pageSize: Int,
prefetchDistance: Int = pageSize,
enablePlaceholders: Boolean = true,
initialLoadSizeHint: Int =
pageSize * PagedList.Config.Builder.DEFAULT_INITIAL_PAGE_MULTIPLIER,
maxSize: Int = PagedList.Config.MAX_SIZE_UNBOUNDED
): PagedList.Config {
return PagedList.Config.Builder()
.setPageSize(pageSize)
.setPrefetchDistance(prefetchDistance)
.setEnablePlaceholders(enablePlaceholders)
.setInitialLoadSizeHint(initialLoadSizeHint)
.setMaxSize(maxSize)
.build()
}
SubRedditDataSourceFactory继承 DataSource.Factory,工厂用于创建DataSource,
class SubRedditDataSourceFactory(
private val redditApi: RedditApi,
private val subredditName: String,
private val retryExecutor: Executor) : DataSource.Factory<String, RedditPost>() {
val sourceLiveData = MutableLiveData<ItemKeyedSubredditDataSource>()
override fun create(): DataSource<String, RedditPost> {*注释②*
val source = ItemKeyedSubredditDataSource(redditApi, subredditName, retryExecutor)
sourceLiveData.postValue(source)
return source
}
}
DataSource.Factory转换为livedata数据,这里创建LivePagedListBuilder方法,该方法用于创