Skip to content

Commit ab9f156

Browse files
committed
接入Paging改写动态页面
1 parent 1f5855a commit ab9f156

File tree

21 files changed

+484
-128
lines changed

21 files changed

+484
-128
lines changed

.idea/codeStyles/Project.xml

Lines changed: 125 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/codeStyles/codeStyleConfig.xml

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ Model-View-ViewModel,View 指绿色的 Activity/Fragment,主要负责界面
8484
Glide相比起Fresco要轻量很多,api调用起来也很简洁,对图片加载要求不是很高的话建议使用Glide。
8585

8686
# 更新日志
87+
### v2.0
88+
* 接入Paging改写动态分页列表页面,并封装Paging版分页模版(BasePagingVMFragment、BaseLPagingModel)
89+
* 提供Paging版分页列表模版以及普通版分页列表模版,方便对比学习
90+
* 下个版本计划加入Navigation
8791
### v1.9
8892
* 添加动态页面
8993
* 调整项目结构,优化代码

app/build.gradle

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,21 @@ apply plugin: 'com.android.application'
22
apply plugin: 'kotlin-android'
33
apply plugin: 'kotlin-android-extensions'
44
apply plugin: 'kotlin-kapt'
5+
apply plugin: 'kotlin-noarg'
6+
apply plugin: 'kotlin-allopen'
7+
58
kapt {
69
generateStubs = true
710
}
811

