首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >Android + Kotlin + Hilt:注入静态方法类

Android + Kotlin + Hilt:注入静态方法类
EN

Stack Overflow用户
提问于 2022-07-30 13:53:41
回答 1查看 455关注 0票数 1

我不太清楚向静态方法助手类(比如自定义类)注入的最佳方法是什么。

我对Kotlin有点陌生,正如我所了解的,我们可以通过两种方式静态地访问一个方法:

  1. 对象类。
  2. 类+同伴对象。

首先,我不确定哪一个是最推荐的(如果有关于此的最佳实践),但是当需要将依赖项注入静态方法类时,我的“问题”就出现了。

让我们来举一个简单的例子:

我有一个名为AWUtils的静态方法类(虽然还没有决定它应该是对象类还是有伴生对象的类,这很可能取决于推荐的注入机制),接下来的方法如下:

代码语言:javascript
运行
复制
fun setAmpersand2Yellow(text2Replace: String, target: String): String {
    return text2Replace.replace(
        target, "<span style=\"color:" +
                app.drawerFooterColor + ";\">" + target + "</span>"
    )
}

在这里,app是我的AppSettings类的实例,它保存了所有的应用程序配置,所以,正如您所看到的,setAmpersand2Yellow需要AppSettings,当然,我不会以任何方式将它作为参数传递,因此它是AWUtils依赖的。

为静态方法使用AWUtils作为伴随对象的类,据我所知,我不能直接将AppSettings注入公司对象(至少我不能进行构造函数注入,如果我错了请告诉我),如果我注入伙伴对象父类(AWUtils)构造函数,那么我不知道如何从伙伴对象本身(子构造器)访问这些依赖项。

如果我在AWUtils中使用字段注入作为类,那么它会比后发字段更抱怨没有初始化,而且我不知道如何处理这个问题,因为据我所知,延迟字段是在onCreate中初始化的,这在这类类中并不存在。

另一种可能是在调用方法之前使用带有字段的对象并以静态方式设置调用方的依赖项值,例如:

代码语言:javascript
运行
复制
object AWUtils {

    var app: AppSettings? = null

    fun setAmpersand2Yellow(text2Replace: String, target: String): String {
        return text2Replace.replace(
            target, "<span style=\"color:" +
                    app.drawerFooterColor + ";\">" + target + "</span>"
        )
    }
}

@AndroidEntryPoint
class OtherClass 
@Inject constructor(private val app: AppSettings) {
    
    fun AnyFunction() {
        var mystr = "whatever"
        AWUtils.app = app
        var yellowStr = AWUtils.setAmpersand2Yellow(myStr)
    }
}

最后,我不确定如何向静态方法类提供依赖关系,以及应该选择哪种形式的“静态”类。

编辑1:

除了我的ApSettings类之外,我还需要一个上下文,例如在下一个isTablet方法中:

代码语言:javascript
运行
复制
val isTablet: String
    get() {
        return ((context.resources.configuration.screenLayout
                and Configuration.SCREENLAYOUT_SIZE_MASK)
                >= Configuration.SCREENLAYOUT_SIZE_LARGE)
    }

最后,我需要一个上下文和我的AppSettings (或任何其他自定义类)被注入到一个带有静态方法的类中。

编辑2:

我可以(从活动中)做:

代码语言:javascript
运行
复制
AWUtils.context = this
AWUtils.app = app
var isTablet = AWUtils.isTablet

而且它可以工作,但是需要为两个字段(或更多的字段)分配值,每次我需要调用静态方法时,我更希望以任何方式注入字段。

这就是依赖注入的目的,不是吗?

编辑3:我开始对Hilt感到厌烦了,我们应该创造的东西是为了简化我们的生活,只会使我们的编程生活变得更加复杂。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-30 21:58:34

正如您在注释中所阐明的那样,您希望您的utils类可以轻松地通过代码库访问,因此这个答案将集中在这一点和您最初的问题上。

我对Kotlin有点陌生,正如我所了解的,我们可以通过两种方式静态地访问一个方法: object类或class +伴侣对象。

