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

Android Kotlin:通过RecyclerView适配器添加并显示新列表项

问题分析与修正方案

我看了你的代码,发现几个核心问题导致添加的数据无法正确显示在RecyclerView中,下面逐一说明并给出修正后的代码:


1. Fragment中的数据与RecyclerView初始化问题

你当前在onActivityResult里每次都新建ArrayList<ItemsItem>(),这会导致之前添加的数据全部丢失,而且RecyclerView的初始化(设置布局管理器、适配器)也不应该每次返回都重复执行。应该把数据列表作为Fragment的成员变量,在onViewCreated里完成RecyclerView的基础配置。

修正后的Fragment代码:

class StepThreeShipmentFragment : Fragment() {
    private val REQUEST_CODE = 2
    internal lateinit var adapter: ShipmentItemAdapter
    // 把items作为成员变量,持久保存所有数据
    private val items = ArrayList<ItemsItem>()

    override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return inflater!!.inflate(R.layout.fragment_step_three_shipment, container, false)
    }

    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        // 初始化RecyclerView的基础配置,只执行一次
        itemsShipments.layoutManager = LinearLayoutManager(context)
        itemsShipments.setHasFixedSize(true)
        adapter = ShipmentItemAdapter(context, items)
        itemsShipments.adapter = adapter
        // 初始状态根据数据量显示/隐藏RecyclerView
        itemsShipments.visibility = if (items.isEmpty()) View.GONE else View.VISIBLE

        btnAddNewShipmentStep3.setOnClickListener {
            val intent = Intent(context, AddItemActivity::class.java)
            startActivityForResult(intent, REQUEST_CODE)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CODE) {
            if (resultCode == Activity.RESULT_OK) {
                // 从Intent中获取返回的新数据
                val newItem = data?.getParcelableExtra<ItemsItem>("NEW_ITEM")
                newItem?.let {
                    items.add(it)
                    // 通知适配器插入了新数据,避免刷新整个列表
                    adapter.notifyItemInserted(items.size - 1)
                    itemsShipments.visibility = View.VISIBLE
                }
            } else if (resultCode == Activity.RESULT_CANCELED) {
                // 只有列表为空时才隐藏RecyclerView
                if (items.isEmpty()) {
                    itemsShipments.visibility = View.GONE
                }
            }
        }
    }
}

2. AddItemActivity的数据传递问题

你当前把新创建的ItemsItem直接加到了全局变量CreateNewShipmentActivity.mainShipment.shipmentObj.items里,但Fragment并没有监听这个变量的变化,也没有通过Intent把数据返回给Fragment。我们需要让ItemsItem实现Parcelable接口,这样才能在Intent中传递数据,同时拆分数据收集逻辑让代码更清晰。

第一步:让ItemsItem实现Parcelable

// 假设你的ItemsItem类结构如下,添加Parcelable实现以支持Intent传递
data class ItemsItem(
    var numberOfPackages: Int = 0,
    var numberOfPieces: String = "",
    var weightUnit: Int = 0,
    var height: String = "",
    var width: String = "",
    var length: String = "",
    var description: String = ""
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readInt(),
        parcel.readString() ?: "",
        parcel.readInt(),
        parcel.readString() ?: "",
        parcel.readString() ?: "",
        parcel.readString() ?: "",
        parcel.readString() ?: ""
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeInt(numberOfPackages)
        parcel.writeString(numberOfPieces)
        parcel.writeInt(weightUnit)
        parcel.writeString(height)
        parcel.writeString(width)
        parcel.writeString(length)
        parcel.writeString(description)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<ItemsItem> {
        override fun createFromParcel(parcel: Parcel): ItemsItem {
            return ItemsItem(parcel)
        }

        override fun newArray(size: Int): Array<ItemsItem?> {
            return arrayOfNulls(size)
        }
    }
}

修正后的AddItemActivity代码:

class AddItemActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_item_form)

        // 保留点击输入框获取焦点的逻辑
        linPackageAddShipment.setOnClickListener {
            edtPackageAddShipment.requestFocus()
        }
        linPiecesAddShipment.setOnClickListener {
            edtPiecesAddShipment.requestFocus()
        }
        linWeightAddShipment.setOnClickListener {
            edtWeightAddShipment.requestFocus()
        }
        linDescriptionAddShipment.setOnClickListener {
            edtDescriptionAddShipment.requestFocus()
        }

        btnAddItemAddShipment.setOnClickListener {
            val errors = collectValidationErrors()
            if (errors.isEmpty()) {
                val newItem = collectItemData()
                // 把新数据通过Intent返回给Fragment
                val intent = Intent().apply {
                    putExtra("NEW_ITEM", newItem)
                }
                setResult(Activity.RESULT_OK, intent)
                // 如果需要同步更新全局变量,保留这行
                CreateNewShipmentActivity.mainShipment.shipmentObj.items?.add(newItem)
                finish()
            } else {
                val errorBody = errors.map { getString(it) }.joinToString("\n")
                MaterialDialog.Builder(this)
                    .title("Oops")
                    .content(errorBody)
                    .positiveText(R.string.ok)
                    .positiveColor(ContextCompat.getColor(this, R.color.colorPrimary))
                    .onAny { dialog, _ -> dialog.dismiss() }
                    .show()
            }
        }
    }

    // 单独提取验证逻辑,只返回错误信息
    private fun collectValidationErrors(): ArrayList<Int> {
        val errors = ArrayList<Int>()
        if (edtPackageAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.packages_must_not_be_empty)
        }
        if (edtPiecesAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.pieces_must_not_be_empty)
        }
        if (edtWeightAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.weight_must_not_be_empty)
        }
        if (edtHeightAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.height_must_not_be_empty)
        }
        if (edtWidthAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.width_must_not_be_empty)
        }
        if (edtLengthAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.length_must_not_be_empty)
        }
        if (edtDescriptionAddShipment.text.toString().isEmpty()) {
            errors.add(R.string.description_must_not_be_empty)
        }
        return errors
    }

    // 单独提取数据收集逻辑,返回构建好的ItemsItem
    private fun collectItemData(): ItemsItem {
        val item = ItemsItem()
        item.numberOfPackages = edtPackageAddShipment.text.toString().toInt()
        item.numberOfPieces = edtPiecesAddShipment.text.toString()
        item.weightUnit = edtWeightAddShipment.text.toString().toInt()
        item.height = edtHeightAddShipment.text.toString()
        item.width = edtWidthAddShipment.text.toString()
        item.length = edtLengthAddShipment.text.toString()
        item.description = edtDescriptionAddShipment.text.toString()
        return item
    }

    override fun onBackPressed() {
        setResult(Activity.RESULT_CANCELED)
        super.onBackPressed()
    }
}

3. ShipmentItemAdapter的绑定错误与点击逻辑问题

你当前的适配器存在字段绑定错误(比如使用不存在的desc字段、错误用description显示数量),点击跳转逻辑也没有传递当前item数据,这里一起修正:

修正后的适配器代码:

class ShipmentItemAdapter(
    private val context: Context,
    private val items: List<ItemsItem>
) : RecyclerView.Adapter<ShipmentItemAdapter.MyViewHolder>() {

    private val inflater: LayoutInflater = LayoutInflater.from(context)

    // 内部ViewHolder类,统一管理布局中的View
    inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val namePackageShipmentPackage: TextView = itemView.findViewById(R.id.namePackageShipmentPackage)
        val quantityPackageShipmentPackage: TextView = itemView.findViewById(R.id.quantityPackageShipmentPackage)
        val dimensionPackageHeightShipmentPackage: TextView = itemView.findViewById(R.id.dimensionPackageHeightShipmentPackage)
        // 根据你的布局添加其他需要绑定的View,比如宽度、长度等
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = inflater.inflate(R.layout.item_shipment_package, parent, false)
        val holder = MyViewHolder(view)
        
        // 处理item点击事件,可选支持编辑跳转
        holder.itemView.setOnClickListener {
            val position = adapterPosition
            if (position != RecyclerView.NO_POSITION) {
                val item = items[position]
                val intent = Intent(context, AddItemActivity::class.java).apply {
                    putExtra("EDIT_ITEM", item)
                    putExtra("EDIT_POSITION", position)
                }
                (context as AppCompatActivity).startActivityForResult(intent, 3) // 用新的requestCode区分编辑请求
            }
        }
        return holder
    }

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        val item = items[position]
        holder.namePackageShipmentPackage.text = item.description
        // 数量显示numberOfPieces字段
        holder.quantityPackageShipmentPackage.text = item.numberOfPieces
        // 高度显示height字段
        holder.dimensionPackageHeightShipmentPackage.text = item.height
        // 绑定其他字段示例
        // holder.dimensionPackageWidthShipmentPackage.text = item.width
        // holder.dimensionPackageLengthShipmentPackage.text = item.length
    }

    override fun getItemCount(): Int {
        return items.size
    }
}

额外注意点

  • 确保布局文件中的View ID和代码中的调用完全一致
  • 如果需要支持编辑功能,可以在Fragment中新增对应的onActivityResult分支,处理编辑返回的数据并调用adapter.notifyItemChanged(position)更新列表
  • 尽量减少全局变量的使用,推荐用ViewModel或LiveData管理跨页面数据,让代码更健壮、更易维护

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:58:16