【问题标题】:How to see if two ArrayLists are from the same Type如何查看两个 ArrayLists 是否来自同一类型
【发布时间】:2019-07-03 20:00:52
【问题描述】:

我正在尝试使用泛型实现 viewmodel 观察者,这样做我不需要 7 个观察者,因为我从 7 个不同的 Fragment 收集数据。

目标

由于这 7 个片段将数据存储在不同的 ArrayLists 类型中,因此我创建了一个通用 ViewModel 类来将该数据传递给我的主 Activity(片段持有者)

SharedViewModel

class SharedViewModel<T>: ViewModel() {

    var data:MutableLiveData<ArrayList<T>> = MutableLiveData()

    fun setData(anyData:ArrayList<T>){
        data.value = anyData
    }

    val getAnyData:LiveData<ArrayList<T>>
    get() = data

}

这样做,我只需在每个片段内设置任何数组数据类型

  (activity as MainActivity).getViewModelInstance().setData(xArray)

在我的 MainActivity 中,我想检查 xArray 数据类型是否与在 MainActivity 全局声明的类型相同,如果它们相等,则应将当前数组数据值分配给新的空数组

主要活动

private var xArray = arrayListOf<Xclass>()

    onCreate()
    ...

     viewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
            viewModel.getAnyData.observe(this, Observer { it:ArrayList<out Any?>
                if(it == xArray){
                    xArray.addAll(it)
                }
            })

目的

如果我这样做,我会阻止在我的 MainActivity 中为每个片段执行 7 个观察者,而只需使用不同的数组类型更新一个观察者,比较它们并重新签名它们将减少代码,并且对我的架构来说更容易。

问题

有两个问题

  • 提到的第一个是如何将观察者在我的 MainActivity 中获得的当前 ArrayList 与我声明的数组进行比较。他们应该检查 itxArray 是否是同一类型的ArrayLists
  • 第二个错误是这个

    (作为 MainActivity 的活动).getViewModelInstance().setData(xArray)

.setData(xArray),其突出显示的红色表示Required: Nothing, Found:ArrayList&lt;Xclass&gt;。这很奇怪,因为 SharedViewModel 的 setData 需要传递 Any ArrayList。

谢谢

【问题讨论】:

  • 现在最重要的是检查数组是否来自同一类型,我找到了 isArrayOf 方法但它只比较数组的内容而不是定义的类型

标签: android kotlin mvvm fragment viewmodel


【解决方案1】:

经过一番思考,我想出了一个简单但不会失败的方法,它利用类类型与泛型结合来实现全部功能。我相信这会以您希望的方式解决您的可重用性问题并删除多余的侦听器。

class SharedViewModel <T> (val listType: Class<T>) : ViewModel() {

    var data: MutableLiveData<ArrayList<T>> = MutableLiveData()

    fun setData(anyData: ArrayList<T>) {

        data.value = anyData
    }

    inline fun <reified K> isOfInternalType(checkType: Class<K>): Boolean = checkType.typeName == listType.typeName
}

通过viewModel设置数组数据

class Xclass
var xArray = arrayListOf<Xclass>()

val viewModel = (activity as MainActivity).getViewModelInstance()
if (viewModel.isOfInternalType(Xclass::class.java) {
    viewModel.setData(Xclass)
}

主要活动

class Xclass
private var xArray = arrayListOf<Xclass>()

onCreate()
...

viewModel = ViewModelProviders.of(this).get(SharedViewModel::class.java)
viewModel.getAnyData.observe(this, Observer { data: ArrayList<out Any?> ->
    if (viewModel.isOfInternalType(Xclass::class.java) {
        xArray.addAll(it)
    }
})

其他示例使用

// Examples of use cases outside of initial question

class ViewOne: SharedView<ClassOne>(ClassOne::class.java)
val testClass = ViewOne()

ViewOne().isOfInternalType(ClassTwo::class.java) // returns false
ViewOne().isOfInternalType(testClass::class.java) // Error: Cannot use captured type as reified parameter

ViewOne().isOfInternalType(ClassOne::class.java) // returns true
ViewOne().isOfInternalType(ClassOne().javaClass) // returns true
testClass.isOfInternalType(ClassOne::class.java) // returns true

我所做的是在实例化时创建了一个 View 的 listType 实例。这需要完成,因为类不像内联函数那样支持类型具体化。 此实现假定每个视图都有一个静态 listType... 这可以修改为类似于以下内容:

class SharedViewModel(listType: Class<*>) : ViewModel() {
    var listType: Class<*> = listType
    private set(value) {
        field = value
    }

    fun setData(anyData: ArrayList<*>) {
        data.value = anyData
    }

    fun updateListType(newType: Class<*>) {
        listType = newType
    }

    inline fun <reified K> isOfInternalType(checkType: Class<K>): Boolean =
        checkType.typeName == listType.typeName
}

变量类型 SharedViewModel 示例

class ViewOne: SharedView(ClassOne::class.java)

val testClass = ViewOne()

testClass.isOfInternalType(ClassOne::class.java) // returns true

testClass.updateListType(ClassTwo::class.java)

testClass.isOfInternalType(ClassOne::class.java)  // returns false now
testClass.isOfInternalType(ClassTwo::class.java)  // returns true now

通过变量类型的这种实现,您可能希望将isOfInternalTypesetData 链接起来,以确保您的类型安全

这应该有足够的功能让你能够完成你的这个项目的架构目标,如果我有什么误解,请告诉我,并可以提供进一步的帮助。

【讨论】:

  • 嗨,本杰明,首先,非常感谢您抽出宝贵时间做出这个很棒的答案。其次,因为我在我的活动中实例化了我的 SharedViewModel 而没有扩展它,我怎么能像你在这里做的一样呢?因为如果我扩展您的抽象 SharedView ,我将失去所有活动功能
  • @CoffeeBreak 啊,我应该更清楚。我正在编辑我的答案。抽象类将扩展 ViewModel——我在示例中删除了它,这样我就可以快速测试我正在编写的代码。因此,如果您需要实现 ViewModel 功能,它将在抽象类 SharedView 中完成——而且该类不需要特别抽象,它也可以作为一个普通类工作
  • 当您提到 ViewOne 和 ClassOne 时,您的意思是 ViewOne、片段 1 和 ClassOne 是什么?
  • 请记住,我只需要从每个片段中执行 .setValue(array) 并在我的主视图中检查这些对象是否相等
  • 我将更新我的命名以使您的示例更有意义
猜你喜欢
  • 1970-01-01
  • 2016-01-24
  • 2013-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-26
  • 2012-04-29
  • 1970-01-01
相关资源
最近更新 更多