如何解决Android LiveData-观察复杂/嵌套的对象
我正在使用MVVM结构进行android项目。我想按建议使用LiveData。
在样本中总是只有简单的对象类型,例如串。
但我想将一个更复杂/嵌套的对象类型放入LiveData。
例如这样的对象结构:
class ClassA {
private var testVarB = ClassB()
fun getTestVarB(): ClassB {
return this.testVarB
}
fun setTestVarB(classB: ClassB) {
this.testVarB = classB
}
fun setTxt(str: String) {
this.testVarB.getTestVarC().setStr(str)
}
}
class ClassB {
private var testVarC = ClassC()
fun getTestVarC(): ClassC {
return this.testVarC
}
fun setTestVarB(classC: ClassC) {
this.testVarC = classC
}
}
class ClassC {
private var str: String = "class C"
fun getStr(): String {
return this.str
}
fun setStr(str: String) {
if (str != this.str) {
this.str = str
}
}
}
我的ViewModel看起来像这样:
class MyViewModel : ViewModel() {
var classAObj= ClassA()
private var _obj: MutableLiveData<ClassA> = MutableLiveData()
val myLiveData: LiveData<ClassA> = _obj
init {
_obj.value = classAObj
}
}
并且在片段中观察到了LiveDataObject:
class FirstFragment : Fragment() {
private var viewModel = MyViewModel()
override fun onCreateView(
inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?
): View? {
...
}
override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
super.onViewCreated(view,savedInstanceState)
viewModel.myLiveData.observe(
requireActivity(),Observer<ClassA>() {
// should get fired!
Log.d("TAG","update view")
})
}
}
因此,如果str
的变量ClassC
发生更改,则应执行回调。
我正在寻找一种智能,简单的解决方案。
我刚发现类似的帖子:
LiveData update on object field change
该示例的深度为1。但是我正在寻找一个任意深度的解决方案。
我找不到解决问题的方法的事实,这使我感到怀疑。 所以我想我的方法无论如何都是错误的或不良的做法。 也许我应该寻找一种分解事物并观察简单对象的方法。
有人对此有解决方案或意见吗?
感谢您的帮助!
解决方法
问题出在创建ViewModel的方式上。您不能直接实例化它。如果您使用fragment-ktx工件,则可以这样:
private val model: SharedViewModel by activityViewModels()
该片段具有自己的生命周期。因此,您应该将viewActivCycleOwner替换为requireActivity()
viewModel.myLiveData.observe(
viewLifeCycleOwner,Observer<ClassA>() {
// should get fired!
Log.d("TAG","update view")
})
此处提供更多信息:https://developer.android.com/topic/libraries/architecture/viewmodel#sharing
,这是我已经解决的解决方案:
我正在从此处使用PropertyAwareMutableLiveData类:LiveData update on object field change
class PropertyAwareMutableLiveData<T : BaseObservable> : MutableLiveData<T>() {
private val callback = object : Observable.OnPropertyChangedCallback() {
override fun onPropertyChanged(sender: Observable?,propertyId: Int) {
value = value
}
}
override fun setValue(value: T?) {
super.setValue(value)
value?.addOnPropertyChangedCallback(callback)
}
}
基于此,我使用iterface / abstract类扩展了模型。
abstract class InterfaceObservable : BaseObservable() {
open fun setNewString(s: String) {
notifyPropertyChanged(BR.str)
}
}
class ClassA : InterfaceObservable() {
private var testVarB = ClassB()
fun getTestVarB(): ClassB {
return this.testVarB
}
fun setTestVarB(classB: ClassB) {
this.testVarB = classB
}
override fun setNewString(s: String) {
super.setNewString(s)
this.testVarB.setNewString(s)
}
}
class ClassB {
private var testVarC = ClassC()
fun getTestVarC(): ClassC {
return this.testVarC
}
fun setTestVarB(classC: ClassC) {
this.testVarC = classC
}
fun setNewString(s: String) {
this.testVarC.setStr(s)
}
}
class ClassC : BaseObservable() {
@Bindable
private var str: String = "class C"
fun getStr(): String {
return this.str
}
fun setStr(str: String) {
if (str != this.str) {
this.str = str
}
}
}
在ViewModel中,我使用PropertyAwareMutableLiveData类。
class MyViewModel() : ViewModel() {
var classAObj: ClassA = ClassA()
val myLiveData = PropertyAwareMutableLiveData<ClassA>()
init {
myLiveData.value = classAObj
}
}
在“片段”中,我可以观察LiveData对象。如果ClassC.str更改,观察者将得到通知,并可以更改UI。
class MyFragment : Fragment() {
private lateinit var viewModel: MyViewModel
override fun onViewCreated(view: View,savedInstanceState: Bundle?) {
super.onViewCreated(view,savedInstanceState)
viewModel.myLiveData.observe(
viewLifecycleOwner,Observer<ClassA> {
Log.d("TAG","change your UI here")
})
}
}
与UI相关的每个属性都只能在类InterfaceObservable
给定的接口上进行更改。
这就是为什么这不是一个完美的解决方案的原因。
但这也许对您来说是合理的。