代码之家  ›  专栏  ›  技术社区  ›  James Jordan Taylor

未调用LiveData观察者

  •  24
  • James Jordan Taylor  · 技术社区  · 6 年前

    我有个活动, TabBarActivity 承载着一个片段, EquipmentRecyclerViewFragment . 片段接收到LiveData回调,但活动没有(如调试模式中的断点所证明的)。奇怪的是,如果调用ViewModel的 initData 方法以下是上述组件的相关部分:

    选项卡活动

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initVM()
        setContentView(R.layout.activity_nav)
        val equipmentRecyclerViewFragment = EquipmentRecyclerViewFragment()
        supportFragmentManager
                .beginTransaction()
                .replace(R.id.frameLayout, equipmentRecyclerViewFragment, equipmentRecyclerViewFragment.TAG)
                .commit()
        navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
    
    }
    
    var eVM : EquipmentViewModel? = null
    private fun initVM() {
        eVM = ViewModelProviders.of(this).get(EquipmentViewModel::class.java)
        eVM?.let { lifecycle.addObserver(it) } //Add ViewModel as an observer of this fragment's lifecycle
        eVM?.equipment?.observe(this, loadingObserver)//        eVM?.initData() //TODO: Not calling this causes Activity to never receive the observed ∆
    }
    val loadingObserver = Observer<List<Gun>> { equipment ->
        ...}
    

    设备回收服务碎片

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        columnCount = 2
        initVM()
    }
    
    //MARK: ViewModel Methods
    var eVM : EquipmentViewModel? = null
    private fun initVM() {
        eVM = ViewModelProviders.of(this).get(EquipmentViewModel::class.java)
        eVM?.let { lifecycle.addObserver(it) } //Add ViewModel as an observer of this fragment's lifecycle
        eVM?.equipment?.observe(this, equipmentObserver)
        eVM?.initData()
    }
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_equipment_list, container, false)
        if (view is RecyclerView) { // Set the adapter
            val context = view.getContext()
            view.layoutManager = GridLayoutManager(context, columnCount)
            view.adapter = adapter
        }
        return view
    }
    

    设备视图模型

    class EquipmentViewModel(application: Application) : AndroidViewModel(application), LifecycleObserver {
    var equipment = MutableLiveData<List<Gun>>()
    var isLoading = MutableLiveData<Boolean>()
    
    fun initData() {
        isLoading.setValue(true)
        thread { Thread.sleep(5000) //Simulates async network call
            var gunList = ArrayList<Gun>()
            for (i in 0..100){
                gunList.add(Gun("Gun "+i.toString()))
            }
            equipment.postValue(gunList)
            isLoading.postValue(false)
        }
    }
    

    最终目的是让活动只观察 isLoading MutableLiveData boolean,但由于这不起作用,我改变了活动,只观察设备的LiveData,以尽量减少变量的数量。

    5 回复  |  直到 6 年前
        1
  •  42
  •   Pavel Poley    3 年前

    获取相同的引用 ViewModel 您的 Activity 你需要通过同样的考试 活动 实例,您应该使用 ViewModelProviders.of(getActivity) . 当你经过时 this 作为参数,您将收到 视图模型 与您的 Fragment .

    有两种重载方法:

    ViewModelProvider.of(Fragment fragment)
    
    ViewModelProvider.of(FragmentActivity activity)
    

    有关详细信息 Share data between fragments

        2
  •  3
  •   iamkdblue    4 年前

    我把这个代码放在 onActivityCreated 片段,不要低估getActivity;)

    if (activity != null) {            
         globalViewModel = ViewModelProvider(activity!!).get(GlobalViewModel::class.java)
        }
    
    
    globalViewModel.onStop.observe(viewLifecycleOwner, Observer { status ->
                Log.d("Parent Viewmodel", status.toString())
            })
    

    这段代码帮助我监听片段中的父视图模型更改。

        3
  •  2
  •   Cenker Canbulut    2 年前

    对于那些对SharedViewModel的定义与让两个片段使用一个视图模型感到困惑的人:

    SharedViewModel用于共享“数据”(假设创建了两个新实例,并将视图模型中的数据发送到两个片段),其中它不用于可观察对象,因为可观察对象寻找“相同”实例来执行操作。这意味着您需要为两个片段创建一个viewmodel实例。

    IMO:谷歌应该在他们的文档中提到这一点,因为我自己认为,在引擎盖下,它们是基本上不存在的同一个实例,现在它实际上是有意义的。

    编辑: Kotlin溶液: 11/25/2021

    在您的活动中-> val viewModel : YourViewModel by viewModels()

    在片段1中->

    val fragmentViewModel =
                    ViewModelProvider(requireActivity() as YourActivity)[YourViewModel::class.java]
    

    在片段2中->

    val fragmentViewModel=
    ViewModelProvider(requireActivity()作为您的活动)[您的ViewModel::class.java]
    

    这样,两个片段共享一个Activity viewmodel实例,两个片段都可以使用监听器来观察它们之间的更改。

        4
  •  1
  •   Manisha    3 年前

    创建片段而不是获取viewModel对象时 viewModels() 从中获取 activityViewModels()

    import androidx.fragment.app.activityViewModels
    
    class WeatherFragment : Fragment(R.layout.fragment_weather) {
    
        private lateinit var binding: FragmentWeatherBinding
        private val viewModel: WeatherViewModel by activityViewModels() // Do not use viewModels()
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
            binding = FragmentWeatherBinding.inflate(inflater, container, false)
    
            binding.viewModel = viewModel
    
            // Observing for testing & Logging
            viewModel.cityName.observe(viewLifecycleOwner, Observer {
                Log.d(TAG, "onCreateView() | City name changed $it")
            })
            return binding.root
        }
    }
    
        5
  •  0
  •   canerkaseler    3 年前

    Kotlin答案

    如果正在使用,请删除函数中的这两点:

    1. =viewModelScope。启动{}