我的片段中有一个回调方法,它是从它的ViewModel中调用的。它初始化片段的OnCreateView()
方法中的变量,但当ViewModel调用它来使用它时,它为null。
我在想,这可能与虚拟机以某种方式被重新创建有关?我好像就是想不通。
以下是VM如何驱动UI的答案。他们提供了谷歌正在创建的回调接口的示例(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基于实时数据中的触发器。禁止将视图(context
(实例发送到ViewModel,即使对其进行包装也是如此,因为内存泄漏的可能性很高。
但是,如果您仍然想遵循这种方法,那么您应该在ViewModel中注册和注销片段实例(保留一个SearchNavigator列表(onStop()
和onStart()
。
并通过它们循环调用openDetails