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