【问题标题】:Is it possible to make a global, generic function for multiple companion objects in kotlin是否可以在 kotlin 中为多个伴随对象创建一个全局通用函数
【发布时间】:2020-08-30 04:36:12
【问题描述】:

我在 Kotlin 中开发了一个应用程序,其中包含许多 Activities。大多数导航只是基本的,开始新的活动,而不是向意图传递任何东西。对于几组活动,我可能会传递标志,这在我的整个项目中也是重复的(例如,设置 intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK 的 5 个活动)。因此,如果我能找到一种方法来实现这一点,那么事情就会变得更好。

为了让事情变得更简单、更整洁,我为 Activities 创建了包含以下功能的伴随对象:

class MyActivity: AppCompatActivity() {
   companion object {
        fun startActivity(context: Context) {
            context.startActivity(
                Intent(context, MyActivity::class.java)
            )
        }
    }
...

其他类可以直接调用MyActivity.startActivity(context)

该功能非常基本,不同活动中的实现之间的唯一区别显然是MyActivity::class.java-part。所以我想知道是否可以只声明这个函数一次,并以某种方式在多个伴生对象中使用它来进行不同的活动。

现在,我知道我可以这样做:

我定义了一个具有泛型函数的对象,并像这样设置它:

object MyObject {
    inline fun <reified T: AppCompatActivity>startActivity(context: Context) {
        context.startActivity(
            Intent(context, T::class.java)
        )
    }
}

class MyActivity() : AppCompatActivity() {
    companion object {
        fun start(context: Context) = MyObject.startActivity<MyActivity>(context)
    }
}

但这似乎还是有点老套。我正在寻找的是类似于继承或接口的实现版本,以简单地添加到我的伴随对象中。比如:

companion object : MyObject<MyActivity>
// Assuming I can somehow put the generic parameter into the object declaration instead of the function or do something similar

companion object {
    import MyObject.startActivity<MyActivity>
}

第一个选项会特别有用,因为它会自动为MyActivity 设置MyObject 的多个功能。这样的事情有可能吗?

【问题讨论】:

    标签: java android kotlin


    【解决方案1】:

    Companion 对象可以从其他类继承。只需在某处进行基础实现:

    abstract class ActivityCompanion<T: Activity>(val activityClass : Class<T>) {
        fun startActivity(context: Context) {
            context.startActivity(Intent(context, activityClass))
        }
        /** rest of functions that reference activityClass **/
    }
    

    并在你的同伴中继承它:

    class MyActivity() : AppCompatActivity() {
        companion object : ActivityCompanion<MyActivity>(MyActivity::class.java)
    }
    

    这有点冗长,但这正是泛型的工作原理。

    【讨论】:

    • 这就是我要找的。快速解释为什么我选择这个答案而不是(另一个)[(@ 987654321@,尽管它几乎做同样的事情并且两者都非常好。一些活动需要通过意图传递的值并在伴随对象函数中实现它并带有额外的paraneter 和隐藏标签更加简洁。因此,使用这种方法将使整个项目更加统一,因为所有活动都可以从静态函数 startActivity 调用,并带有所有需要的参数。
    • 另外,快速补充:类不必是抽象的,它可以是open
    • 当然可以打开它,但是如果它是专门为伴随对象继承的,那么直接实例化它的目的是什么?
    • 好点。我只是去了那里,因为那是使用 java 时的“默认”。您需要在那里完成一个类才能获得 kotlin 中的默认类。但是,是的,如果它没有直接实例化,那就没有用了。
    • 我问了另一个问题,因为我对这个解决方案的外观不太满意。虽然它绝对是正确的解决方案,但有一个 easy way to make it even neater
    【解决方案2】:

    你甚至不需要伴侣,只需要一个扩展功能。

    inline fun <reified T: AppCompatActivity> Activity.startActivity() {
        startActivity(Intent(this, T::class.java))
    }
    

    如果你需要额外的配置,你可以传递一个 lambda。

    inline fun <reified T: AppCompatActivity> Activity.startActivity(intentConfiguration: Intent.() -> Unit) {
        startActivity(Intent(this, T::class.java).apply(intentConfiguration))
    }
    

    【讨论】:

    • 你不需要一个类的实例来调用它的扩展函数吗?
    • 我刚刚注意到,我什至实现了一个类似的函数,只是将类作为 KClass 类型的普通参数传递,并将扩展名赋予 Context 而不是 Activity 以使视图能够无需强制转换即可调用它。但是 lambda 在这里是一个很好的补充。好答案!!现在唯一剩下的问题是哪一个在性能方面更好。伴随或扩展。
    【解决方案3】:

    只想指出,更简洁的语法是使用Context 上的具体扩展函数来执行此操作。而且您也不必担心伴随对象。

    inline fun <reified T: Activity> Context.startActivity() = 
        startActivity(Intent(this, T::class.java))
    
    //Usage:
    someViewOrActivity.startActivity<MyActivity>()
    

    它在语义上也更有意义。一个上下文启动一个活动。 Activity 不会自行启动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多