12+
allOpen {
13+
annotation("com.fmt.github.Poko")
14+
}
15+
16+
noArg {
17+
annotation("com.fmt.github.Poko")
18+
}
19+
920
android {
1021
compileSdkVersion 28
1122
defaultConfig {
@@ -77,6 +88,9 @@ dependencies {
7788
kapt "androidx.room:room-compiler:2.2.5"
7889
implementation "androidx.room:room-ktx:2.2.5"
7990

91+
//paging
92+
implementation "androidx.paging:paging-runtime-ktx:2.1.2"
93+
8094
//koin(依赖注入)
8195
implementation "org.koin:koin-androidx-scope:2.0.1"
8296
implementation "org.koin:koin-androidx-viewmodel:2.0.1"
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.fmt.github.base.fragment
2+
3+
import androidx.lifecycle.Observer
4+
import androidx.paging.PagedList
5+
import androidx.paging.PagedListAdapter
6+
import androidx.recyclerview.widget.LinearLayoutManager
7+
import androidx.recyclerview.widget.RecyclerView
8+
import com.fmt.github.R
9+
import com.fmt.github.base.viewmodel.BaseLPagingModel
10+
import com.fmt.github.ext.yes
11+
import com.kennyc.view.MultiStateView
12+
import com.scwang.smartrefresh.layout.api.RefreshLayout
13+
import com.scwang.smartrefresh.layout.listener.OnLoadMoreListener
14+
import com.scwang.smartrefresh.layout.listener.OnRefreshListener
15+
import kotlinx.android.synthetic.main.common_refresh_recyclerview.*
16+
17+
/**
18+
* 基于Paging封装通用分页列表
19+
*/
20+
abstract class BasePagingVMFragment<M, VM : BaseLPagingModel<M>, VH : RecyclerView.ViewHolder> :
21+
BaseVMFragment(), OnRefreshListener,
22+
OnLoadMoreListener {
23+
24+
private val mAdapter: PagedListAdapter<M, VH> by lazy { getAdapter() }
25+
26+
lateinit var mViewModel: VM
27+
28+
override fun getLayoutRes(): Int = R.layout.common_refresh_recyclerview
29+
30+
override fun initView() {
31+
mRefreshLayout.run {
32+
setOnRefreshListener(this@BasePagingVMFragment)
33+
setOnLoadMoreListener(this@BasePagingVMFragment)
34+
}
35+
36+
mRecyclerView.layoutManager = LinearLayoutManager(mActivity)
37+
mRecyclerView.adapter = mAdapter
38+
39+
mViewModel = getViewModel() as VM
40+
mViewModel.mBoundaryData.observe(this, Observer {
41+
it.yes {
42+
mMultipleStatusView.viewState = MultiStateView.ViewState.CONTENT
43+
}
44+
})
45+
mViewModel.loadMoreState.observe(this, Observer {
46+
mRefreshLayout.setEnableLoadMore(it)//上拉加载进度条只有在Paging加载更多失败时才有效(用于规避Paging加载更多失败后,无法再次加载问题)
47+
})
48+
49+
afterViewCreated()
50+
}
51+
52+
override fun initData() {
53+
mRefreshLayout.autoRefreshAnimationOnly()
54+
mViewModel.pagedList.observe(this, Observer<PagedList<M>> {
55+
mAdapter.submitList(it)
56+
})
57+
}
58+
59+
override fun onRefresh(refreshLayout: RefreshLayout) {
60+
mViewModel.refresh()
61+
}
62+
63+
override fun onLoadMore(refreshLayout: RefreshLayout) {
64+
mViewModel.loadMoreRetry()
65+
}
66+
67+
override fun dismissLoading() {
68+
mRefreshLayout.run {
69+
finishRefresh()
70+
finishLoadMore()
71+
}
72+
}
73+
74+
abstract fun afterViewCreated()
75+
76+
abstract fun getAdapter(): PagedListAdapter<M, VH>
77+
78+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.fmt.github.base.viewmodel
2+
3+
import androidx.lifecycle.LiveData
4+
import androidx.lifecycle.MutableLiveData
5+
import androidx.lifecycle.viewModelScope
6+
import androidx.paging.DataSource
7+
import androidx.paging.LivePagedListBuilder
8+
import androidx.paging.PageKeyedDataSource
9+
import androidx.paging.PagedList
10+
import com.fmt.github.config.Configs
11+
import kotlinx.coroutines.launch
12+
13+
/**
14+
* 基于Paging封装通用ViewModel
15+
*/
16+
abstract class BaseLPagingModel<M> : BaseViewModel() {
17+
18+
lateinit var mDataSource: PageKeyedDataSource<Int, M>
19+
20+
val mBoundaryData = MutableLiveData(false)//控制页面显示状态
21+
22+
val loadMoreState = MutableLiveData(false)
23+
24+
var loadMoreRetry: (() -> Unit)? = null
25+
26+
val pagedList: LiveData<PagedList<M>> by lazy {
27+
LivePagedListBuilder<Int, M>(
28+
object : DataSource.Factory<Int, M>() {
29+
override fun create(): DataSource<Int, M> {
30+
mDataSource = PageDataSource()
31+
return mDataSource
32+
}
33+
}, PagedList.Config.Builder()
34+
.setPageSize(Configs.PAGE_SIZE)
35+
.setInitialLoadSizeHint(12)
36+
.build()
37+
).build()
38+
}
39+
40+
//真正加载数据的来源
41+
inner class PageDataSource : PageKeyedDataSource<Int, M>() {
42+
override fun loadInitial(
43+
params: LoadInitialParams<Int>,
44+
callback: LoadInitialCallback<Int, M>
45+
) {
46+
launch {
47+
val list = getDataList(1)
48+
mBoundaryData.postValue(list.isNotEmpty())
49+
callback.onResult(list, null, 2)
50+
}
51+
}
52+
53+
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, M>) {
54+
viewModelScope.launch {
55+
try {
56+
mStateLiveData.value = LoadState
57+
val list = getDataList(params.key)
58+
callback.onResult(
59+
list,
60+
params.key + 1
61+
)
62+
mStateLiveData.value = SuccessState
63+
loadMoreState.postValue(false)
64+
} catch (e: Exception) {
65+
mStateLiveData.value = ErrorState(e.message)
66+
loadMoreState.postValue(true)
67+
loadMoreRetry = {
68+
//保存加载更多失败时的场景
69+
loadMoreFail(params, callback)
70+
}
71+
}
72+
}
73+
}
74+
75+
override fun loadBefore(params: LoadParams<Int>, callback: LoadCallback<Int, M>) {}
76+
}
77+
78+
fun refresh() {//Paging刷新数据
79+
mDataSource.invalidate()
80+
}
81+
82+
fun loadMoreRetry() {//加载更多失败重试
83+
loadMoreRetry?.invoke()
84+
}
85+
86+
fun loadMoreFail(//加载更多失败时调用
87+
params: PageKeyedDataSource.LoadParams<Int>,
88+
callback: PageKeyedDataSource.LoadCallback<Int, M>
89+
) {
90+
mDataSource.loadAfter(params, callback)
91+
}
92+
93+
abstract suspend fun getDataList(page: Int): List<M>
94+
95+
96+
}

app/src/main/java/com/fmt/github/di/app_module.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.fmt.github.BuildConfig
77
import com.fmt.github.data.db.AppDataBase
88
import com.fmt.github.data.http.interceptor.AuthorizationInterceptor
99
import com.fmt.github.home.viewmodel.HomeViewModel
10+
import com.fmt.github.home.viewmodel.ReceivedEventViewModel
1011
import com.fmt.github.repos.api.ReposApi
1112
import com.fmt.github.repos.repository.ReposRepository
1213
import com.fmt.github.repos.viewmodel.ReposViewModel
@@ -28,17 +29,19 @@ private const val TAG = "fmt"
2829

2930
val viewModelModule = module {
3031
viewModel { HomeViewModel(get()) }
32+
viewModel { ReceivedEventViewModel(get()) }
3133
viewModel { ReposViewModel(get()) }
3234
viewModel { UserViewModel(get()) }
3335
}
3436

3537
val reposModule = module {
38+
//factory 每次注入时都重新创建一个新的对象
3639
factory { ReposRepository(get()) }
3740
factory { UserRepository(get(), get()) }
3841
}
3942

4043
val remoteModule = module {
41-
44+
//single 单例对象
4245
single {
4346
val httpLoggingInterceptor = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
4447
override fun log(message: String) {

0 commit comments

Comments
 (0)