Skip to content

Commit dddf24f

Browse files
committed
新增Flow+协程
1 parent d671b37 commit dddf24f

File tree

11 files changed

+142
-39
lines changed

11 files changed

+142
-39
lines changed

common/src/main/java/com/fuusy/common/base/BaseRepository.kt

+59-6
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import com.fuusy.common.network.DataState
66
import com.fuusy.common.network.ResState
77
import com.fuusy.common.network.net.StateLiveData
88
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Dispatchers
910
import kotlinx.coroutines.coroutineScope
11+
import kotlinx.coroutines.flow.*
1012
import java.io.IOException
1113

1214

13-
private const val TAG = "BaseRepository"
14-
1515
/**
1616
* @date:2021/5/20
1717
* @author fuusy
@@ -20,11 +20,65 @@ private const val TAG = "BaseRepository"
2020
*/
2121
open class BaseRepository {
2222

23+
companion object {
24+
private const val TAG = "BaseRepository"
25+
}
26+
27+
/**
28+
* 方式二:结合Flow请求数据。
29+
* 根据Flow的不同请求状态,如onStart、onEmpty、onCompletion等设置baseResp.dataState状态值,
30+
* 最后通过stateLiveData分发给UI层。
31+
*
32+
* @param block api的请求方法
33+
* @param stateLiveData 每个请求传入相应的LiveData,主要负责网络状态的监听
34+
*/
35+
suspend fun <T : Any> executeReqWithFlow(
36+
block: suspend () -> BaseResp<T>,
37+
stateLiveData: StateLiveData<T>
38+
) {
39+
var baseResp = BaseResp<T>()
40+
flow {
41+
val respResult = block.invoke()
42+
baseResp = respResult
43+
Log.d(TAG, "executeReqWithFlow: $baseResp")
44+
baseResp.dataState = DataState.STATE_SUCCESS
45+
stateLiveData.postValue(baseResp)
46+
emit(respResult)
47+
}
48+
.flowOn(Dispatchers.IO)
49+
.onStart {
50+
Log.d(TAG, "executeReqWithFlow:onStart")
51+
baseResp.dataState = DataState.STATE_LOADING
52+
stateLiveData.postValue(baseResp)
53+
}
54+
.onEmpty {
55+
Log.d(TAG, "executeReqWithFlow:onEmpty")
56+
baseResp.dataState = DataState.STATE_EMPTY
57+
stateLiveData.postValue(baseResp)
58+
}
59+
.catch { exception ->
60+
run {
61+
Log.d(TAG, "executeReqWithFlow:code ${baseResp.errorCode}")
62+
exception.printStackTrace()
63+
baseResp.dataState = DataState.STATE_ERROR
64+
baseResp.error = exception
65+
stateLiveData.postValue(baseResp)
66+
}
67+
}
68+
.collect {
69+
Log.d(TAG, "executeReqWithFlow: collect")
70+
stateLiveData.postValue(baseResp)
71+
}
72+
73+
74+
}
75+
2376
/**
77+
* 方式一
2478
* repo 请求数据的公共方法,
2579
* 在不同状态下先设置 baseResp.dataState的值,最后将dataState 的状态通知给UI
26-
* @param api的请求方法
27-
* @param 每个请求传入相应的LiveData,主要负责网络状态的监听
80+
* @param block api的请求方法
81+
* @param stateLiveData 每个请求传入相应的LiveData,主要负责网络状态的监听
2882
*/
2983
suspend fun <T : Any> executeResp(
3084
block: suspend () -> BaseResp<T>,
@@ -63,8 +117,7 @@ open class BaseRepository {
63117

64118

65119
/**
66-
* @deprecated Use {@link executeResp}
67-
* instead.
120+
* @deprecated Use {@link executeResp} instead.
68121
*/
69122
suspend fun <T : Any> executeResp(
70123
resp: BaseResp<T>,

common/src/main/java/com/fuusy/common/base/BaseViewModel.kt

+10-8
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
package com.fuusy.common.base
22

3-
import android.util.Log
4-
import androidx.lifecycle.MutableLiveData
53
import androidx.lifecycle.ViewModel
64
import androidx.lifecycle.viewModelScope
7-
import com.fuusy.common.network.BaseResp
8-
import com.fuusy.common.network.DataState
95
import com.fuusy.common.support.SingleLiveData
10-
import kotlinx.coroutines.*
11-
import java.lang.Exception
6+
import kotlinx.coroutines.Dispatchers
7+
import kotlinx.coroutines.launch
128

13-
private const val TAG = "BaseViewModel"
9+
/**
10+
* @date:2021/6/11
11+
* @author fuusy
12+
* @instruction:
13+
*/
1414
open class BaseViewModel : ViewModel() {
1515
val loadingLiveData = SingleLiveData<Boolean>()
1616

1717
val errorLiveData = SingleLiveData<Throwable>()
1818

19+
/**
20+
* @deprecated
21+
*/
1922
fun launch(
2023
block: suspend () -> Unit,
2124
error: suspend (Throwable) -> Unit,
@@ -26,7 +29,6 @@ open class BaseViewModel : ViewModel() {
2629
try {
2730
block()
2831
} catch (e: Exception) {
29-
Log.d(TAG, "launch: error ")
3032
error(e)
3133
} finally {
3234
complete()

common/src/main/java/com/fuusy/common/base/paging/BasePagingAdapter.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ import com.fuusy.common.R
1818
* @author fuusy
1919
* @instruction:Paging3Adapter的公共类,主要减少adapter的冗余代码。
2020
*/
21-
private const val TAG = "BasePagingAdapter"
22-
2321
abstract class BasePagingAdapter<T : Any>(private var diffCallback: DiffUtil.ItemCallback<T>) :
2422
PagingDataAdapter<T, RecyclerView.ViewHolder>(diffCallback) {
2523

2624
companion object {
27-
25+
private const val TAG = "BasePagingAdapter"
2826
}
2927

3028
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

common/src/main/java/com/fuusy/common/network/net/StateLiveData.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import com.fuusy.common.network.BaseResp
55

66

77
/**
8-
* MutableLiveData,用于将请求状态分发给UI
8+
* @date:2021/6/11
9+
* @author fuusy
10+
* @instruction:MutableLiveData,用于将请求状态分发给UI
911
*/
1012
class StateLiveData<T> : MutableLiveData<BaseResp<T>>() {
1113
}

dependencies.gradle

+3-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ dependencies {
6969
implementation 'androidx.paging:paging-runtime:3.0.0-beta01'
7070
implementation 'androidx.paging:paging-common:3.0.0-beta01'
7171

72-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2")
72+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2"
7373
implementation "androidx.viewpager2:viewpager2:1.0.0"
7474
implementation "com.alibaba:arouter-api:1.5.0"
7575
kapt "com.alibaba:arouter-compiler:1.2.2"
@@ -97,4 +97,6 @@ dependencies {
9797
//coil
9898
implementation("io.coil-kt:coil:1.2.1")
9999

100+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
101+
100102
}

home/src/main/java/com/fuusy/home/dao/ArticleDao.kt

-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,4 @@ interface ArticleDao {
1616
@Query("DELETE FROM tab_article WHERE articleType=:articleType")
1717
suspend fun clearArticleByType(articleType: Int)
1818

19-
2019
}

project/src/main/java/com/fuusy/project/repo/ProjectDataSource.kt

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,43 @@
11
package com.fuusy.project.repo
22

3+
import android.util.Log
34
import androidx.paging.PagingSource
45
import androidx.paging.PagingState
56
import com.fuusy.project.bean.ProjectContent
67

8+
/**
9+
* @date:2021/6/11
10+
* @author fuusy
11+
* @instruction:项目列表Paging数据源
12+
*/
713
class ProjectDataSource(private val service: ProjectApi, id: Int) :
814
PagingSource<Int, ProjectContent>() {
915

16+
companion object {
17+
private const val TAG = "ProjectDataSource"
18+
}
19+
1020
private val mId: Int = id
1121

1222
override fun getRefreshKey(state: PagingState<Int, ProjectContent>): Int? = null
1323

1424
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ProjectContent> {
25+
Log.d(TAG, "load: *******")
1526
return try {
16-
val pageNum = params.key ?: 1
17-
val data = service.loadContentById(pageNum, mId)
18-
val preKey = if (pageNum > 1) pageNum - 1 else null
19-
LoadResult.Page(data.data!!.datas, prevKey = preKey, nextKey = pageNum + 1)
27+
var currentPage = params.key ?: 1
28+
val response = service.loadContentById(currentPage, mId)
29+
var nextPageNumber = if (currentPage < response.data?.pageCount ?: 0) {
30+
currentPage + 1
31+
} else {
32+
//没有更多数据
33+
null
34+
}
2035

36+
return LoadResult.Page(
37+
data = response.data!!.datas,
38+
prevKey = null, // 仅向后翻页
39+
nextKey = nextPageNumber
40+
)
2141
} catch (e: Exception) {
2242
LoadResult.Error(e)
2343
}

project/src/main/java/com/fuusy/project/repo/ProjectRepo.kt

+17-9
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,33 @@ import androidx.paging.Pager
44
import androidx.paging.PagingConfig
55
import androidx.paging.PagingData
66
import com.fuusy.common.base.BaseRepository
7-
import com.fuusy.common.network.RetrofitManager
87
import com.fuusy.common.network.net.StateLiveData
98
import com.fuusy.project.bean.ProjectContent
109
import com.fuusy.project.bean.ProjectTree
1110
import kotlinx.coroutines.flow.Flow
1211

13-
private const val TAG = "ProjectRepo"
14-
12+
/**
13+
* @date:2021/6/11
14+
* @author fuusy
15+
* @instruction:“项目” Repository层
16+
*/
1517
class ProjectRepo(private val service: ProjectApi) : BaseRepository() {
18+
private val pageSize = 20
1619

17-
20+
/**
21+
* 请求项目分类。
22+
* @param stateLiveData 带有请求状态的LiveData
23+
*/
1824
suspend fun loadProjectTree(stateLiveData: StateLiveData<List<ProjectTree>>) {
19-
executeResp({ service.loadProjectTree() }, stateLiveData)
25+
executeResp(
26+
{ service.loadProjectTree() }
27+
, stateLiveData)
2028
}
2129

22-
23-
private val pageSize = 20
24-
25-
//请求首页文章
30+
/**
31+
* 通过项目分类的ID,利用Paging3+Flow请求项目详细列表。
32+
*
33+
*/
2634
fun loadContentById(id: Int): Flow<PagingData<ProjectContent>> {
2735
val config = PagingConfig(
2836
pageSize = pageSize,

project/src/main/java/com/fuusy/project/ui/ProjectContentFragment.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import kotlinx.coroutines.flow.collectLatest
1313
import kotlinx.coroutines.launch
1414
import org.koin.androidx.viewmodel.ext.android.viewModel
1515

16+
/**
17+
* @date:2021/6/11
18+
* @author fuusy
19+
* @instruction:项目列表ListFragment
20+
*/
1621
class ProjectContentFragment : BaseFragment<FragmentProjectContentBinding>() {
1722
private val mViewModel: ProjectViewModel by viewModel()
1823

@@ -31,7 +36,6 @@ class ProjectContentFragment : BaseFragment<FragmentProjectContentBinding>() {
3136
}
3237
}
3338

34-
3539
mBinding?.run {
3640
rvProjectContent.adapter = projectAdapter.withLoadStateFooter(FooterAdapter {
3741

project/src/main/java/com/fuusy/project/ui/ProjectFragment.kt

+9-1
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ import com.fuusy.project.databinding.FragmentProjectBinding
1111
import com.fuusy.project.viewmodel.ProjectViewModel
1212
import org.koin.androidx.viewmodel.ext.android.viewModel
1313

14-
private const val TAG = "ProjectFragment"
1514

15+
/**
16+
* @date:2021/6/11
17+
* @author fuusy
18+
* @instruction:‘项目’Fragment
19+
*/
1620
class ProjectFragment : BaseFragment<FragmentProjectBinding>() {
1721

1822
private val mViewModel: ProjectViewModel by viewModel()
1923
private val mAdapter by lazy { ProjectAdapter() }
2024

25+
companion object {
26+
private const val TAG = "ProjectFragment"
27+
}
28+
2129
override fun initData() {
2230
Log.d(TAG, "initData: ")
2331
initView()

project/src/main/java/com/fuusy/project/viewmodel/ProjectViewModel.kt

+11-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import kotlinx.coroutines.flow.Flow
1313
import kotlinx.coroutines.launch
1414

1515
private const val TAG = "ProjectViewModel"
16-
class ProjectViewModel(private val repo :ProjectRepo) : BaseViewModel() {
16+
17+
class ProjectViewModel(private val repo: ProjectRepo) : BaseViewModel() {
1718
val mProjectTreeLiveData = StateLiveData<List<ProjectTree>>()
1819

1920

@@ -41,16 +42,22 @@ class ProjectViewModel(private val repo :ProjectRepo) : BaseViewModel() {
4142
4243
*/
4344

45+
/**
46+
* 向Repository层请求项目分类。
47+
*/
4448
fun loadProjectTree() {
4549
viewModelScope.launch(Dispatchers.IO) {
4650
repo.loadProjectTree(mProjectTreeLiveData)
4751
}
4852
}
4953

50-
51-
fun loadProjectContentById(id: Int) : Flow<PagingData<ProjectContent>> =
54+
/**
55+
* 根据项目ID请求项目列表详情。Paging3+Flow
56+
*
57+
* @param id 项目分类ID
58+
*/
59+
fun loadProjectContentById(id: Int): Flow<PagingData<ProjectContent>> =
5260
repo.loadContentById(id).cachedIn(viewModelScope)
5361

5462

55-
5663
}

0 commit comments

Comments
 (0)