Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 从父recyclerview适配器添加数据并从子recyclerview适配器删除数据_Android_Kotlin_Android Recyclerview - Fatal编程技术网

Android 从父recyclerview适配器添加数据并从子recyclerview适配器删除数据

Android 从父recyclerview适配器添加数据并从子recyclerview适配器删除数据,android,kotlin,android-recyclerview,Android,Kotlin,Android Recyclerview,我有一个嵌套的回收视图。父recyclerview适配器可以通过按钮将数据添加到子级,然后子recyclerview适配器可以通过按钮删除子级中的数据。预览如下图所示 添加数据似乎很好,但当删除数据时,我得到了超出范围的索引。我在添加或删除函数中调用了notifyDataSetChanged() 我的父适配器代码: class FormPlanParentAdapter : RecyclerView.Adapter<FormPlanParentAdapter.ViewHolder

我有一个嵌套的回收视图。父recyclerview适配器可以通过按钮将数据添加到子级,然后子recyclerview适配器可以通过按钮删除子级中的数据。预览如下图所示

添加数据似乎很好,但当删除数据时,我得到了超出范围的索引。我在添加或删除函数中调用了
notifyDataSetChanged()

我的父适配器代码:

class FormPlanParentAdapter :
    RecyclerView.Adapter<FormPlanParentAdapter.ViewHolder>() {

    private val data: MutableList<MutableList<ItemPlan>> = mutableListOf()

    private val viewPool = RecyclerView.RecycledViewPool()

    fun setData(newData: List<MutableList<ItemPlan>>) {
        data.clear()
        data.addAll(newData)
        notifyDataSetChanged()
    }

    fun getData(): String = Gson().toJson(data)

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_plan_parent, parent, false)
        )
    }

    override fun getItemCount(): Int = data.size

    override fun onBindViewHolder(
        holder: ViewHolder,
        position: Int
    ) {
        val listPlans = data[position]
        val childLayoutManager = LinearLayoutManager(
            holder.recyclerView.context,
            LinearLayoutManager.VERTICAL,
            false
        )

        val childAdapter = FormPlanChildAdapter(listPlans, object : PlanParentCallback {
            override fun deletePlan(position: Int) {
                listPlans.removeAt(position)
                notifyDataSetChanged()
            }
        })

        holder.recyclerView.apply {
            layoutManager = childLayoutManager
            adapter = childAdapter
            setRecycledViewPool(viewPool)
        }

        holder.textView.text = "Hari ke ${position + 1}"

        holder.imageButton.setOnClickListener {
            listPlans.add(ItemPlan())
            notifyDataSetChanged()
        }
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val recyclerView: RecyclerView = itemView.rv_plan_child
        val textView: TextView = itemView.tv_days_of
        val imageButton: ImageButton = itemView.ib_add
    }

    interface PlanParentCallback {
        fun deletePlan(position: Int)
    }

}
class FormPlanChildAdapter(
    private val listPlans: List<ItemPlan>,
    private val callback: FormPlanParentAdapter.PlanParentCallback
) :
    RecyclerView.Adapter<FormPlanChildAdapter.ViewHolder>() {

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_plan_child, parent, false)
        )
    }

    override fun getItemCount(): Int = listPlans.size

    override fun onBindViewHolder(
        holder: ViewHolder,
        position: Int
    ) {
        val itemPlan = listPlans[position]
        holder.etPlan.setText(itemPlan.plan)
        holder.etPlan.doAfterTextChanged {
            listPlans[position].plan = it.toString()
        }

        if (position == 0) {
            holder.ibDelete.invisible()
        } else {
            holder.ibDelete.visible()
        }

        holder.ibDelete.setOnClickListener {
            if (listPlans.size > 1) {
                callback.deletePlan(position)
            }
        }
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val etPlan: EditText = itemView.et_plan
        val ibDelete: ImageButton = itemView.ib_delete
    }
}
类FormPlanParentAdapter:
RecyclerView.Adapter(){
私有val数据:MutableList=mutableListOf()
private val viewPool=RecyclerView.RecycledViewPool()
fun setData(新数据:列表){
data.clear()
data.addAll(newData)
notifyDataSetChanged()
}
fun getData():String=Gson().toJson(数据)
覆盖视图保持器(
父对象:视图组,
视图类型:Int
):视窗座{
返回视窗座(
LayoutFlater.from(parent.context)。充气(R.layout.item\u plan\u parent,parent,false)
)
}
重写getItemCount():Int=data.size
覆盖BindViewHolder(
持有者:视图持有者,
职位:Int
) {
val listPlans=数据[位置]
val childLayoutManager=LinearLayoutManager(
holder.recyclerView.context,
LinearLayoutManager.VERTICAL,
假的
)
val childAdapter=FormPlanChildAdapter(listPlans,对象:PlanParentCallback{
覆盖平面图(位置:Int){
listPlans.removeAt(位置)
notifyDataSetChanged()
}
})
holder.recyclerView.apply{
layoutManager=childLayoutManager
适配器=子适配器
setRecycledViewPool(viewPool)
}
holder.textView.text=“Hari ke${position+1}”
holder.imageButton.setOnClickListener{
添加(ItemPlan())
notifyDataSetChanged()
}
}
内部类ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
val recyclerView:recyclerView=itemView.rv\u计划\u子项
val textView:textView=itemView.tv\u天
val imageButton:imageButton=itemView.ib_添加
}
接口PlanParentCallback{
平面图(位置:Int)
}
}
我的子适配器代码:

