【问题标题】:When I add a new element in Arraylist its replace all the current element?当我在 Arraylist 中添加一个新元素时,它会替换所有当前元素吗?
【发布时间】:2021-02-27 07:47:36
【问题描述】:

我有一个问题,当我向arraylist 添加一个作为数据类的新元素时,它总是用新元素替换当前元素。你能告诉我什么是问题,什么是解决方案。提前致谢

型号

import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.android.parcel.Parcelize

@Parcelize
data class ScheduleModel(

    @field:SerializedName("user_available_id")
    var userAvailableId: String? = null,

    @field:SerializedName("teacher_id")
    var teacherId: String? = null,

    @field:SerializedName("schedule")
    var schedule: ArrayList<schedule?>? = null


) : Parcelable

@Parcelize
data class schedule(

    @field:SerializedName("event_id")
    var eventId: String? = null,

    @field:SerializedName("schedule_time")
    var scheduleTime: String? = null,

    @field:SerializedName("status")
    var status: String? = null
) : Parcelable

我正在使用 recyclerview 将元素添加到 arraylist。元素是数据类模型。这是首先我从 API 获取数据然后使用 recyclerview 显示数据的流程。然后在显示后我想获取显示数据并将其保存到数组列表中。将数据保存到arraylist后,arraylist会像这样将数据发送到api:

{
    "user_available_id": 702,
    "teacher_id" : 3207,
    "schedule" : [{
                "event_id" : 47533,
                "schedule_time" : "2020-11-30 07:00:00",
                "status" :1
             },
             {
                "event_id" : 47532,
                "schedule_time" : "2020-11-30 06:30:00",
                "status" :1
             }]
}

当我将新数据添加到 arraylist 时,我一直在努力处理保存到 arraylist 的数据。

函数

  private suspend fun getMultiSlotJadwal(id: String, date: String) {
        jamList.clear()
        val networkConfig =
            NetworkConfig().getTeacher().getTeacherScheduleAvailability(token, id, date)

        if (networkConfig.isSuccessful) {

            if (networkConfig.body()!!.availability!!.isEmpty()) {

                binding.rvSlot.visibility = View.GONE
                Handler(Looper.getMainLooper()).post {
                    Toast.makeText(
                        this,
                        "Jam tidak tersedia",
                        Toast.LENGTH_SHORT
                    ).show()
                }
            } else {
                for (slot in networkConfig.body()!!.availability!!) {

                    //convert tanggal start ke millis
                    val tanggalSlot = slot!!.start!!.toDate().formatTo("yyyy-MM-dd HH:mm")
                    val tanggalInMillis = convertToMillis(tanggalSlot)

                    //ambil tanggal sekarang
                    val myFormat = "yyyy-MM-dd HH:mm" // format tanggal
                    val calendar = Calendar.getInstance()
                    val time = calendar.time
                    val sdf = SimpleDateFormat(myFormat, Locale.getDefault())
                    val curdate = sdf.format(time) //diconvert ke tanggal local
                    val curDateinMillis = convertToMillis(curdate) // convert ke millis

                    val hasilDate = tanggalInMillis - curDateinMillis
                    val tanggalJam = hasilDate / 3600000 //diubah dari millis ke jam

                    if (tanggalJam >= 6) {
                        jamList.add(slot)
                        val sortJamList = jamList.sortedBy { jamList -> jamList.start }
                       
                        binding.rvSlot.visibility = View.VISIBLE

                        val adapter = SlotJamMultiAdapter(sortJamList) {

                            teacher_id = it.teacherId.toString()

                            scheduleModel.userAvailableId = user_avalaible_id //model
                            scheduleModel.teacherId = teacher_id

                            scheduleItem.scheduleTime = it.start.toString()
                            scheduleItem.status = "1"
                            scheduleItem.eventId = it.id.toString()

                            scheduleList.add(scheduleItem) // array list

                            scheduleModel.schedule = scheduleList
                            Log.d(TAG, "getMultiSlotJadwal: $scheduleList")
                            itemClicked = true

                            changeBackgroundButtonSesi2()
                        }
                        adapter.submitList(sortJamList)
                        binding.rvSlot.adapter = adapter


                    }

                }
            }

        } else {

            Handler(Looper.getMainLooper()).post {
                Toast.makeText(
                    this,
                    "Jam tidak tersedia",
                    Toast.LENGTH_SHORT
                ).show()
            }
        }
    }

编辑 这是我使用 diffutils 后的适配器 适配器


