Android Fragments ViewModel和LiveData在已销毁的片段中持续存在,导致NPE第二次访问片段

ff29svar  于 9个月前  发布在  Android
关注(0)|答案(1)|浏览(89)

我有一个ViewModel,它使用Disposable从单个RxJava Observable中检索数据。

internal class MyViewModel: ViewModel() {
   internal var disposable: Disposable? = null

   internal var myMutableLiveData= MutableLiveData<List<...>?>()

   internal fun getData(myParam: String) {
       disposable = (ApiServiceClient.createApiService().getDataFromAPI(
           myParam
    )).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
        { response -> myMutableLiveData.postValue(response) },{ myMutableLiveData.postValue(null) }
    )
   }
}

在我的片段中,我观察onViewCreated中的myMutableLiveData以检索数据。在片段的onDestroyView中,我释放资源。
内部类MyFragment:String(){

private var _binding: FragmentMyBinding? = null
private val binding get() = _binding!!
private val viewModel: MyViewModel by viewModels()

override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View {
    _binding = FragmentMyBinding.inflate(inflater, container, false)
    return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    viewModel.myMutableLiveData.observe((context as MyActivity)) { data ->
        if (data == null) // Error
        else {
    // Success, use binding
        }
    }
    viewModel.getData("text")
}

override fun onDestroyView() {
    super.onDestroyView()
    _binding = null
    viewModel.disposable.dispose()
}

}
我第一次选择片段MyFragment时,一切正常。然而,当我切换到同一Activity中的另一个片段时(MyFragment通过onDestroyView、onDestroy和onDetach),然后我返回MyFragment(onCreate、onDestroyView、onViewCreated),似乎ViewModel仍然在那里,导致观察在绑定类被重构之前发生,从而导致NullPointerException。
管理Fragment-ViewModel-Disposable生命周期的正确方法是什么?

piv4azn7

piv4azn71#

虽然可能有一些特殊的用例使用Activity作为观察者的所有者,但您的情况似乎不是这样。

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    viewModel.myLiveData.observe(viewLifecycleOwner) { data ->
        if (data == null) {
            // Error
        } else {
            // Success, use binding
        }
    }
    viewModel.getData("text")
}

另外,公开可变的LiveData也不是一个好主意。

private val _myMutableLiveData = MutableLiveData<List<...>?>()
internal val myLiveData = _myMutableLiveData.asLiveData()

需要注意的是,如果LiveData没有被观察到/还没有启动,它可能会返回null

相关问题