class FormPlanParentAdapter :
    RecyclerView.Adapter<FormPlanParentAdapter.ViewHolder>() {

    private val data: MutableList<MutableList<ItemPlan>> = mutableListOf()

    private val viewPool = RecyclerView.RecycledViewPool()

    fun setData(newData: List<MutableList<ItemPlan>>) {
        data.clear()
        data.addAll(newData)
        notifyDataSetChanged()
    }

    fun getData(): String = Gson().toJson(data)

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_plan_parent, parent, false)
        )
    }

    override fun getItemCount(): Int = data.size

    override fun onBindViewHolder(
        holder: ViewHolder,
        position: Int
    ) {
        val listPlans = data[position]
        val childLayoutManager = LinearLayoutManager(
            holder.recyclerView.context,
            LinearLayoutManager.VERTICAL,
            false
        )

        val childAdapter = FormPlanChildAdapter(listPlans, object : PlanParentCallback {
            override fun deletePlan(position: Int) {
                listPlans.removeAt(position)
                notifyDataSetChanged()
            }
        })

        holder.recyclerView.apply {
            layoutManager = childLayoutManager
            adapter = childAdapter
            setRecycledViewPool(viewPool)
        }

        holder.textView.text = "Hari ke ${position + 1}"

        holder.imageButton.setOnClickListener {
            listPlans.add(ItemPlan())
            notifyDataSetChanged()
        }
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val recyclerView: RecyclerView = itemView.rv_plan_child
        val textView: TextView = itemView.tv_days_of
        val imageButton: ImageButton = itemView.ib_add
    }

    interface PlanParentCallback {
        fun deletePlan(position: Int)
    }

}
class FormPlanChildAdapter(
    private val listPlans: List<ItemPlan>,
    private val callback: FormPlanParentAdapter.PlanParentCallback
) :
    RecyclerView.Adapter<FormPlanChildAdapter.ViewHolder>() {

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_plan_child, parent, false)
        )
    }

    override fun getItemCount(): Int = listPlans.size

    override fun onBindViewHolder(
        holder: ViewHolder,
        position: Int
    ) {
        val itemPlan = listPlans[position]
        holder.etPlan.setText(itemPlan.plan)
        holder.etPlan.doAfterTextChanged {
            listPlans[position].plan = it.toString()
        }

        if (position == 0) {
            holder.ibDelete.invisible()
        } else {
            holder.ibDelete.visible()
        }

        holder.ibDelete.setOnClickListener {
            if (listPlans.size > 1) {
                callback.deletePlan(position)
            }
        }
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val etPlan: EditText = itemView.et_plan
        val ibDelete: ImageButton = itemView.ib_delete
    }
}
类FormPlanChildAdapter(
私有val列表计划:列表,
私有val回调:FormPlanParentAdapter.PlanParentCallback
) :
RecyclerView.Adapter(){
覆盖视图保持器(
父对象:视图组,
视图类型:Int
):视窗座{
返回视窗座(
LayoutFlater.from(parent.context).充气(R.layout.item\u plan\u child,parent,false)
)
}
重写getItemCount():Int=listPlans.size
覆盖BindViewHolder(
持有者:视图持有者,
职位:Int
) {
val itemPlan=listPlans[位置]
holder.etPlan.setText(itemPlan.plan)
holder.etPlan.doAfterTextChanged{
listPlans[position].plan=it.toString()
}
如果(位置==0){
holder.ibDelete.invisible()文件
}否则{
holder.ibDelete.visible()
}
holder.ibDelete.setOnClickListener{
如果(listPlans.size>1){
callback.deletePlan(位置)
}
}
}
内部类ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
val etPlan:EditText=itemView.et_计划
val ibDelete:ImageButton=itemView.ib_delete
}
}
感谢您的帮助。

请尝试

listPlans.removeAt(position)
notifyItemRemoved(position)
而不是

listPlans.removeAt(position)
notifyDataSetChanged()
原因: 当数据集更改时,旧的
TextWatcher
s和适配器位置会出现混乱

notifyDatasetChanged
触发
onBindViewHolder
,然后
EditText
TextWatcher
由于此行而收到通知
holder.etPlan.setText(itemPlan.plan)

由于
etPlan
已经有一个来自上一个绑定的活动
TextWatcher
,因此它尝试用适配器的旧位置通知它

快速回答:

TextWatcher
保留在
ViewHolder
中,将其从
onBindViewHolder
上的
EditText
中删除,并在设置
EditText
的值后再次将其设置为
EditText

因此,将子适配器的onBindViewHolder更新为

覆盖BindViewHolder(
持有者:视图持有者,
职位:Int
) {
val itemPlan=listPlans[位置]
holder.etPlan.removeTextChangedListener(holder.textWatcher)
holder.etPlan.setText(itemPlan.plan)
holder.textWatcher=holder.etPlan.doaftertexchanged{
listPlans[position].plan=it.toString()
}
...
}
并更新其ViewHolder,如:

内部类ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView){
val etPlan:EditText=itemView.et_计划
val ibDelete:ImageButton=itemView.ib_delete
var textWatcher:textWatcher?=null
}

但是,由于性能问题,不建议在
onBindViewHolder
上设置侦听器。请查收

以下是另一个解决方法:

通过侦听器将所有
TextWatcher
内容移动到
Adapter
,并防止在不必要时通知
TextWatcher

接口TextChangeListener{
有趣的onTextChange(文本:字符串,位置:Int)
}
类FormPlanChildAdapter(…):
RecyclerView.Adapter(),TextChangeListener{
覆盖BindViewHolder(
持有者:视图持有者,
职位:Int
) {
val itemPlan=listPlans[位置]
固定平面图(一)