Kotlin RecyclerView添加条目异常:新条目覆盖旧条目而非追加
问题分析与解决方案
核心问题
每次添加新收支条目时,旧条目被覆盖的原因是:
MainActivity每次启动都会重新创建空的data列表,之前的记录未被保存- 跳转回
MainActivity时启动了新实例,而非复用原有实例 - 余额直接用新金额替换,未做累加/扣除计算
一、修复MainActivity的数据逻辑与跳转方式
将数据列表改为全局变量,用Activity Result API接收返回数据,维护全局余额变量:
package com.example.financestation import android.content.Intent import android.os.Bundle import android.widget.ImageButton import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView class MainActivity : AppCompatActivity() { // 全局存储所有收支记录 private val data = ArrayList<ItemsViewModel>() private lateinit var adapter: CustomAdapter private var currentBalance = 0.0 // 维护当前余额 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val addBtn = findViewById<ImageButton>(R.id.add_button) val balanceTv = findViewById<TextView>(R.id.current_balance_number) val settingsBtn = findViewById<ImageButton>(R.id.settings_button) val recyclerView = findViewById<RecyclerView>(R.id.recyclerview) // 初始化RecyclerView recyclerView.layoutManager = LinearLayoutManager(this) adapter = CustomAdapter(data) recyclerView.adapter = adapter // 初始化余额显示 updateBalanceDisplay(balanceTv) // 跳转到添加页面 addBtn.setOnClickListener { val intent = Intent(this, AddingSpendings::class.java) startActivityForResult(intent, 1001) } settingsBtn.setOnClickListener { // 补充设置页面跳转逻辑 } } // 接收添加页面返回的数据 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == 1001 && resultCode == RESULT_OK) { val costStr = data?.getStringExtra("COST") ?: return val category = data.getStringExtra("CATEGORY") ?: return val type = data.getStringExtra("TYPE") ?: return val cost = costStr.toDoubleOrNull() ?: return // 更新余额与数据列表 when (type) { "Income" -> { currentBalance += cost this.data.add(ItemsViewModel(R.drawable.add_icon, "$${"%.2f".format(cost)}", category)) } "Outcome" -> { currentBalance -= cost this.data.add(ItemsViewModel(R.drawable.substract_icon, "-$${"%.2f".format(cost)}", category)) } } // 更新UI updateBalanceDisplay(findViewById(R.id.current_balance_number)) adapter.notifyItemInserted(this.data.size - 1) } } // 统一更新余额显示 private fun updateBalanceDisplay(textView: TextView) { textView.text = "$${"%.2f".format(currentBalance)}" } }
二、修改CustomAdapter支持可变列表
将构造参数改为MutableList,确保数据可修改:
package com.example.financestation import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView class CustomAdapter(private val mList: MutableList<ItemsViewModel>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.card_view_design, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = mList[position] holder.imageView.setImageResource(item.image) holder.textView.text = item.cost holder.textView2.text = item.category } override fun getItemCount(): Int { return mList.size } class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val imageView: ImageView = itemView.findViewById(R.id.imageview) val textView: TextView = itemView.findViewById(R.id.textView) val textView2: TextView = itemView.findViewById(R.id.categories) } }
三、修复AddingSpendings的返回逻辑
用setResult返回数据,关闭当前页面而非启动新的MainActivity:
package com.example.financestation import android.content.Intent import android.os.Bundle import android.widget.* import androidx.appcompat.app.AppCompatActivity class AddingSpendings : AppCompatActivity() { private lateinit var costEt: EditText private var selectedCategory = "" private var selectedType = "" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.addingspending) val homeBtn = findViewById<ImageButton>(R.id.home_button) val addItemBtn = findViewById<Button>(R.id.add_item_button) val categorySpinner = findViewById<Spinner>(R.id.categoryspinner) val typeSpinner = findViewById<Spinner>(R.id.typespinner) val categories = resources.getStringArray(R.array.Category) val types = resources.getStringArray(R.array.Income_Outcome) costEt = findViewById(R.id.cost) // 初始化类别Spinner val categoryAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, categories) categorySpinner.adapter = categoryAdapter categorySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { selectedCategory = categories[p2] } override fun onNothingSelected(p0: AdapterView<*>?) { Toast.makeText(this@AddingSpendings, "未选择类别", Toast.LENGTH_SHORT).show() } } // 初始化类型Spinner val typeAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, types) typeSpinner.adapter = typeAdapter typeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { selectedType = types[p2] } override fun onNothingSelected(p0: AdapterView<*>?) { Toast.makeText(this@AddingSpendings, "未选择类型", Toast.LENGTH_SHORT).show() } } // 添加条目按钮逻辑 addItemBtn.setOnClickListener { val costStr = costEt.text.toString().trim() when { costStr.isEmpty() -> Toast.makeText(this, "请输入金额", Toast.LENGTH_SHORT).show() selectedCategory.isEmpty() -> Toast.makeText(this, "请选择类别", Toast.LENGTH_SHORT).show() selectedType.isEmpty() -> Toast.makeText(this, "请选择类型", Toast.LENGTH_SHORT).show() else -> { // 返回数据给MainActivity val resultIntent = Intent().apply { putExtra("COST", costStr) putExtra("CATEGORY", selectedCategory) putExtra("TYPE", selectedType) } setResult(RESULT_OK, resultIntent) finish() } } } // 返回主页按钮逻辑 homeBtn.setOnClickListener { finish() } } }
额外优化建议
- 数据持久化:当前数据仅存于内存,重启App会丢失,可使用
SharedPreferences或Room数据库保存记录 - 输入校验:增加金额非负校验、格式校验
- 状态恢复:在
MainActivity的onSaveInstanceState中保存余额和数据列表,避免横竖屏切换丢失数据
内容的提问来源于stack exchange,提问作者Adam Bołoz
相关产品推荐
相关产品推荐

