diff --git a/app/src/main/java/com/shuwei/dish/match/net/NetViewModel.kt b/app/src/main/java/com/shuwei/dish/match/net/NetViewModel.kt index 31220c6..caa5240 100644 --- a/app/src/main/java/com/shuwei/dish/match/net/NetViewModel.kt +++ b/app/src/main/java/com/shuwei/dish/match/net/NetViewModel.kt @@ -6,6 +6,9 @@ import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodGoodsEntity import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.entity.SeasoningEntity +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch /** @@ -42,16 +45,19 @@ class NetViewModel( } } + /** + * 搜索菜品列表的 UI 状态流,UI 层通过 collect 监听 + */ + private val _searchFoodState = MutableStateFlow?>>(UiState.Idle) + val searchFoodState: StateFlow?>> = _searchFoodState.asStateFlow() + /** * 搜索菜品列表 */ - fun searchFoodList( - param: MutableMap, - onSuccess: (MutableList?) -> Unit, - onFailure: (String, String) -> Unit - ) { + fun searchFoodList(param: MutableMap) { viewModelScope.launch { - repository.searchFoodList(param, onSuccess, onFailure) + _searchFoodState.value = UiState.Loading + _searchFoodState.value = repository.searchFoodList(param) } } diff --git a/app/src/main/java/com/shuwei/dish/match/net/RemoteRepository.kt b/app/src/main/java/com/shuwei/dish/match/net/RemoteRepository.kt index 3b24236..5fb598c 100644 --- a/app/src/main/java/com/shuwei/dish/match/net/RemoteRepository.kt +++ b/app/src/main/java/com/shuwei/dish/match/net/RemoteRepository.kt @@ -46,18 +46,18 @@ class RemoteRepository { /** * 搜索菜品列表 * @param param 查询参数 - * @param onSuccess 成功回调 - * @param onFailure 失败回调,参数为 (errorCode, errorMsg) + * @return UiState 包装的结果,Success 携带列表数据,Error 携带错误信息 */ - suspend fun searchFoodList( - param: MutableMap, - onSuccess: (MutableList?) -> Unit, - onFailure: (String, String) -> Unit - ) = request( - onRequest = { apiService.searchFoodList(param = param) }, - onSuccess = onSuccess, - onFailure = onFailure - ) + suspend fun searchFoodList(param: MutableMap): UiState?> { + return try { + val resp = apiService.searchFoodList(param = param) + if (resp.isSuccess()) UiState.Success(resp.data) + else UiState.Error(resp.code, resp.msg ?: "") + } catch (e: Exception) { + val ex = getApiException(e) + UiState.Error("-1", ex.errorMsg) + } + } /** * 查询采样数据列表 diff --git a/app/src/main/java/com/shuwei/dish/match/net/UiState.kt b/app/src/main/java/com/shuwei/dish/match/net/UiState.kt new file mode 100644 index 0000000..3374de9 --- /dev/null +++ b/app/src/main/java/com/shuwei/dish/match/net/UiState.kt @@ -0,0 +1,15 @@ +package com.shuwei.dish.match.net + +/** + * 统一 UI 状态模型,用于 ViewModel 向 UI 层传递请求状态 + * Idle — 初始状态,未发起请求 + * Loading — 请求进行中 + * Success — 请求成功,携带数据 + * Error — 请求失败,携带错误码和错误信息 + */ +sealed class UiState { + object Idle : UiState() + object Loading : UiState() + data class Success(val data: T) : UiState() + data class Error(val code: String, val msg: String) : UiState() +} diff --git a/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt index 42f2df8..9b9144c 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/DishSamplingActivity.kt @@ -107,8 +107,8 @@ class DishSamplingActivity : BaseActivity() { ViewModelProvider(this, factory)[AppViewModel::class.java] } - fun getCookFoodList(action: (MutableList?) -> Unit) { - appViewModel.getCookFoodList(cookMode = 1) { action(it) } + fun getCookFoodList() { + appViewModel.getCookFoodList(cookMode = 1) } /** diff --git a/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt index 9df5d76..30a69c3 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/FoodSearchActivity.kt @@ -4,6 +4,9 @@ import android.annotation.SuppressLint import android.content.Intent import android.os.Bundle import android.view.LayoutInflater +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.LinearLayoutManager import com.shuwei.dish.match.R import com.shuwei.dish.match.adapter.FoodRecordAdapter @@ -12,6 +15,7 @@ import com.shuwei.dish.match.base.BaseApp import com.shuwei.dish.match.databinding.ActivityFoodSearchBinding import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding import com.shuwei.dish.match.entity.FoodRecord +import com.shuwei.dish.match.net.UiState import com.shuwei.dish.match.utils.KeyboardUtil import com.shuwei.dish.match.utils.ext.addOnActionSearchListener import com.shuwei.dish.match.utils.ext.gone @@ -19,6 +23,7 @@ import com.shuwei.dish.match.utils.ext.startActivity import com.shuwei.dish.match.utils.ext.toast import com.shuwei.dish.match.utils.ext.visible import java.io.Serializable +import kotlinx.coroutines.launch class FoodSearchActivity : BaseActivity() { @@ -83,6 +88,31 @@ class FoodSearchActivity : BaseActivity() { adapter = recordAdapter } addViewListener() + initObserver() + } + + /** + * 收集 searchFoodState,统一处理 Loading / Success / Error 状态 + */ + private fun initObserver() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + netViewModel.searchFoodState.collect { state -> + when (state) { + is UiState.Loading -> showLoading() + is UiState.Success -> handleSearchResult(state.data) + is UiState.Error -> { + delayDismissLoading() + finishRefresh() + binding.refreshLayout.setEnableRefresh(true) + toast(state.msg) + if (pageNo == 1) loadEmptyView() + } + is UiState.Idle -> {} + } + } + } + } } private fun addViewListener() { @@ -140,61 +170,6 @@ class FoodSearchActivity : BaseActivity() { @SuppressLint("NotifyDataSetChanged") private fun queryListInfo(input: String) { - showLoading() -// val map = mutableMapOf( -// "foodName" to input.trim(), -// "pageNo" to "$pageNo", -// "pageSize" to "$pageSize", -// "canteenId" to BaseApp.canteenId -// "dinnerType" to getDinnerTypeText() -// ) -// val sb = StringBuilder(UrlConfig.QUERY_FOOD_LIST).apply { -// append("?") -// map.forEach { (key, value) -> append("$key=$value&") } -// } -// sb.deleteCharAt(sb.length - 1) -// HttpUtil.get( -// url = sb.toString(), -// doSuccess = { -// delayDismissLoading() -// finishRefresh() -// binding.refreshLayout.run { -// setEnableRefresh(true) -// } -// val json = it.toJsonString() -// val recordBean: FoodRecordBean? = json.toObject() -// if (recordBean == null || recordBean.records.isNullOrEmpty()) { -//// toast("暂未搜索到相关菜品信息") -// if (pageNo == 1) { -// loadEmptyView() -// } -// return@get -// } -// val records = recordBean.records -// if (pageNo == 1) { -// list.clear() -// } -// list.addAll(records!!) -// recordAdapter.notifyDataSetChanged() -// val isLoadMoreEnable = records.size >= pageSize -// binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable) -// if (isLoadMoreEnable) { -// pageNo++ -// } -// }, -// doFailure = { code, msg -> -// binding.refreshLayout.run { -// setEnableRefresh(true) -// } -// toast(msg) -// delayDismissLoading() -// finishRefresh() -// if (pageNo == 1) { -// loadEmptyView() -// } -// } -// ) - val map = mutableMapOf( "foodName" to input.trim(), "pageNum" to pageNo, @@ -202,40 +177,27 @@ class FoodSearchActivity : BaseActivity() { "placeId" to BaseApp.canteenId, "dinnerType" to getDinnerTypeText() ) - netViewModel.searchFoodList( - param = map, - onSuccess = { - delayDismissLoading() - finishRefresh() - binding.refreshLayout.setEnableRefresh(true) - if (it.isNullOrEmpty()) { -// toast("暂未搜索到相关菜品信息") - if (pageNo == 1) { - loadEmptyView() - } - return@searchFoodList - } - if (pageNo == 1) { - list.clear() - } - list.addAll(it) - recordAdapter.notifyDataSetChanged() - val isLoadMoreEnable = it.size >= pageSize - binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable) - if (isLoadMoreEnable) { - pageNo++ - } - }, onFailure = { code, msg -> - binding.refreshLayout.run { - setEnableRefresh(true) - } - toast(msg) - delayDismissLoading() - finishRefresh() - if (pageNo == 1) { - loadEmptyView() - } - }) + netViewModel.searchFoodList(param = map) + } + + /** + * 处理搜索结果,填充列表或展示空视图 + */ + @SuppressLint("NotifyDataSetChanged") + private fun handleSearchResult(records: MutableList?) { + delayDismissLoading() + finishRefresh() + binding.refreshLayout.setEnableRefresh(true) + if (records.isNullOrEmpty()) { + if (pageNo == 1) loadEmptyView() + return + } + if (pageNo == 1) list.clear() + list.addAll(records) + recordAdapter.notifyDataSetChanged() + val isLoadMoreEnable = records.size >= pageSize + binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable) + if (isLoadMoreEnable) pageNo++ } private fun finishRefresh() { diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt index 0577cd6..a3130ea 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/SamplingListActivity.kt @@ -5,7 +5,10 @@ import android.content.Intent import android.os.Bundle import android.view.LayoutInflater import androidx.activity.addCallback +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import com.shuwei.dish.match.R @@ -27,6 +30,7 @@ import com.shuwei.dish.match.utils.ext.visible import com.shuwei.dish.match.viewmodel.AppViewModel import com.shuwei.dish.match.viewmodel.factory.AppFactory import java.io.Serializable +import kotlinx.coroutines.launch class SamplingListActivity : BaseActivity() { @@ -47,10 +51,45 @@ class SamplingListActivity : BaseActivity() { initViewModel() initRecyclerView() addViewListener() + initObserver() requestData(true) onBackPressedDispatcher.addCallback(this) { } } + /** + * 收集 cookFoodListState,将本地烹饪中数据渲染到列表 + */ + private fun initObserver() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + appViewModel.cookFoodListState.collect { cookFoodEntities -> + delayDismissLoading() + if (cookFoodEntities.isNullOrEmpty()) { + loadEmptyView() + return@collect + } + val tempList = mutableListOf() + cookFoodEntities.sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) } + .forEach { entity -> + tempList.add(FoodRecord().apply { + foodId = entity.foodId + foodName = entity.foodName + cookMode = 1 + isCooking = true + }) + } + list.clear() + list.addAll(tempList) + dishAdapter.notifyDataSetChanged() + binding.refreshLayout.run { + setEnableRefresh(false) + setEnableLoadMore(false) + } + } + } + } + } + private fun setTitleBar() { setTitleBar(titleBarAction = { @@ -78,8 +117,8 @@ class SamplingListActivity : BaseActivity() { appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java] } - fun getCookFoodList(action: (MutableList?) -> Unit) { - appViewModel.getCookFoodList(cookMode = 1) { action(it) } + fun getCookFoodList() { + appViewModel.getCookFoodList(cookMode = 1) } fun deleteCookFoodAndGoods(foodId: String, action: () -> Unit) { @@ -298,32 +337,7 @@ class SamplingListActivity : BaseActivity() { @SuppressLint("NotifyDataSetChanged") fun refreshLocalData() { showLoading() - //查询本地数据 - getCookFoodList { cookFoodEntities -> - delayDismissLoading() - if (cookFoodEntities.isNullOrEmpty()) { - loadEmptyView() - return@getCookFoodList - } - val tempList = mutableListOf() - - cookFoodEntities.sortedByDescending { DateTimeUtil.convert(dateStr = it.createTime) } - .forEach { entity -> - tempList.add(FoodRecord().apply { - foodId = entity.foodId - foodName = entity.foodName - cookMode = 1 - isCooking = true - }) - } - list.clear() - list.addAll(tempList) - dishAdapter.notifyDataSetChanged() - binding.refreshLayout.run { - setEnableRefresh(false) - setEnableLoadMore(false) - } - } + getCookFoodList() } private fun requestData(isCooking: Boolean) { diff --git a/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt b/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt index bb986e8..ce8ea8a 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/SelectDishActivity.kt @@ -10,8 +10,6 @@ import com.shuwei.dish.match.base.BaseApp import com.shuwei.dish.match.databinding.ActivitySelectDishBinding import com.shuwei.dish.match.db.AppRepository import com.shuwei.dish.match.dialog.CommonDialog -import com.shuwei.dish.match.entity.CookFoodEntity -import com.shuwei.dish.match.entity.FoodRecord import com.shuwei.dish.match.ui.fragment.DishListFragment import com.shuwei.dish.match.utils.KeyboardUtil import com.shuwei.dish.match.utils.ext.addOnActionSearchListener @@ -32,7 +30,8 @@ class SelectDishActivity : BaseActivity() { private lateinit var binding: ActivitySelectDishBinding - private lateinit var appViewModel: AppViewModel + lateinit var appViewModel: AppViewModel + private set private var dinnerType: String = "1" @@ -72,8 +71,8 @@ class SelectDishActivity : BaseActivity() { appViewModel = ViewModelProvider(this, factory)[AppViewModel::class.java] } - fun getCookFoodList(action: (MutableList?) -> Unit) { - appViewModel.getCookFoodList(cookMode = 0, dinnerType = dinnerType) { action(it) } + fun getCookFoodList() { + appViewModel.getCookFoodList(cookMode = 0, dinnerType = dinnerType) } private var configFinished = false @@ -189,16 +188,8 @@ class SelectDishActivity : BaseActivity() { isVisible = false } - public fun getFoodList( - param: MutableMap, - onSuccess: (MutableList?) -> Unit, - onFailure: (String, String) -> Unit - ) { - netViewModel.searchFoodList( - param = param, - onSuccess = onSuccess, - onFailure = onFailure - ) + public fun getFoodList(param: MutableMap) { + netViewModel.searchFoodList(param = param) } } \ No newline at end of file diff --git a/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt b/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt index 8b28231..0e4bfaf 100644 --- a/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt +++ b/app/src/main/java/com/shuwei/dish/match/ui/fragment/DishListFragment.kt @@ -5,6 +5,9 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager import com.chad.library.adapter4.util.setOnDebouncedItemClick @@ -13,7 +16,9 @@ import com.shuwei.dish.match.base.BaseApp import com.shuwei.dish.match.base.BaseFragment import com.shuwei.dish.match.databinding.FragmentDishListBinding import com.shuwei.dish.match.databinding.LayoutEmptyViewBinding +import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.FoodRecord +import com.shuwei.dish.match.net.UiState import com.shuwei.dish.match.ui.PrepareCookActivity import com.shuwei.dish.match.ui.SelectDishActivity import com.shuwei.dish.match.ui.SubmitFoodActivity @@ -21,6 +26,8 @@ import com.shuwei.dish.match.utils.SwipeCallback import com.shuwei.dish.match.utils.ext.startActivity import com.shuwei.dish.match.utils.ext.toast import java.io.Serializable +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.launch class DishListFragment : BaseFragment() { @@ -108,6 +115,7 @@ class DishListFragment : BaseFragment() { itemTouchHelper.attachToRecyclerView(this) } addViewListener() + initObserver() pageNo = 1 activity.showLoading() @@ -115,6 +123,39 @@ class DishListFragment : BaseFragment() { binding.refreshLayout.setEnableRefresh(true) } + /** + * 用 combine 同时监听网络结果与本地数据,网络成功时统一合并渲染 + * pageNo > 1(加载更多)时 cookFoodListState 不参与合并,直接追加网络数据 + */ + private fun initObserver() { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + combine( + activity.netViewModel.searchFoodState, + activity.appViewModel.cookFoodListState + ) { networkState, localList -> Pair(networkState, localList) } + .collect { (networkState, localList) -> + when (networkState) { + is UiState.Loading -> activity.showLoading() + is UiState.Success -> { + activity.delayDismissLoading() + finishRefresh() + loadAndMergeDishList(networkState.data, localList) + } + is UiState.Error -> { + if (isAdded.not()) return@collect + toast(networkState.msg) + finishRefresh() + if (pageNo == 1) loadEmptyView() + activity.delayDismissLoading() + } + is UiState.Idle -> {} + } + } + } + } + } + private fun addViewListener() { binding.refreshLayout.run { setEnableRefresh(true) @@ -147,72 +188,15 @@ class DishListFragment : BaseFragment() { @SuppressLint("NotifyDataSetChanged") @Suppress("unchecked_cast") fun getDishList() { - activity.showLoading() - activity.getFoodList( - param = mutableMapOf( - "pageNum" to pageNo, - "pageSize" to pageSize, - "placeId" to BaseApp.canteenId, - "dinnerType" to getDinnerTypeText() - ), - onSuccess = { records -> - activity.delayDismissLoading() - finishRefresh() - loadDishList(records) - }, - onFailure = { code, msg -> - if (isAdded.not()) { - return@getFoodList - } - toast(msg) - finishRefresh() - if (pageNo == 1) { - loadEmptyView() - } - activity.delayDismissLoading() - } + val param = mutableMapOf( + "pageNum" to pageNo, + "pageSize" to pageSize, + "placeId" to BaseApp.canteenId, + "dinnerType" to getDinnerTypeText() ) -// val map = mapOf( -//// "foodName" to input, -// "dinnerType" to getDinnerTypeText(), -// "pageNo" to "$pageNo", -// "pageSize" to "$pageSize", -// "canteenId" to BaseApp.canteenId -// ) -// val sb = StringBuilder(UrlConfig.QUERY_FOOD_LIST).apply { -// append("?") -// map.forEach { (key, value) -> append("$key=$value&") } -// } -// sb.deleteCharAt(sb.length - 1) -// HttpUtil.get( -// url = sb.toString(), -// doSuccess = { data -> -// binding.refreshLayout.run { -// setEnableRefresh(true) -// } -// activity.delayDismissLoading() -// finishRefresh() -// val json = data.toJsonString() -// val recordBean: FoodRecordBean? = json.toObject() -// loadDishList(recordBean) -// }, doFailure = { code, msg -> -// try { -// if (isAdded.not()) { -// return@get -// } -// binding.refreshLayout.run { -// setEnableRefresh(true) -// } -// toast(msg) -// finishRefresh() -// if (pageNo == 1) { -// loadEmptyView() -// } -// activity.delayDismissLoading() -// } catch (e: Exception) { -// e.printStackTrace() -// } -// }) + // 网络与本地并行触发,pageNo > 1 时不重复查询本地数据 + activity.getFoodList(param = param) + if (pageNo == 1) activity.getCookFoodList() } private var emptyViewBinding: LayoutEmptyViewBinding? = null @@ -248,64 +232,65 @@ class DishListFragment : BaseFragment() { } } + /** + * 将网络数据与本地烹饪中数据合并后渲染列表 + * pageNo > 1 时忽略本地数据,直接追加网络数据,避免 combine 带入旧的本地状态 + */ @SuppressLint("NotifyDataSetChanged") - private fun refreshLocalData(list: MutableList) { - activity.getCookFoodList { cookFoodEntities -> - if (cookFoodEntities.isNullOrEmpty()) { - return@getCookFoodList - } - val tempList = mutableListOf() - - cookFoodEntities.forEachIndexed { index, entity -> - val food = list.firstOrNull { it.foodId == entity.foodId } - if (food != null) { - food.isCooking = true - food.sort = index - food.dinnerType = entity.dinnerType ?: "0" - tempList.add(food) - } else { - //当前查询到的list不包括本地数据id,可能数据在很多页以后了,暂时只能直接构造数据 - tempList.add( - FoodRecord( - foodId = entity.foodId, - foodName = entity.foodName, - sort = index, - dinnerType = entity.dinnerType ?: "0", - isCooking = true - ) - ) - } - } - list.removeAll(tempList) - list.addAll(0, tempList) - dishAdapter.notifyDataSetChanged() - } - } - - @SuppressLint("NotifyDataSetChanged") - private fun loadDishList(records: MutableList?) { + private fun loadAndMergeDishList( + records: MutableList?, + localList: MutableList? + ) { try { - if (isAdded.not()) { + if (isAdded.not()) return + // pageNo > 1 时不参与本地合并,避免 combine 带入旧的本地状态 + val effectiveLocalList = if (pageNo == 1) localList else null + if (records.isNullOrEmpty() && effectiveLocalList.isNullOrEmpty()) { + if (pageNo == 1) loadEmptyView() return } - if (records.isNullOrEmpty()) { - //toast("暂未搜索到相关菜品信息") - if (pageNo == 1) { - loadEmptyView() + if (pageNo == 1) list.clear() + + val mergedList = records?.toMutableList() ?: mutableListOf() + + // 仅 pageNo == 1 时才有本地数据参与合并 + if (!effectiveLocalList.isNullOrEmpty()) { + val cookingItems = mutableListOf() + effectiveLocalList.forEachIndexed { index, entity -> + val food = mergedList.firstOrNull { it.foodId == entity.foodId } + if (food != null) { + mergedList.remove(food) + food.isCooking = true + food.sort = index + food.dinnerType = entity.dinnerType ?: "0" + cookingItems.add(food) + } else { + // 当前网络数据不包含该本地记录,直接构造 + cookingItems.add( + FoodRecord( + foodId = entity.foodId, + foodName = entity.foodName, + sort = index, + dinnerType = entity.dinnerType ?: "0", + isCooking = true + ) + ) + } } - return + mergedList.addAll(0, cookingItems) } - if (pageNo == 1) { - list.clear() + + if (pageNo >= 2 && !localList.isNullOrEmpty()) { + //第2页起,从mergedList中移除localList中的同foodId数据 + val localIds = localList.map { it.foodId }.toHashSet() + mergedList.removeAll { it.foodId in localIds } } - list.addAll(records) + + list.addAll(mergedList) dishAdapter.notifyDataSetChanged() - val isLoadMoreEnable = records.size >= pageSize + val isLoadMoreEnable = (records?.size ?: 0) >= pageSize binding.refreshLayout.setEnableLoadMore(isLoadMoreEnable) - if (isLoadMoreEnable) { - pageNo++ - } - refreshLocalData(list) + if (isLoadMoreEnable) pageNo++ } catch (e: Exception) { e.printStackTrace() } diff --git a/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt b/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt index 2e8912d..30368b5 100644 --- a/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt +++ b/app/src/main/java/com/shuwei/dish/match/viewmodel/AppViewModel.kt @@ -6,6 +6,9 @@ import com.shuwei.dish.match.db.AppRepository import com.shuwei.dish.match.entity.CookFoodEntity import com.shuwei.dish.match.entity.CookFoodGoodsEntity import com.shuwei.dish.match.entity.SeasoningEntity +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock @@ -26,14 +29,15 @@ class AppViewModel(private val rep: AppRepository) : ViewModel() { } } + private val _cookFoodListState = MutableStateFlow?>(null) + val cookFoodListState: StateFlow?> = _cookFoodListState.asStateFlow() + fun getCookFoodList( cookMode: Int, - dinnerType: String = "0", - action: (MutableList?) -> Unit + dinnerType: String = "0" ) { viewModelScope.launch { - val data = rep.getCookFoodList(cookMode, dinnerType) - action(data) + _cookFoodListState.value = rep.getCookFoodList(cookMode, dinnerType) } }