#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