如何查看两个ArrayList是否来自同一类型

时间:2019-07-03 20:00:52

标签: android kotlin mvvm fragment viewmodel

我正在尝试使用泛型来实现viewmodel观察器,这样做是因为我要从7个不同的Fragments中收集数据,所以我不需要7个观察器。

目标

由于这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全局声明的类型相同,如果它们相等,则应将当前数组数据值赋给新的空数组

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与我声明的数组进行比较。他们应该检查 it xArray 是否都是相同类型的ArrayLists
  • 第二个错误是这个

    (活动为MainActivity).getViewModelInstance()。setData(xArray)

.setData(xArray)的红色突出显示为Required: Nothing, Found:ArrayList<Xclass>。太奇怪了,因为SharedViewModel的setData需要传递任何ArrayList。

谢谢

1 个答案:

答案 0 :(得分: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实例。之所以需要这样做,是因为类不像内联函数那样支持类型化。 此实现假定每个View都有一个静态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链接起来,以确保类型安全

它应该具有足够的功能来实现该项目的体系结构目标,如果我误解了任何内容并可以提供进一步的帮助,请告诉我。