ItemTouchHelper создает исключение IndexOutOfBoundException при попытке обмена элементами - PullRequest
0 голосов
/ 24 апреля 2019

У меня есть RecyclerView, который добавляет элементы, которые следует перетаскивать, однако, когда элемент добавляется, и я пытаюсь поменять его, возникает исключение IndexOutOfBoundException

RecyclerView наблюдает за ViewModel, который обновляет информацию, когда какой-то блок добавляется, я использовал LiveData для его достижения.

Мое решение отлично работает, когда в списке есть определенное количество элементов, проблема возникает, когда я пытаюсь добавить что-то в RecyclerView.

Я расширил ItemTouchHelper.SimpleCallBack классом, который содержит адаптер для RecyclerView, но когда элементы добавляются, размер странным образом не меняется (я пытался установить его вручную, но он не будет работать).

Я пытался отсоединить TouchHelper, вызвав

touchHelper? .AttachToRecyclerView (null)

и затем присоединение его снова с новым обратным вызовом, но оно также не будет работать.

это деятельность


class CreateWorkflowActivity: AppCompatActivity(), View.OnClickListener {

    var touchHelper:ItemTouchHelper?= null
    private lateinit var callback:ItemMoveCallback
    private lateinit var rec_view: RecyclerView
    companion object {
        private lateinit var viewModel : WorkflowViewModel
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_create_workflow)
        val factory= InjectorUtils.provideWorkflowViewModelFactory("")
        viewModel = ViewModelProviders.of(this,factory).get(WorkflowViewModel::class.java)
        rec_view= findViewById(R.id.recyclerView_addedBlocksOnCreation)
        rec_view.layoutManager= LinearLayoutManager(this)
        val observer = Observer<ArrayList<String>>{
            val adapter = BlockViewAdapter(it!!, this@CreateWorkflowActivity)
            callback= ItemMoveCallback(adapter,this@CreateWorkflowActivity,ItemTouchHelper.UP.or(ItemTouchHelper.DOWN),0)
            touchHelper= ItemTouchHelper(callback)
            touchHelper?.attachToRecyclerView(rec_view)
            runOnUiThread{
                rec_view.adapter= adapter
            }
        }
        viewModel.getLiveBlockNames().observe(this,observer)


    }

//this gets called when the user has decided the parameters for the block
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if(requestCode == 1) {
            if(resultCode==Activity.RESULT_OK) {

               //all block additions

                }

            }

        }

    }

}


это расширяет ItemTouchHelper.SimpleCallBack


class ItemMoveCallback(adapter: BlockViewAdapter, context: Context, dragDirs: Int, swipeDirs: Int) : ItemTouchHelper.SimpleCallback(dragDirs, swipeDirs)
{
    var mAdapter = adapter


    override fun onSwiped(p0: RecyclerView.ViewHolder, p1: Int) {
        return
    }

    override fun onMove(p0: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
        mAdapter.swapItems(viewHolder.adapterPosition, target.adapterPosition)
        return true
    }
    fun setAdapter(adapter: BlockViewAdapter){
        mAdapter=adapter
    }

}

Это адаптер (я опустил BlockViewHolder, потому что он довольно стандартный)

class BlockViewAdapter(val dataset: ArrayList<String>,val context: Context): RecyclerView.Adapter<BlockViewHolder>(){

    @SuppressLint("ClickableViewAccessibility")
    override fun onBindViewHolder(holder: BlockViewHolder, position: Int) {
        holder.tView?.text = dataset[position]

        }


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

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlockViewHolder {

        return BlockViewHolder(
            LayoutInflater.from(context).inflate(
                R.layout.block_item,
                parent,
                false
            )
        )

    }

    fun swapItems(fromPosition: Int, toPosition: Int) {

        if (fromPosition < toPosition) {
            for (i in fromPosition..toPosition - 1) {
                dataset.set(i, dataset.set(i+1, dataset.get(i)))
            }
        } else {
            for (i in fromPosition..toPosition + 1) {
                dataset.set(i, dataset.set(i-1, dataset.get(i)))
            }
        }

        notifyItemMoved(fromPosition, toPosition)
    }


}

1 Ответ

0 голосов
/ 25 апреля 2019

@ Ludovico Brocca Вы сталкиваетесь с IndexOutOfBoundException, потому что вы не звоните notifyDataSetChanged() после добавления нового элемента в адаптер.

Итак, инициализируйте ваш адаптер только контекстом, а затем настройте элементы. Пример ниже для справки:

class BlockViewAdapter(val context: Context) : RecyclerView.Adapter<BlockViewHolder>() {

    var dataset: List<String> = emptyList()
      set(value) {
        // might have to do this on main thread
        field = value
        notifyDataSetChanged()
      }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlockViewHolder {
      TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun onBindViewHolder(holder: BlockViewHolder, position: Int) {
      TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun getItemCount(): Int {
      TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...