【问题标题】:Handle search results after configuration change MVVM配置更改 MVVM 后处理搜索结果
【发布时间】:2022-01-22 11:21:58
【问题描述】:

我正在构建一个基于“电影数据库”的电影应用程序。我的应用程序只有一个带有 recyclerview 的活动和一个搜索操作按钮 (SearchView)。 应用程序一启动,recyclerview 就充满了流行电影列表。

当我搜索电影时,我得到了结果,一切都很好,但是当我旋转屏幕时,我得到了热门电影列表,而不是我的搜索结果。

现在我知道原因了,因为在onCreate 我有initMoviesRecyclerView() 用流行电影填充recyclerview。

我的问题是如何在不填充 recyclerview 的情况下保留搜索结果 popularMovies ?我怎样才能以正确的方式做到这一点?

这是Repository 类:

class MainRepository {

    //MutableLiveData
    private val popularMoviesMutableLiveData = MutableLiveData<List<Movie>>()
    private val searchAfterMutableLiveData = MutableLiveData<List<Movie>>()

    // API
    private val apiService : GetFromApi = APIService.retrofitClientRequest
    private val apiKey = "NOT"

     
    fun getPopularMoviesList() : MutableLiveData<List<Movie>>{

        apiService.getPopularMovies(apiKey,1)?.enqueue(object : Callback<MovieListResult?> {
            override fun onResponse(
                call: Call<MovieListResult?>,
                response: Response<MovieListResult?>
            ) {

                if (response.isSuccessful){

                    popularMoviesMutableLiveData.value = response.body()?.moviesResults
                    Log.e("MovieListResults","Result: ${popularMoviesMutableLiveData.value}")
                }

            }

            override fun onFailure(call: Call<MovieListResult?>, t: Throwable) { 
                Log.e("MovieListResults","Failed: ${t.message}")
            }
        })

        return popularMoviesMutableLiveData

    }

    fun searchAfter(searchAfter : String) : MutableLiveData<List<Movie>>{

        apiService.searchAfter(apiKey,searchAfter)?.enqueue(object : Callback<MovieListResult?> {
            override fun onResponse(
                call: Call<MovieListResult?>,
                response: Response<MovieListResult?>
            ) {

                if (response.isSuccessful){
                    searchAfterMutableLiveData.value = response.body()?.moviesResults
                    Log.e("SearchMovieListResults","Result: ${searchAfterMutableLiveData.value}")
                }

            }

            override fun onFailure(call: Call<MovieListResult?>, t: Throwable) {
                Log.e("SearchMovieListResults","Failed: ${t.message}")
            }
        })

        return searchAfterMutableLiveData
    }

}

这是viewModel 类:

class MainViewModel : ViewModel(){

    //Repository
    private val mainRepository = MainRepository()

    //MutableLiveData
    var popularMoviesMutableLiveData = MutableLiveData<List<Movie>>()
    var searchAfterMutableLiveData = MutableLiveData<List<Movie>>()

    //The Main Movie List
    var mainMovieList = listOf<Movie>()

    fun getPopularMovies() : LiveData<List<Movie>>{
        popularMoviesMutableLiveData = mainRepository.getPopularMoviesList()
        popularMoviesMutableLiveData.value = mainMovieList
        return popularMoviesMutableLiveData
    }

    fun getMovieBySearch(searchAfter : String) : LiveData<List<Movie>>{
        searchAfterMutableLiveData = mainRepository.searchAfter(searchAfter)
        searchAfterMutableLiveData.value = mainMovieList
        return searchAfterMutableLiveData
    }


}

这是MainActivity 类:

class MainActivity : AppCompatActivity() {



    //ViewModel
    private val mainViewModel : MainViewModel by viewModels()

    // Views
    private lateinit var mainRecyclerView : RecyclerView
    private lateinit var mainAdapter : MainRecyclerViewAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        
        initMoviesRecyclerView()


    }


    private fun initMoviesRecyclerView() {

        mainRecyclerView = findViewById(R.id.mainRecyclerView)
        mainRecyclerView.setHasFixedSize(true)
        mainRecyclerView.layoutManager = GridLayoutManager(this,1)

        mainViewModel.getPopularMovies().observe(this, object : Observer<List<Movie>?> {
            override fun onChanged(newList: List<Movie>?) {

                if (newList != null) {

                    mainViewModel.mainMovieList = newList
                    mainAdapter = MainRecyclerViewAdapter(mainViewModel.mainMovieList)
                    mainRecyclerView.adapter = mainAdapter

                }

            }
        })

    }




    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.main_menu,menu)

        val searchView = menu.findItem(R.id.menu_search_movie).actionView as androidx.appcompat.widget.SearchView

        searchView.queryHint = "Search By Name,Actor .."
        searchView.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(whileTextChange: String?): Boolean {
                //Clear SearchView
                searchView.isIconified = true
                searchView.setQuery("", false)
                searchView.onActionViewCollapsed()
                mainViewModel.getMovieBySearch(whileTextChange.toString()).observe(this@MainActivity,object : Observer<List<Movie>?> {
                    override fun onChanged(newList: List<Movie>?) {
                        if (newList != null) {

                            mainViewModel.mainMovieList = newList
                            mainAdapter.changeCurrentList(mainViewModel.mainMovieList)
                        }
                    }
                })

                return false
            }

            override fun onQueryTextChange(whileTextChange: String?): Boolean {
                Log.e("onQueryTextChange","Text: $whileTextChange")
                return false
            }
        })

        return true
    }



}

谢谢!

【问题讨论】:

    标签: android kotlin android-recyclerview android-viewmodel android-mvvm


    【解决方案1】:

    我看不到您在ViewModel 中实际填充数据的位置。但这一切看起来都很好。

    这行有点可疑:

    mainViewModel.mainMovieList = newList
    

    您不应从View 生命周期更新ViewModel。此外,您不应在 observe 调用期间更新 ViewModel。

    【讨论】:

    • 嗨伊利亚,谢谢你的澄清!
    【解决方案2】:

    所以过了一段时间后,我设法用一个简单的解决方案解决了这个问题:

    我在viewModel中创建了一个函数,检查搜索列表value是否为空:

    fun startFromSearch(): Boolean {
        return searchAfterMutableLiveData.value != null
    }
    

    之后我在initMoviesRecyclerView()中做了一个if语句,就是这样!

        private fun initMoviesRecyclerView() {
        
            mainRecyclerView = findViewById(R.id.mainRecyclerView)
            mainRecyclerView.setHasFixedSize(true)
            mainRecyclerView.layoutManager = GridLayoutManager(this,1)
            mainAdapter = MainRecyclerViewAdapter(mainViewModel.mainMovieList,this)
            mainRecyclerView.adapter = mainAdapter
        
        
        
            if (!mainViewModel.startFromSearch()){
        
                mainViewModel.getPopularMovies(1).observe(this, object : Observer<List<Movie>?> {
                    override fun onChanged(newList: List<Movie>?) {
        
                        if (newList != null) {
        
                            mainAdapter = MainRecyclerViewAdapter(newList,this@MainActivity)
                            mainRecyclerView.adapter = mainAdapter
        
                        }
        
                    }
                })
            }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-11
      • 2013-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多