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

Android开发:删除全部列表项后界面仍显示1条数据,如何修复?

Android列表删除最后一项后界面未更新问题

我是Android开发新手,目前除一处问题外其他功能均正常。删除列表项操作在技术层面有效,但删除最后一项时,数据已从数据库移除,却仍显示在Activity界面上,仅重启应用后才会消失。我希望无需重启应用,删除最后一项后界面就能正确显示空列表。


相关代码

Repository代码

private val mWebsDao: WebDao
private val executorService: ExecutorService = Executors.newSingleThreadExecutor()

init {
    val db = WebRoomDatabase.getDatabase(application)
    mWebsDao = db.webDao()
}

fun deleteWeb(web: Web) {
    executorService.execute { mWebsDao.deleteWebById(web) }
}

ViewModel代码

private val mWebRepository: WebRepository = WebRepository(application)

fun deleteWeb(web: Web) {
    mWebRepository.deleteWeb(web)
}

Adapter代码

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val (_, webName, webUrl, webImgColor) = listWeb[position]

    holder.binding.imgColorWeb.background = ColorDrawable(android.graphics.Color.rgb(webImgColor.r, webImgColor.g, webImgColor.b))
    holder.binding.tvWebName.text = webName
    holder.binding.tvWebLink.text = webUrl
    holder.binding.tvCharWebName.text = webName

    holder.itemView.setOnClickListener {
        onItemClickCallback.onItemClicked(listWeb[holder.adapterPosition])
    }

    holder.itemView.setOnLongClickListener {
        val popUpMenu = PopupMenu(holder.itemView.context, holder.itemView)
        popUpMenu.inflate(R.menu.menu_popup_item_pressed)

        popUpMenu.setOnMenuItemClickListener { menuItem ->
            when (menuItem.itemId) {
                R.id.action_edit -> {
                    onItemLongClickCallback.onItemLongClickedEdit(listWeb[holder.adapterPosition])
                    true
                }
                R.id.action_delete -> {
                    onItemLongClickCallback.onItemLongClickedDelete(listWeb[holder.adapterPosition])
                    notifyItemRemoved(holder.adapterPosition)
                    true
                }
                else -> false
            }
        }

        popUpMenu.show()
        true
    }
}

override fun getItemCount() = listWeb.size

interface OnItemClickCallback {
    fun onItemClicked(web: Web)
}

interface OnItemLongClickCallback {
    fun onItemLongClickedEdit(web: Web)
    fun onItemLongClickedDelete(web: Web)
}

Activity代码

override fun onItemLongClickedDelete(web: Web) {
    mainViewModel.deleteWeb(web)

    Snackbar.make(binding.root, getString(R.string.deleted_web_message), Snackbar.LENGTH_LONG)
        .setAction(getString(R.string.undo)) {
            mainViewModel.insertWeb(web)
        }
        .show()
}

列表展示代码

mainViewModel.getAllWebs().observe(this) {
    if (it.isNullOrEmpty()) {
        binding.emptyListInfo.alpha = 1f
    } else {
        binding.emptyListInfo.alpha = 0f
        val webs = webList(it)
        val rvWeb = binding.rvListWeb
        rvWeb.layoutManager = LinearLayoutManager(this@MainActivity)
        webAdapter = WebAdapter(webs)
        rvWeb.adapter = webAdapter
    }
}

解决方案

1. 给Adapter添加数据源更新方法

避免每次新建Adapter,改为更新现有Adapter的数据源:

class WebAdapter(private var listWeb: List<Web>) : RecyclerView.Adapter<WebAdapter.ViewHolder>() {
    // ... 保留原有代码

    fun updateData(newList: List<Web>) {
        listWeb = newList
        notifyDataSetChanged()
    }

    // ... 保留原有代码
}

2. 优化LiveData观察逻辑

确保数据为空时也更新Adapter,同时LayoutManager只初始化一次:

mainViewModel.getAllWebs().observe(this) { webs ->
    val isEmpty = webs.isNullOrEmpty()
    binding.emptyListInfo.alpha = if (isEmpty) 1f else 0f

    val rvWeb = binding.rvListWeb
    // 仅首次初始化LayoutManager和Adapter
    if (rvWeb.layoutManager == null) {
        rvWeb.layoutManager = LinearLayoutManager(this@MainActivity)
        webAdapter = WebAdapter(emptyList())
        rvWeb.adapter = webAdapter
    }

    // 转换数据并更新Adapter
    val convertedWebs = if (isEmpty) emptyList() else webList(webs)
    webAdapter.updateData(convertedWebs)
}

3. 移除Adapter中手动的通知更新

因为Room的LiveData会自动监听数据库变化并通知界面,手动调用notifyItemRemoved会造成更新冲突:

// Adapter中删除这行代码
// notifyItemRemoved(holder.adapterPosition)

4. 确认Dao方法返回LiveData

确保Dao的查询方法返回LiveData<List<Web>>,这样数据库变化时才能自动触发界面更新:

@Dao
interface WebDao {
    @Query("SELECT * FROM webs")
    fun getAllWebs(): LiveData<List<Web>>

    @Delete
    fun deleteWebById(web: Web)
}

完成以上修改后,删除最后一项时,数据库数据清空,LiveData会推送空列表,Adapter更新数据源为空,RecyclerView会自动清空并显示预设的空状态界面,无需重启应用。


内容的提问来源于stack exchange,提问作者Ridhwanafzn

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:24:29