You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Retrofit删除Item后如何更新RecyclerView?notifyDataSetChanged()无效问题解决

Retrofit删除Item后RecyclerView无法更新的问题解决

我最近在用Retrofit完成Item删除操作后,碰到了RecyclerView无法刷新的问题——明明调用了notifyDataSetChanged(),列表却完全没反应。折腾了一阵后终于找到了解决方案,下面把整个过程分享出来:

原代码实现

API接口与Repository

interface RetrofitService {
    @GET("/")
    suspend fun getAllItem() : Response<List<Item>>
    @POST("/delete")
    suspend fun deleteItem(@Body item :Item) : Response<Item>
}

class ItemRepository(private val retrofitService: RetrofitService) {
    suspend fun getAllItem() = retrofitService.getAllItem()
    suspend fun deleteItem(item : Item) = retrofitService.deleteItem(item)
}

ViewModel逻辑

class ItemViewModel(private val itemRepository: ItemRepository) : ViewModel() {
    val itemResponse: MutableLiveData<Resource<Item>> = MutableLiveData()
    val listItemResponse : MutableLiveData<Resource<List<Item>>> = MutableLiveData()

    fun getItemResponse() = viewModelScope.launch {
        val response : Response<List<Item>> = itemRepository.getAllItem()
        withContext(Dispatchers.Main) {
            listItemResponse.postValue(handleListItemResponse(response))
        }
    }

    fun deleteItem(item: Item) = viewModelScope.launch {
        val response = itemRepository.deleteItem(item)
        itemResponse.postValue(handleItemResponse(response))
    }

    private fun handleItemResponse(response: Response<Item>): Resource<Item> {
        if (response.isSuccessful) {
            response.body()?.let { resultResponse ->
                return Resource.Success(resultResponse)
            }
        }
        return Resource.Error(response.message())
    }

    private fun handleListItemResponse(response: Response<List<Item>>): Resource<List<Item>> {
        if (response.isSuccessful) {
            response.body()?.let { resultResponse ->
                return Resource.Success(resultResponse)
            }
        }
        return Resource.Error(response.message())
    }
}

sealed class Resource<T>(
    val data:T?=null,
    val messaage : String? = null
) {
    class Success<T>(data:T) : Resource<T>(data)
    class Error<T>(messaage: String,data:T? = null) : Resource<T>(data,messaage)
    class Loading<T> : Resource<T>()
}

Fragment中ViewModel的使用

viewModel.listItemResponse.observe(viewLifecycleOwner, Observer {
    when (it) {
        is Resource.Success -> {
            Toast.makeText(context,"All Success",Toast.LENGTH_SHORT).show()
            it.data?.let { itemReponse ->
                listItem = itemReponse
                adapter.setNotes(listItem)
            }
        }
        is Resource.Error -> {
            it.messaage?.let { msg ->
                Log.e("AAA","ERR:$msg ")
            }
        }
    }
})
viewModel.getItemResponse()

Adapter中的删除逻辑

fun setNotes(items:List<Item>){
    this.items = items
    notifyDataSetChanged()
}

private val onItemDelete:(Item)->Unit ={ item ->
    viewModel.itemResponse.observe(viewLifecycleOwner, Observer {
        when (it) {
            is Resource.Success -> {
                it.data?.let {
                    Toast.makeText(context,"Delete successfully!",Toast.LENGTH_SHORT).show()
                }
            }
            is Resource.Error -> {
                it.messaage?.let { msg ->
                    Toast.makeText(context," \"ERR:$msg \"",Toast.LENGTH_SHORT).show()
                }
            }
        }
    })
    viewModel.deleteItem(item)
}

问题分析与解决方案

原来的问题在于:删除操作完成后,我们只在Adapter里处理了Toast提示,但没有更新本地数据源,也没有正确通知RecyclerView刷新。哪怕调用了notifyDataSetChanged(),如果本地的列表数据没变化,RecyclerView也不会有反应。

解决方法是让Adapter回调Item的位置到Fragment,在Fragment中更新本地数据源并调用精准的刷新方法:

修改后的删除逻辑

Adapter中调整回调参数

把原来的(Item)->Unit改成(Int)->Unit,传递Item的位置:

// Adapter里的回调定义(假设你有外部传递的接口)
private val onItemDelete:(Int)->Unit ={ pos ->
    onDeleteClick(pos) // 调用外部传入的回调,把位置传出去
}

Fragment中处理删除逻辑

// 在Fragment中设置Adapter的删除回调
private val onItemDelete:(Int)->Unit ={ pos ->
    viewModel.itemResponse.observe(viewLifecycleOwner, Observer {
        when (it) {
            is Resource.Success -> {
                it.data?.let {
                    Toast.makeText(context,"Delete successfully!",Toast.LENGTH_SHORT).show()
                    // 1. 更新本地数据源
                    listItem.removeAt(pos)
                    // 2. 通知RecyclerView移除对应位置的Item
                    adapter.notifyItemRemoved(pos)
                    // 可选:如果需要处理后续Item的位置更新,可以加上这行
                    // adapter.notifyItemRangeChanged(pos, listItem.size)
                }
            }
            is Resource.Error -> {
                it.messaage?.let { msg ->
                    Toast.makeText(context," \"ERR:$msg \"",Toast.LENGTH_SHORT).show()
                }
            }
        }
    })
    // 调用ViewModel的删除接口,传入对应位置的Item
    viewModel.deleteItem(listItem[pos])
}

这样做的好处是:

  1. 确保本地数据源和后端数据同步
  2. 使用notifyItemRemoved(pos)比notifyDataSetChanged()更高效,只刷新需要变化的位置
  3. 逻辑集中在Fragment中,Adapter只负责UI展示和事件传递

内容的提问来源于stack exchange,提问作者Lộc Trần Phước

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:34:09