Android: LiveData postValue() 越来越空
Android: LiveData postValue() getting null
我正在尝试使用 postValue() 将值从一个 LiveData (Repository.getMovieList(editTextContent.value.toString()).value
) 传输到另一个 LiveData (this.movieList.postValue
)。
我正在观察 movieList 并希望根据单击的不同按钮从 Repo 更改它的值但是我在它运行时只获得 null
值并且不会等到 Repo 的LiveData 获得它们的价值。
片段xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewmodel"
type="com.example.movieapp.ui.search.SearchMovieFragmentViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.search.SearchMovieFragment">
<EditText
android:id="@+id/search_movie_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewmodel.editTextContent}"
android:inputType="text"
android:hint="Movie Name" />
<Button
android:id="@+id/search_fragment_search_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Search"
android:onClick="@{() -> viewmodel.getMovieSearchList()}"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_movie_fragment_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</layout>
SearchMovieFragment
class SearchMovieFragment : Fragment(), MovieSearchItemViewModel {
companion object {
fun newInstance() = SearchMovieFragment()
}
private lateinit var searchMovieFragmentViewModel: SearchMovieFragmentViewModel
private lateinit var binding: SearchMovieFragmentBinding
private lateinit var movieRecyclerView: RecyclerView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.search_movie_fragment, container, false)
searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
binding.lifecycleOwner = this
binding.viewmodel = searchMovieFragmentViewModel
setUpRecyclerView(container!!.context)
return binding.root
}
private fun setUpRecyclerView(context: Context) {
movieRecyclerView = binding.searchMovieFragmentRecyclerView.apply {
this.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
}
val adapter = MovieListAdapter()
adapter.setCallback(this)
binding.searchMovieFragmentRecyclerView.adapter = adapter
searchMovieFragmentViewModel.getMovieListLiveData().observe(viewLifecycleOwner, Observer {movieList ->
adapter.submitList(movieList)
})
}
}
SearchMovieViewModel
class SearchMovieFragmentViewModel : ViewModel() {
val editTextContent = MutableLiveData<String>()
var movieList: MutableLiveData<List<Movie>> = MutableLiveData()
fun getMovieSearchList(){
this.movieList.postValue(Repository.getMovieList(editTextContent.value.toString()).value)
}
fun getTrendingMovies() {
movieList.postValue(Repository.getTrendingMovies().value)
}
fun getMovieDetail(movieId: String): MutableLiveData<Movie> {
return Repository.getMovieDetail(movieId)
}
fun getMovieListLiveData() : LiveData<List<Movie>> {
return movieList
}
private fun getMovieList(movieSearch: String): MutableLiveData<List<Movie>> = Repository.getMovieList(movieSearch)
}
我认为您以错误的方式实现它,相反,使用 MediatorLiveData
将是一个很好且实用的解决方案,因为它允许您观察多个 LiveData 对象以及它们之间的 select 基于您的偏好(例如特定操作)。
这是在您的案例中如何实施的示例
val editTextContent = MutableLiveData<String>()
val finalList = MediatorLiveData<List<Movie>>()
// Here.. Define all of your LiveData objects
private val movieList = repository.getMovieList(editTextContent.value.toString())
private val trendingMovies = repository.getTrendingMovies()
private val movieDetail = repository.getMovieDetail()
fun setSelection(selection: String) {
finalList.addSource(movieList) { result ->
if (selection == "movieList") {
result?.let { finalList.value = it }
}
}
finalList.addSource(trendingMovies) { result ->
if (selection == "trendingMovies") {
result?.let { finalList.value = it }
}
}
finalList.addSource(movieDetail) { result ->
if (selection == "movieDetail") {
result?.let { finalList.value = it }
}
}
}
所以你要做的就是只观察MediatorLiveData
,然后调用setSelection
函数,将对应的selection动作作为参数传给它,它就会将观察切换到另一个 LiveData
我正在尝试使用 postValue() 将值从一个 LiveData (Repository.getMovieList(editTextContent.value.toString()).value
) 传输到另一个 LiveData (this.movieList.postValue
)。
我正在观察 movieList 并希望根据单击的不同按钮从 Repo 更改它的值但是我在它运行时只获得 null
值并且不会等到 Repo 的LiveData 获得它们的价值。
片段xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewmodel"
type="com.example.movieapp.ui.search.SearchMovieFragmentViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.search.SearchMovieFragment">
<EditText
android:id="@+id/search_movie_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@={viewmodel.editTextContent}"
android:inputType="text"
android:hint="Movie Name" />
<Button
android:id="@+id/search_fragment_search_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Search"
android:onClick="@{() -> viewmodel.getMovieSearchList()}"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/search_movie_fragment_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
</layout>
SearchMovieFragment
class SearchMovieFragment : Fragment(), MovieSearchItemViewModel {
companion object {
fun newInstance() = SearchMovieFragment()
}
private lateinit var searchMovieFragmentViewModel: SearchMovieFragmentViewModel
private lateinit var binding: SearchMovieFragmentBinding
private lateinit var movieRecyclerView: RecyclerView
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.search_movie_fragment, container, false)
searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
binding.lifecycleOwner = this
binding.viewmodel = searchMovieFragmentViewModel
setUpRecyclerView(container!!.context)
return binding.root
}
private fun setUpRecyclerView(context: Context) {
movieRecyclerView = binding.searchMovieFragmentRecyclerView.apply {
this.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
}
val adapter = MovieListAdapter()
adapter.setCallback(this)
binding.searchMovieFragmentRecyclerView.adapter = adapter
searchMovieFragmentViewModel.getMovieListLiveData().observe(viewLifecycleOwner, Observer {movieList ->
adapter.submitList(movieList)
})
}
}
SearchMovieViewModel
class SearchMovieFragmentViewModel : ViewModel() {
val editTextContent = MutableLiveData<String>()
var movieList: MutableLiveData<List<Movie>> = MutableLiveData()
fun getMovieSearchList(){
this.movieList.postValue(Repository.getMovieList(editTextContent.value.toString()).value)
}
fun getTrendingMovies() {
movieList.postValue(Repository.getTrendingMovies().value)
}
fun getMovieDetail(movieId: String): MutableLiveData<Movie> {
return Repository.getMovieDetail(movieId)
}
fun getMovieListLiveData() : LiveData<List<Movie>> {
return movieList
}
private fun getMovieList(movieSearch: String): MutableLiveData<List<Movie>> = Repository.getMovieList(movieSearch)
}
我认为您以错误的方式实现它,相反,使用 MediatorLiveData
将是一个很好且实用的解决方案,因为它允许您观察多个 LiveData 对象以及它们之间的 select 基于您的偏好(例如特定操作)。
这是在您的案例中如何实施的示例
val editTextContent = MutableLiveData<String>()
val finalList = MediatorLiveData<List<Movie>>()
// Here.. Define all of your LiveData objects
private val movieList = repository.getMovieList(editTextContent.value.toString())
private val trendingMovies = repository.getTrendingMovies()
private val movieDetail = repository.getMovieDetail()
fun setSelection(selection: String) {
finalList.addSource(movieList) { result ->
if (selection == "movieList") {
result?.let { finalList.value = it }
}
}
finalList.addSource(trendingMovies) { result ->
if (selection == "trendingMovies") {
result?.let { finalList.value = it }
}
}
finalList.addSource(movieDetail) { result ->
if (selection == "movieDetail") {
result?.let { finalList.value = it }
}
}
}
所以你要做的就是只观察MediatorLiveData
,然后调用setSelection
函数,将对应的selection动作作为参数传给它,它就会将观察切换到另一个 LiveData