在Kotlin中模块化以创建具有可变类型的函数 [英] Modularising to create a function with variable Types in Kotlin

查看:67
本文介绍了在Kotlin中模块化以创建具有可变类型的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在项目的许多地方都有这样的乐趣

  class ClubsViewModel():BaseViewModel(){私人var _mClubs = MutableLiveData< ArrayList< ClubFSEntity>>()...私人乐趣listenToFireStoreClubs(){mFirestore.collection(俱乐部").addSnapshotListener {快照,e->//如果有异常,我们要跳过.如果(e!= null){return @ addSnapshotListener}//如果我们在这里,就不会遇到异常如果(快照!= null){val allClubs = ArrayList< ClubFSEntity>()snapshot.documents.forEach {it.toObject(ClubFSEntity :: class.java)?. let {allClubs.add(it)}}_mClubs.value = allClubs}}}}......类ProjectsViewModel():BaseViewModel(){私人var _mProjects = MutableLiveData< ArrayList< ProjectsFSEntity>>()私人乐趣listenToFireStoreProjects(){//这里的代码类似于ClubsViewModel中类似函数中的代码.}}......打开类BaseViewModel():ViewModel(){保护的val mFirestore = Firebase.firestore保护的var mStorageReferenence:StorageReference受保护的val _networkState = MutableLiveData< NetworkState>()保护的val networkState:LiveData< NetworkState>.= _networkState//我想将此函数设为私有,以访问上述变量.内联乐趣listenToFireStoreCollection [移动到这里,我的所有其他视图模型都可以调用它]}......@包裹数据类ClubFSEntity(val title:String =",val描述:String =",val startDate:String?= null,var clubId:字符串=""):可打包 

很容易模块化 "Clubs" 参数.该文档列表中的Firebase数据将进入 ClubFSEntity 数据对象的数组列表.将Firebase快照数据添加到 allClubs 数组时,我们使用 ClubFSEntity :: class.java 进行转换./p>

我在很多地方都使用相同的代码,但只有三件事发生了变化( "Clubs" ClubFSEntity ClubFSEntity :: class.java ).我想用这三个项目作为变量来创建一个函数.

我什至都不知道要搜索什么.我已经尝试使用泛型,但到目前为止还无法实现.

如果可能的话,我也想使用泛型类.

我希望像这样初始化ViewModel:

  class ClubsFragment:Fragment(){私有val mClubsViewModel:ClubsViewModel< ClubsFSEntity>通过viewModels()} 

然后,将ViewModel定义更改为类似的内容:

  class ClubsViewModel< T>():BaseViewModel(){专用var _mClubs = MutableLiveData< List< T>>()...} 

每个视图模型都会使用自己的参数调用 listenToFirestoreCollection .

解决方案

首先让您简化初始功能:

  private var _mClubs = MutableLiveData< List< ClubFSEntity>>()私人乐趣listenToFireStoreClubs(){mFirestore.collection(俱乐部").addSnapshotListener {快照,e->//如果有异常,我们要跳过.如果(e!= null){return @ addSnapshotListener}//如果我们在这里,就不会遇到异常如果(快照!= null){_mClubs.value = snapshot.documents.mapNotNull {it.toObject(ClubFSEntity :: class.java)}}}} 

您可以像这样使它更通用:

 私人乐趣< T>listenToFireStoreCollection(collectionName:字符串,liveData:MutableLiveData< List< List>> ;,clazz:Class< T> ;,){mFirestore.collection(collectionName).addSnapshotListener {快照,e->//如果有异常,我们要跳过.如果(e!= null){return @ addSnapshotListener}//如果我们在这里,就不会遇到异常如果(快照!= null){liveData.value = snapshot.documents.mapNotNull {it.toObject(clazz)}}}} 

您还可以更进一步,并为此定义一个版本化,因此您不必每次都显式地传递 Class< T> :

 私有内联乐趣< reified T>listenToFireStoreCollection(collectionName:字符串,liveData:MutableLiveData< List< List>> ;,)= listenToFireStoreCollection(collectionName,liveData,T :: class.java) 

如果实时数据和函数位于同一类中,则还可以使该类具有通用性,如下所示:

  class FireStoreLiveData< T>(val collectionName:字符串,val clazz:Class< T> ;,){专用var _mClubs = MutableLiveData< List< ClubFSEntity>>()私人乐趣listenToFireStoreCollection(){mFirestore.collection(collectionName).addSnapshotListener {快照,e->//如果有异常,我们要跳过.如果(e!= null){return @ addSnapshotListener}//如果我们在这里,就不会遇到异常如果(快照!= null){liveData.value = snapshot.documents.mapNotNull {it.toObject(clazz)}}}}} 

但是,如果没有更多关于您打算如何从外部使用它的信息,那么很难告诉我们如何设计此类的API(目前一切都是私有的,因此使用量不多).例如,谁启动了监听器?有办法阻止它吗?等

I have a funtion like this in many places in my project

class ClubsViewModel():  BaseViewModel() {
    private var _mClubs = MutableLiveData<ArrayList<ClubFSEntity>>()
    ...

    private fun listenToFireStoreClubs() {
        mFirestore.collection("Clubs").addSnapshotListener { snapshot, e ->
            // if there is an exception we want to skip.
            if (e != null) {
                return@addSnapshotListener
            }
            // if we are here, we did not encounter an exception
            if (snapshot != null) {
                val allClubs = ArrayList<ClubFSEntity>()
                snapshot.documents.forEach {
                    it.toObject(ClubFSEntity::class.java)?.let {
        
                        allClubs.add(it)
                    }
                }
                _mClubs.value = allClubs
            }
        }
    }
}
...
...
class ProjectsViewModel():  BaseViewModel() {
    private var _mProjects = MutableLiveData<ArrayList<ProjectsFSEntity>>()

    private fun listenToFireStoreProjects() {
        //Code Here is Similar to the Code in the similar function in ClubsViewModel.
    }
}
...
...
open class BaseViewModel() : ViewModel()  {
    protected val mFirestore = Firebase.firestore
    protected var mStorageReferenence: StorageReference

    protected val _networkState = MutableLiveData<NetworkState>()
    protected val networkState: LiveData<NetworkState> = _networkState

    //I would like to make this function private to access the above variables.
    inline fun listenToFireStoreCollection[TO MOVE HERE SO THAT ALL MY OTHER VIEW MODELS CAN CALL IT]
}
...
...
@Parcelize
data class ClubFSEntity(val title: String="",
                        val description: String="",
                        val startDate: String?=null,
                        var clubId : String=""): Parcelable

It's easy to modularize out the "Clubs" parameter. The Firebase data from that document list goes to an arraylist of ClubFSEntity data objects. When adding the Firebase snapshot data to the allClubs array, we convert using ClubFSEntity::class.java.

I have many places with this same code, but only three things change ("Clubs", ClubFSEntity and ClubFSEntity::class.java). I would like to create a function with those three items as a variables.

I don't even know what to search for. I have tried to use generics but can't get it so far.

I would like to also use a generic class if possible.

I would prefer to initialize the ViewModel like so:

class ClubsFragment : Fragment() {
  private val mClubsViewModel: ClubsViewModel<ClubsFSEntity> by viewModels()

}

And, to change the ViewModel definition to something like:

class ClubsViewModel<T> () :  BaseViewModel() {

    private var _mClubs = MutableLiveData<List<T>>()
...
}

Each view model would call listenToFirestoreCollection with its own parameter(s).

解决方案

Let's first simplify your initial function:

private var _mClubs = MutableLiveData<List<ClubFSEntity>>()

private fun listenToFireStoreClubs() {
    mFirestore.collection("Clubs").addSnapshotListener { snapshot, e ->
        // if there is an exception we want to skip.
        if (e != null) {
            return@addSnapshotListener
        }
        // if we are here, we did not encounter an exception
        if (snapshot != null) {
            _mClubs.value = snapshot.documents.mapNotNull { 
                it.toObject(ClubFSEntity::class.java)
            }
        }
    }
}

You could make it more generic like this:

private fun <T> listenToFireStoreCollection(
    collectionName: String,
    liveData: MutableLiveData<List<T>>,
    clazz: Class<T>,
) {
    mFirestore.collection(collectionName).addSnapshotListener { snapshot, e ->
        // if there is an exception we want to skip.
        if (e != null) {
            return@addSnapshotListener
        }
        // if we are here, we did not encounter an exception
        if (snapshot != null) {
            liveData.value = snapshot.documents.mapNotNull { it.toObject(clazz) }
        }
    }
}

You can also go one step further and additionally define a reified version of this, so you don't have to pass in the Class<T> explicitly each time:

private inline fun <reified T> listenToFireStoreCollection(
    collectionName: String,
    liveData: MutableLiveData<List<T>>,
) = listenToFireStoreCollection(collectionName, liveData, T::class.java)

If the live data and the function are in the same class, you can also make the class generic itself like the following:

class FireStoreLiveData<T>(
    val collectionName: String,
    val clazz: Class<T>,
) {
    private var _mClubs = MutableLiveData<List<ClubFSEntity>>()

    private fun listenToFireStoreCollection() {
        mFirestore.collection(collectionName).addSnapshotListener { snapshot, e ->
            // if there is an exception we want to skip.
            if (e != null) {
                return@addSnapshotListener
            }
            // if we are here, we did not encounter an exception
            if (snapshot != null) {
                liveData.value = snapshot.documents.mapNotNull { it.toObject(clazz) }
            }
        }
    }
}

But it's hard to tell how to design the API of this class without more info about how you intend to use it from outside (everything is private right now, so not much use). For instance, who starts the listener? Is there a way to stop it? etc.

这篇关于在Kotlin中模块化以创建具有可变类型的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