Android LiveData-观察复杂/嵌套的对象

如何解决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给定的接口上进行更改。 这就是为什么这不是一个完美的解决方案的原因。 但这也许对您来说是合理的。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?