Search code examples
androidkotlinmvvmandroid-recyclerviewviewmodel

kotlin recyclerview MVVM error - IndexOutOfBoundsException


On recyclerview I'm setting a list, using MVVM where I'm getting an error, IndexOutOfBoundsException. code I use for recyclerview adapter is below - onBindViewHolder is where I set articles:List

  class MainAdapter(private val context: Context,private val articles:List<Article>) : ListAdapter<Article, MainAdapter.MainViewHolder>(DiffUtil()) {

    inner class MainViewHolder(val binding: HomeRecViewBinding) : RecyclerView.ViewHolder(binding.root)

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

        val binding = HomeRecViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return MainViewHolder(binding)
    }

    override fun onBindViewHolder(holder: MainViewHolder, position: Int) {

        val articles_ = articles[position]
        holder.binding.artical = articles_

    }

    class DiffUtil : androidx.recyclerview.widget.DiffUtil.ItemCallback<Article>() {
        override fun areItemsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Article, newItem: Article): Boolean {
            return oldItem == newItem
        }

    }
}

my ViewModel is given below

  val article : LiveData<NewsModel>
    get() = repoHelper.article

my main Activity

class TestActivity : AppCompatActivity() {

    lateinit var binding: ActivityTestBinding
    lateinit var mainViewModel: MainViewModel
    lateinit var article_: List<Article>

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this,R.layout.activity_test)

        article_ = ArrayList()
        val mainAdapter = MainAdapter(this,article_)
        binding.recView.apply {
            this.layoutManager = LinearLayoutManager(this@TestActivity)
            this.adapter = mainAdapter
        }

        val apiHelper = RetrofitHelper.getInstance().create(ApiHelper::class.java)
        val database_ = DBHelper.getDatabase(applicationContext)
        val repoHelper = RepoHelper(apiHelper,database_,applicationContext)

        mainViewModel = ViewModelProvider(this,ViewModelFactory(repoHelper)).get(MainViewModel::class.java)

        mainViewModel.article.observe(this, Observer {
            Log.d("list_of_article",it.articles.toString())
            mainAdapter.submitList(it.articles)
        })
    }

what's the main cause for this error and how do I resolve it.


Solution

  • article_ = ArrayList()
    val mainAdapter = MainAdapter(this,article_)
    

    Here you provide an empty list to the Adapter.

    After this never changes!

    mainAdapter.submitList(it.articles) does not set this list in the adapter.

    So val articles_ = articles[position] will try to access something from an empty list.

    As a matter of fact. You don't even need to have this list at all. ListAdapter has methods to access the list you provide with submitList

    Instead of

    val articles_ = articles[position]
    

    you can do

    val articles_ = getItem(position)
    

    and then you can remove the articles completely there so change

    class MainAdapter(private val context: Context,private val articles:List<Article>)
    

    to

    class MainAdapter(private val context: Context)
    

    and change

    val mainAdapter = MainAdapter(this,article_)
    

    to

    val mainAdapter = MainAdapter(this)