我有一个简单的搜索应用程序。API调用正确地获取对象并将其加载到movies. list中。我从viewModel中观察此列表并将其传递给适配器。(大多数时候为空)然后适配器连接到recyclerview,...它不会显示任何内容。
我尝试使用viewmodelFactory对ViewModel初始化进行调整-可能是列表加载速度慢于适配器发布的速度。我尝试在等待时制作加载动画,但不起作用
结果片段
package com.dragos.moviesearch.ui.main
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import com.dragos.moviesearch.databinding.FragmentResultsBinding
import com.dragos.moviesearch.viewmodel.MainViewModel
class ResultsFragment : Fragment() {
private val viewModel: MainViewModel by lazy {
ViewModelProvider(this).get(MainViewModel::class.java)
}
private var myadapter = ResultsAdapter()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = FragmentResultsBinding.inflate(inflater)
binding.lifecycleOwner = this
viewModel.moviesList.observe(viewLifecycleOwner) {
if (it != null){
println("dra avem urmatoarele filme atasate la adaptor: " + it)
myadapter.info = it
myadapter.notifyDataSetChanged()
for(i in 0..5){
println("dra avem urmatoarele filme in resultsfragment la onCreate: " + (viewModel.moviesList.value?.get(i)))
}
}
}
binding.resultsRecyclerview.adapter = myadapter
binding.resultsRecyclerview.layoutManager = LinearLayoutManager(context)
return binding.root
}
}
主视图模型
package com.dragos.moviesearch.viewmodel
import androidx.lifecycle.*
import com.dragos.moviesearch.data.Movie
import com.dragos.moviesearch.data.MoviesList
import com.dragos.moviesearch.repository.DataRepository
import kotlinx.coroutines.launch
enum class MovieApiStatus { LOADING, ERROR, DONE }
class MainViewModel : ViewModel() {
private val repository: DataRepository = DataRepository
private var _moviesList = MutableLiveData<List<Movie>>()
val moviesList: LiveData<List<Movie>>
get() = _moviesList
private val _status = MutableLiveData<MovieApiStatus>()
val status: LiveData<MovieApiStatus> = _status
private var _query = MutableLiveData<String>()
val query: LiveData<String> = _query
fun getMovieInfo() {
viewModelScope.launch {
_status.value = MovieApiStatus.LOADING
try {
_moviesList.value = _query.value?.let { repository.getMovieInfo(it)}
_status.value = MovieApiStatus.DONE
println("dra here we have the movie list at done: " + _moviesList.value)
} catch (e: Exception) {
_status.value = MovieApiStatus.ERROR
_moviesList.value = ArrayList()
}
}
}
fun updateQuery(rawInputQuery: String) {
_query.value = rawInputQuery.replace(" ","+")
println("dra query-ul este: " + _query.value)
}
}
结合衔接子
package com.dragos.moviesearch.utils
import android.os.Build.VERSION_CODES.M
import android.view.View
import android.widget.ImageView
import androidx.core.net.toUri
import androidx.databinding.BindingAdapter
import com.dragos.moviesearch.R
import coil.load
import com.dragos.moviesearch.viewmodel.MovieApiStatus
@BindingAdapter("showPhoto")
fun bindImage(imgView: ImageView, imgUrl: String?) {
imgUrl?.let {
val imgUri = imgUrl.toUri().buildUpon().scheme("https").build()
imgView.load(imgUri) {
placeholder(R.drawable.loading_animation)
error(R.drawable.ic_broken_image)
}
}
}
@BindingAdapter("movieApiStatus")
fun bindStatus(statusImageView: ImageView, status: MovieApiStatus?) {
when (status) {
MovieApiStatus.LOADING -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.loading_animation)
}
MovieApiStatus.ERROR -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.ic_connection_error)
}
else -> {statusImageView.visibility = View.GONE}
}}
结果适配器
package com.dragos.moviesearch.ui.main
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.dragos.moviesearch.data.Movie
import com.dragos.moviesearch.data.MoviesList
import com.dragos.moviesearch.databinding.MovieItemBinding
import com.dragos.moviesearch.utils.bindImage
class ResultsAdapter: RecyclerView.Adapter<ResultsAdapter.MovieHolder>() {
var info: List<Movie> = listOf()
class MovieHolder(private var binding: MovieItemBinding): RecyclerView.ViewHolder(binding.root) {
fun bind(movie: Movie){
binding.itemTitle.text = movie.show.name
binding.itemGenres.text = movie.show.genres.joinToString(separator = " ")
bindImage(binding.movieImg, movie.show.image.medium)
binding.executePendingBindings()
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieHolder {
return MovieHolder(MovieItemBinding.inflate(LayoutInflater.from(parent.context)))
}
override fun onBindViewHolder(holder: MovieHolder, position: Int) {
holder.bind(info[position])
}
override fun getItemCount() = info.size
}
fragment_results.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.dragos.moviesearch.viewmodel.MainViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/secondaryTextColor">
<EditText
android:id="@+id/searchMovie"
style="@style/editTextStyle"
android:layout_marginTop="20dp"
android:layout_marginEnd="17dp"
android:background="@drawable/round_corners_shape_empty"
android:hint="@string/search"
android:textColor="@color/whiteText"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/magnifierButton"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="5dp"
app:layout_constraintBottom_toBottomOf="@+id/searchMovie"
app:layout_constraintStart_toEndOf="@+id/searchMovie"
app:layout_constraintTop_toTopOf="@+id/searchMovie"
app:srcCompat="@drawable/baseline_search_24" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/resultsRecyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/searchMovie" />
<ImageView
android:id="@+id/status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:movieApiStatus="@{viewModel.status}" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
谢谢大家!
1条答案
按热度按时间iyfjxgzm1#
对于标准实施:
据我所知,在您的
MainViewModel
类中,您需要在从API提取数据后调用ResultsAdapter.notifyDataSetChanged()
...您还可以(最好使用
DiffUtil
以提高效率)。对于实时数据:
你可以通过一个观察者来完成这个任务,观察者会接收修改,然后更新RecyclerView的列表。有很多关于这个主题的指南和博客,包括update RecyclerView with Android LiveData