科特林没有Java风格的静力学。其背后的一个理由是鼓励更可维护的编码实践。静态方法和静态类也是测试代码的噩梦。

在Kotlin中,您可以使用一个对象(但是类+伙伴对象将以同样的方式工作)

代码语言:javascript
运行
复制
object AWUtils {
    lateinit var appContext: Context
    lateinit var appSettings: AppSettings

    fun initialize(
        appContext: Context,
        appSettings: AppSettings,
        // more dependencies go here
    ) {
        this.appContext = appContext
        this.appSettings = appSettings
        // and initialize them here
    }

    val isTablet: Boolean
        get() = ((appContext.resources.configuration.screenLayout
                and Configuration.SCREENLAYOUT_SIZE_MASK)
                >= Configuration.SCREENLAYOUT_SIZE_LARGE)


    fun setAmpersand2Yellow(text2Replace: String, target: String): String {
        return text2Replace.replace(
            target, "<span style=\"color:" +
                    appSettings.drawerFooterColor + ";\">" + target + "</span>"
        )
    }
}

由于这个对象应该可以在整个应用程序中访问,所以应该尽快初始化它,因此在Application.onCreate中是如此。

代码语言:javascript
运行
复制
@HiltAndroidApp
class Application : android.app.Application() {
    // you can inject other application-wide dependencies here
    // @Inject
    // lateinit var someOtherDependency: SomeOtherDependency

    override fun onCreate() {
        super.onCreate()

        // initialize the utils singleton object with dependencies
        AWUtils.initialize(applicationContext, AppSettings())
    }

现在,在应用程序代码中的任何地方,您都可以使用AWUtilsAppSettings

代码语言:javascript
运行
复制
class OtherClass { // no need to inject AppSettings anymore
    
    fun anyFunction() {
        val mystr = "whatever"
        val yellowStr = AWUtils.setAmpersand2Yellow(myStr)

        // This also works
        if (AWUtils.isTablet) {
            // and this as well
            val color = AWUtils.appSettings.drawerFooterColor
        }        
    }
}

Kotlin中还有另一种编写助手/util函数的方法,称为扩展函数

您的isTablet检查可以编写为如下扩展函数

代码语言:javascript
运行
复制
// This isTablet() can be called on any Configuration instance
// The this. part can also be omitted
fun Configuration.isTablet() = ((this.screenLayout
        and Configuration.SCREENLAYOUT_SIZE_MASK)
        >= Configuration.SCREENLAYOUT_SIZE_LARGE)

// This isTablet() can be called on any Resources instance 
fun Resources.isTablet() = configuration.isTablet()

// This isTablet() can be called on any Context instance
fun Context.isTablet() = resources.isTablet()

有了上述扩展函数之后,AWUtils内部的实现将简化为

代码语言:javascript
运行
复制
    val isTablet: Boolean
        get() = appContext.isTablet()

在(或引用)实现Context的任何类中,例如ApplicationActivityService等,您可以简单地调用isTablet()

代码语言:javascript
运行
复制
class SomeActivity : Activity() {
    fun someFunction() {
        if (isTablet()) {
            // ...
        }
    }
}

在其他以某种方式可用ContextResources的地方,您可以简单地调用resources.isTablet()

代码语言:javascript
运行
复制
class SomeFragment : Fragment() {
    fun someFunction() {
        if (resources.isTablet()) {
            // ...
        }
    }
}

编辑3:我开始对Hilt感到厌烦了,我们应该创造的东西是为了简化我们的生活,只会使我们的编程生活变得更加复杂。

是的,希尔特专注于构造函数注入,并且只能在非常有限的情况下,在非常有限的情况下,只在带有@AndroidEntryPoint注解的Android类中,以及在用@HiltAndroidApp注释时在类内扩展Application类。

@AndroidEntryPoint文档

标记一个Android组件类,以便使用标准的Hilt组件进行注入。目前,这支持活动、片段、视图、服务和广播接收器。

如果您觉得需要大量的字段注入,因为您正在使用Kotlin中的“静态”-like对象,请考虑在下一个项目中使用Koin而不是Hilt。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73176180

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档