class SlotJamMultiAdapter(
    private var data: List<AvailabilitySlotItem>,
    private val listener: (AvailabilitySlotItem) -> Unit
) : RecyclerView.Adapter<SlotJamMultiAdapter.LeagueViewHolder>() {
    private lateinit var ContextAdapter: Context

    class LeagueViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val tvJam = view.findViewById<TextView>(R.id.tv_slot_jam_list)
        val cvSlot = view.findViewById<CardView>(R.id.cv_slot_list)
        val llSlot = view.findViewById<LinearLayout>(R.id.ll_cv_slot)

        fun bidnItem(
            data: AvailabilitySlotItem,
            listener: (AvailabilitySlotItem) -> Unit,
            context: Context,
            position: Int
        ) {
            val jam = data.start!!.toDate().formatTo("HH:mm")
            tvJam.text = jam

            itemView.setOnClickListener {
                listener(data)

            }
        }

        private fun String.toDate(
            dateFormat: String = "yyyy-MM-dd HH:mm:ss",
            timeZone: TimeZone = TimeZone.getTimeZone("UTC")
        ): Date {
            val parser = SimpleDateFormat(dateFormat, Locale.getDefault())
            parser.timeZone = timeZone
            return parser.parse(this)
        }

        private fun Date.formatTo(
            dateFormat: String,
            timeZone: TimeZone = TimeZone.getDefault()
        ): String {
            val formatter = SimpleDateFormat(dateFormat, Locale.getDefault())
            formatter.timeZone = timeZone
            return formatter.format(this)
        }

    }

    class slotItemDiffCallback(
        var oldSlotList: List<AvailabilitySlotItem>,
        var newSlotList: List<AvailabilitySlotItem>
    ) : DiffUtil.Callback() {
        override fun getOldListSize(): Int {
            return oldSlotList.size
        }

        override fun getNewListSize(): Int {
            return newSlotList.size
        }

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return (oldSlotList.get(oldItemPosition).id == newSlotList.get(newItemPosition).id)
        }

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
            return oldSlotList.get(oldItemPosition).equals(newSlotList.get(newItemPosition))
        }

    }


    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): SlotJamMultiAdapter.LeagueViewHolder {
        val layoutInflater = LayoutInflater.from(parent.context)
        ContextAdapter = parent.context
        val inflatedView: View = layoutInflater.inflate(R.layout.slot_list, parent, false)
        return SlotJamMultiAdapter.LeagueViewHolder(inflatedView)
    }

    override fun onBindViewHolder(holder: SlotJamMultiAdapter.LeagueViewHolder, position: Int) {
        holder.bidnItem(data[position], listener, ContextAdapter, position)

    }

    override fun getItemCount(): Int = data.size

    fun submitList(availabilitySlotItemList: List<AvailabilitySlotItem>) {
        val oldList = data
        val diffResult:DiffUtil.DiffResult=DiffUtil.calculateDiff(
            slotItemDiffCallback(
                oldList,availabilitySlotItemList
            )
        )
        data = availabilitySlotItemList
        diffResult.dispatchUpdatesTo(this)
    }

}

【问题讨论】:

    标签: android kotlin arraylist


    【解决方案1】:

    因为每次使用 getMultiSlotJadwal() 获取列表时,都会创建一个新的适配器实例并将其分配给 recyclerview。

     binding.rvSlot.adapter = SlotJamMultiAdapter(sortJamList) { }
    

    继续引用分配的适配器,然后当您从服务器获取新列表时,将列表提供给您之前引用的适配器。

    您可以搜索 ListAdatper / DiffUtil.Callback,它们会代表您检查新列表中的项目是否与旧列表中的相同项目。您所要做的就是将新列表提交到ListAdapter,如下所示

     val newList = getNewListFromServer()
     myAdapter.submitList(list)
    

    更新

    好的,对于 ScheduleModel

    class ScheduleModel(
        val userAvailableId : String?,
        val teacherId : String?,
        val schedule : List<String>?
    ) {
    
        class ScheduleDiffUtilCallback : DiffUtil.ItemCallback<ScheduleModel>(){
            override fun areItemsTheSame(oldItem: ScheduleModel, newItem: ScheduleModel): Boolean {
                return true
                // set the way how to identify if the newItem is the same as the oldItem
            }
    
            override fun areContentsTheSame(oldItem: ScheduleModel, newItem: ScheduleModel): Boolean {
                return true
                // set the way how to identify if the newItem's contents is the same as the oldItem's contents
            }
        }
    }
    
    

    适配器

    class SlotJamMultiAdapter : ListAdapter<ScheduleModel, SlotJamMultiAdapter.ViewHolder>(
        ScheduleModel.ScheduleDiffUtilCallback()
    ){
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
            return ViewHolder(
                LayoutInflater.from(parent.context)
                    .inflate(R.layout.item_schedule, parent, false)
            )
        }
    
        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val item = getItem(position)
            holder.bind(item)
        }
    
        class ViewHolder(root : View) : RecyclerView.ViewHolder(root) {
            fun bind(item : ScheduleModel) {
                //bind data to view here
            }
        }
    }
    

    您实际上并未在适配器类中自己引用数据的节点列表。 ListAdapter 会引用它并执行更新数据所需的所有操作。

    你所要做的就是,在片段或活动中

       val adapter = SlotJamMultiAdapter()
       rc.adapter = adapter
    

    当你的数据发生变化时(如果你得到新列表)

       adapter.submitList(newList)
    

    请注意,我没有创建新的 Adapter 实例,我引用的是附加到 recyclerview 的旧适配器,并且我正在重用它

    【讨论】:

    • 对不起,我不太明白,我的情况是如果我单击该项目然后添加到 arraylist。不是当我点击服务器然后添加到arraylist时。如果您的答案与我的情况相同,那么我应该将 DiffUtil 添加到我的适配器吗?
    • 所以你正在向绑定到 recyclerview 的列表中添加一个数据,对吗?然后,在您的情况下, DiffUtil.Callback 将解决您的问题。
    • notifyDataSetChanged 也可以,但这样做有点负担。
    • 你好,SGTCheung,还是一样,你能看看我更新我的问题吗
    猜你喜欢
    • 2011-08-02
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2014-06-02
    • 2021-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多