Настройка адаптера в моем фрагменте, чтобы он работал

#android #android-studio #android-fragments #android-adapter #android-viewmodel

Вопрос:

Когда я попытался запустить приложение, я получил эту ошибкувведите описание изображения здесь

Я пробовал разные способы реализации адаптера во фрагменте, но, похоже, это не работает

Адаптер

 class AsteroidViewAdapter(private val onClickListener: OnClickListener)  :
    ListAdapter<Asteroid, AsteroidViewAdapter.AsteroidViewHolder>(DiffCallback) {




    companion object DiffCallback : DiffUtil.ItemCallback<Asteroid>() {
        override fun areItemsTheSame(oldItem: Asteroid, newItem: Asteroid): Boolean {
            return oldItem.id == newItem.id
        }

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

    }

    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): AsteroidViewHolder {
        return AsteroidViewHolder(
            AsteroidListContainerBinding.inflate(
                LayoutInflater.from(parent.context),
                parent,
                false
            )
        )
    }

    override fun onBindViewHolder(holder: AsteroidViewHolder, position: Int) {
        holder.bind(getItem(position), onClickListener)
    }

    class AsteroidViewHolder(private val binding: AsteroidListContainerBinding) :
        RecyclerView.ViewHolder(binding.root) {
        fun bind(item: Asteroid, listener: OnClickListener) {
            binding.value = item
            binding.listener = listener
            binding.executePendingBindings()
        }


    }


    class OnClickListener(val clickListener: (asteroid: Asteroid) -> Unit) {
        fun onClick(asteroid: Asteroid) = clickListener(asteroid)
    }

}
 

Модель представления

 private const val TAG = "MainViewModel"

class MainViewModel(application: Application) : ViewModel() {

    private val database = AsteroidDatabase.getDatabase(application)

    private val repository = AsteroidRepository(database.asteroidDao)

    private val _pictureOfDay = MutableLiveData<PictureOfDay>()
    val pictureOfDay: LiveData<PictureOfDay>
        get() = _pictureOfDay

   val info: LiveData<List<Asteroid>> = Transformations.map(repository.feeds) {
       it
   }


    private val _showProgress = MutableLiveData(true)
    val showProgress: LiveData<Boolean>
        get() = _showProgress

    private val _navigation: MutableLiveData<Asteroid> = MutableLiveData()
    val navigation: LiveData<Asteroid>
        get() = _navigation


    init {
        fetchThePictureOfTheDay()
        loadFeeds()
    }

    private fun loadFeeds() {
        _showProgress.value =  true
        viewModelScope.launch {
            try {
                repository.fetchFeeds()
            }catch (e: Exception) {
                Log.e(TAG, e.message, e.cause)
            }
        }
    }

    private fun fetchThePictureOfTheDay() {
        viewModelScope.launch {
            try {
                val picture = repository.getPictureOfTheDay()
                _pictureOfDay.postValue(picture)
            }catch (e: Exception) {
                Log.e(TAG, e.message, e.cause)
            }
        }
    }


    fun navigateToDetails(asteroid: Asteroid) {
        _navigation.value = asteroid
    }

    fun navigationDone() {
        _navigation.value = null
    }

    fun progress(empty: Boolean) {
        _showProgress.value = empty
    }

    fun filter(filter: Filter) {
        viewModelScope.launch(Dispatchers.IO) {
            repository.filterFeeds(filter)
        }
    }

}
 

Фрагмент

 class MainFragment : Fragment() {

//    private lateinit var  manager: RecyclerView.LayoutManager

  private lateinit var viewModel: MainViewModel
  private lateinit var adapter: AsteroidViewAdapter

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {

        val mainViewModelFactory = MainViewModelFactory(requireActivity().application)
        viewModel = ViewModelProvider(this, mainViewModelFactory).get(MainViewModel::class.java)


        val binding = FragmentMainBinding.inflate(inflater)
        binding.lifecycleOwner = this

        binding.viewModel = viewModel

//        val mutableList: MutableList<Asteroid> = ArrayList()
//        mutableList.add(Asteroid(1, "fgnuugrhrg", "bihagtyjerwailgubivb", 4.0, 8.0,3.0, 9.0, false))
//        mutableList.add(Asteroid(2, "fguk.nuugrhrg", "bidjswjyhagrwailgubivb", 3.0, 90.0,355.0, 9.0, true))
//        mutableList.add(Asteroid(3, "fgnssuugrhrg", "bshjtihagrwailgubivb", 4.0, 33.0,33.0, 9.0, false))
//        mutableList.add(Asteroid(4, "fgnuw4suugrhrg", "bjsryjihagrwailgubivb", 6.0, 8.0,11.0, 9.0, true))
//        mutableList.add(Asteroid(5, "fgnuugrudkdkhrg", "bihjjkkuagrwailgubivb", 4.0, 5.0,77.0, 9.0, false))

//        manager = LinearLayoutManager(this.context)


         binding.asteroidRecycler.adapter = AsteroidViewAdapter(AsteroidViewAdapter.OnClickListener {
             viewModel.navigateToDetails(it)
         })

        viewModel.info.observe(viewLifecycleOwner, Observer {
            viewModel.progress(it.isNullOrEmpty())
            binding.asteroidRecycler.smoothScrollToPosition(0)
            adapter.submitList(it)
        })

       viewModel.navigation.observe(viewLifecycleOwner, Observer { asteroid ->
           asteroid?.let {
               findNavController().navigate(MainFragmentDirections.actionShowDetail(it))
               viewModel.navigationDone()
           }
       })


//        binding.asteroidRecycler.adapter = adapter


        setHasOptionsMenu(true)

        return binding.root
    }


    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        inflater.inflate(R.menu.main_overflow_menu, menu)
        super.onCreateOptionsMenu(menu, inflater)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.menu_show_week -> {
                viewModel.filter(Filter.WEEK)
                true
            }
            R.id.menu_show_today -> {
                viewModel.filter(Filter.TODAY)
                true
            }
            R.id.menu_show_saved -> {
                viewModel.filter(Filter.SAVED)
                true
            }
            else -> false
        }
    }
}
 

Ответ №1:

Согласно сообщению об ошибке, вы на самом деле никогда не устанавливали adapter для себя какое — либо значение-вы просто напрямую назначаете его binding.asteroidRecycler.adapter .

Поскольку адаптер хранит жесткую ссылку на сам RecyclerView, вы все равно не должны содержать ссылку на него на уровне фрагмента, вместо этого вам следует создать для него локальную переменную, прежде чем назначать ее вашему RecyclerView:

 val adapter = binding.asteroidRecycler.adapter = AsteroidViewAdapter(AsteroidViewAdapter.OnClickListener {
             viewModel.navigateToDetails(it)
         })
binding.asteroidRecycler.adapter = adapter