Не вызывается onCreateViewHolder
Пишу несложный проект по визуализации списка анекдотов. При попытке завернуть все во фрагменты столкнулся с проблемой: перестали отрисовываться элементы, выяснил, что проблема в ListAdapter`е. Метод onCreateViewHolder не вызывается, onBindViewHolder соответственно тоже. Разметка с ContainerView:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.MainActivity" >
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Разметка фрагмента:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/purple_100"
android:paddingHorizontal="20dp"
android:paddingVertical="6dp"
tools:context=".ui.main.ListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/joke_item" />
</androidx.constraintlayout.widget.ConstraintLayout>
Код фрагмента:
class ListFragment : Fragment(R.layout.fragment_list) {
private lateinit var binding: FragmentListBinding
private lateinit var viewModel: JokesListViewModel
private val adapter = JokesListAdapter {
findNavController().navigate(
ListFragmentDirections.actionListFragmentToJokeDetailsFragment(
viewModel.getJokeId(it)
)
)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initViewModel()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentListBinding.inflate(layoutInflater)
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(activity)
savedInstanceState ?: run {
viewModel.generateJokes()
}
}
private fun initViewModel() {
val factory = JokeViewModelFactory(JokesGenerator)
viewModel = ViewModelProvider(this, factory)[JokesListViewModel::class.java]
viewModel.jokes.observe(this) {
adapter.submitList(it)
Toast.makeText(activity, "jokes updated", Toast.LENGTH_SHORT).show()
}
viewModel.error.observe(this) {
Toast.makeText(activity, it, Toast.LENGTH_SHORT).show()
}
}
}
Код адаптера:
class JokesListAdapter(
private val clickListener: (Int) -> Unit
) :
ListAdapter<Joke, JokesViewHolder>(JokeItemCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JokesViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = JokeItemBinding.inflate(inflater, parent, false)
return JokesViewHolder(binding).apply {
binding.root.setOnClickListener {
handlePersonClick(bindingAdapterPosition)
}
}
}
override fun getItemCount() = currentList.size
override fun onBindViewHolder(holder: JokesViewHolder, position: Int) {
holder.bind(currentList[position])
}
private fun handlePersonClick(position: Int) {
if (position != RecyclerView.NO_POSITION) {
clickListener(position)
}
}
}
И viewHolder`а:
class JokesViewHolder(private val binding: JokeItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(joke: Joke) {
binding.textViewQuestion.text = joke.jokeQuestion
binding.textViewAnswer.text = joke.jokeAnswer
binding.textViewCategory.text = joke.category
println("!!! $joke.id binded")
}
}
Ответы (2 шт):
binding = FragmentListBinding.inflate(layoutInflater)
в этой строке создаётся копия вью, не связанная с фрагментом, она не отображается на экране и, соответственно, адаптер не задействован.
Вместо этого следует получить привязку к вью, которую создал фрагмент (она приходит параметром метода):
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding = FragmentListBinding.bind(view)
Нужно изменить метод onViewCreated и переопределить метод onCreateView следующим образом:
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentListBinding.inflate(inflater)
val view: View = binding.root
binding.recyclerView.adapter = adapter
binding.recyclerView.layoutManager = LinearLayoutManager(activity)
savedInstanceState ?: run {
viewModel.generateJokes()
}
return view;
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
savedInstanceState ?: run {
viewModel.generateJokes()
}
}