Android LiveData - 观察 complex/nested 个对象

Android LiveData - observe complex/nested objects

我正在开发一个具有 MVVM 结构的 android 项目。我想按照推荐使用 LiveData。 在示例中,总是只有简单的对象类型,例如细绳。 但我想将更多 complex/nested 对象类型放入 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")
            })

    }
}

因此,如果 ClassC 的变量 str 更改,则应执行回调。 我正在寻找一个聪明而简单的解决方案。

我刚发现类似的 post:
此示例的深度为 1。但我正在寻找任意深度的解决方案。

我找不到解决问题的示例,这让我很怀疑。 所以我想我的方法无论如何都是错误的或不好的做法。 也许我应该寻找一种分解事物并观察简单对象的方法。

有没有人对此有解决方案或意见?

感谢您的帮助!

问题出在您创建 ViewModel 的方式上。你不能直接实例化它。如果您使用 fragment-ktx 神器,您可以这样做:

        private val model: SharedViewModel by activityViewModels()

片段有自己的生命周期。所以你应该用 viewLifeCycleOwner

替换 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 class:

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 class.

扩展了模型
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。

class MyViewModel() : ViewModel() {

    var classAObj: ClassA = ClassA()

    val myLiveData = PropertyAwareMutableLiveData<ClassA>()

    init {
        myLiveData.value = classAObj
    }

}

在 Fragment 中,我可以观察到 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 相关的每个 属性 只能通过 class InterfaceObservable 提供的界面进行更改。 这就是为什么这不是一个完美的解决方案的原因。 但也许在你的情况下是合理的。