Android:变量在 Fragment 中初始化后在 ViewModel 中未初始化

Android: Variable gets uninitialized in ViewModel after being initialized in the Fragment

我的片段中有一个回调方法,它是从它的 ViewModel 调用的。它在片段的 OnCreateView() 方法中初始化变量,但是当 ViewModel 调用它使用它时,它的 null.

我认为这可能与以某种方式重新创建 VM 有关?我就是想不通。

我正在关注正在创建的回调接口的 of how the VM drives the UI. They provide Google's sample (TasksNavigator.java),覆盖视图中的方法 (TasksActivity.java),然后从 VM 调用该方法 ( TasksViewModel.java) 但它似乎对我不起作用。

片段

class SearchMovieFragment : Fragment(), SearchNavigator {

    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? {

        searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
        binding = DataBindingUtil.inflate(inflater, R.layout.search_movie_fragment, container, false)
        binding.viewmodel = searchMovieFragmentViewModel
        searchMovieFragmentViewModel.setNavigator(this)

        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()
        binding.searchMovieFragmentRecyclerView.adapter = adapter
        searchMovieFragmentViewModel.movieList.observe(viewLifecycleOwner, Observer {
            adapter.submitList(it)
        })
    }

    override fun openDetails() {
        Log.d("TEST", "opening details")
    }
}

ViewModel


class SearchMovieFragmentViewModel : ViewModel(), MovieSearchItemViewModel {

    private lateinit var searchNavigator: SearchNavigator
    val editTextContent = MutableLiveData<String>()
    var movieList = Repository.getMovieList("batman")

    fun setNavigator(_searchNavigator: SearchNavigator) {
        this.searchNavigator = _searchNavigator
        if (searchNavigator != null) {
            Log.d("TEST", "its not null $searchNavigator") // Here it is not null
        }
    }

    private fun getMovieDetail(movieId: String) {
        val movie = Repository.getMovieDetail(movieId)

        Log.d("TEST", "checking ${this.searchNavigator}") // Here is where I call it but it is null
//        searchNavigator.openDetails()
    }
    private fun getMovieList(movieSearch: String): MutableLiveData<List<Movie>> = Repository.getMovieList(movieSearch)

    override fun displayMovieDetailsButton(movieId: String) {
        Log.d("TEST", "button clicked $movieId")
        getMovieDetail(movieId)
    }
}

回调接口

interface SearchNavigator {
    fun openDetails()
}

在下面的片段方法中启动 ViewModel

override onActivityCreated(@Nullable final Bundle savedInstanceState){
    searchMovieFragmentViewModel = ViewModelProvider(this).get(SearchMovieFragmentViewModel::class.java)
}

我会推荐使用实时数据在 ViewModel 和 Fragment 之间创建连接,这将是更安全和正确的方法。

基于您实时触发器的触发器 openDetails data.It 禁止将您的视图 (context) 实例发送到 ViewModel,即使您包装它也是如此,因为内存泄漏的可能性很高。

但是如果您仍然想遵循这种方法,那么您应该在您的 ViewModel 中注册和注销片段实例(保留 SearchNavigator 列表)onStop()onStart()

并循环调用 openDetails