【问题标题】:StackOverflowError using Singleton in Kotlin在 Kotlin 中使用 Singleton 的 StackOverflowError
【发布时间】:2016-08-01 23:50:38
【问题描述】:

谁能告诉我,为什么我使用这个 Kotlin 类会得到 java.lang.StackOverflowError?第 41 行是if (instance == null) {

class TokenHelper protected constructor() {
    var token: String? = null
    var appId: String? = null
    var installationId: String? = null
    var userId: String? = null

    companion object {
        var instance: TokenHelper? = null
            get() {
                if (instance == null) {
                    instance = TokenHelper()
                }
                return instance
            }
    }
}

堆栈跟踪:

04-11 19:07:42.188 16142-16142/com.foo.bar.debug E/AndroidRuntime: FATAL EXCEPTION: main
  Process: com.foo.bar.debug, PID: 16142
  java.lang.StackOverflowError: stack size 8MB
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:0)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
      at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
    at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: exClass=java.lang.StackOverflowError
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: exMsg=stack size 8MB
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: file=TokenHelper.kt
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: class=com.foo.bar.helper.TokenHelper$Companion
04-11 19:07:42.271 16142-16142/com.foo.bar.debug D/Error: ERR: method=getInstance line=0
04-11 19:07:42.282 16142-16142/com.foo.bar.debug D/Error: ERR: stack=java.lang.StackOverflowError: stack size 8MB
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:0)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
  at com.foo.bar.helper.TokenHelper$Companion.getInstance(TokenHelper.kt:41)
    at com.foo.bar.helper.TokenHelper$Companion.getInstance(
04-11 19:07:42.283 16142-16142/com.foo.bar.debug D/Error: ERR: TOTAL BYTES WRITTEN: 880768
04-11 19:07:45.527 16142-16142/com.foo.bar.debug D/Process: killProcess, pid=16142
04-11 19:07:45.528 16142-16142/com.foo.bar.debug D/Process: com.android.internal.os.RuntimeInit$UncaughtHandler.uncaughtException:113 java.lang.ThreadGroup.uncaughtException:693 java.lang.ThreadGroup.uncaughtException:690 

Android Studio 2.0、Kotlin 1.0.1-2

【问题讨论】:

  • 如果你想让TokenHelper 成为单例,只需将其声明为object 并一起删除instance 属性。编译器将为您处理样板文件。
  • @KirillRakhman 我相信您的评论是真正的答案。现在它是一个对象,我像 TokenHelper.INSTANCE.getToken() 一样使用它(在 Java 类中)。
  • 我将其添加为答案。

标签: android kotlin jetbrains-ide kotlin-android-extensions


【解决方案1】:

改编自对原始答案的评论:

在 Kotlin 中,您不需要所有样板来声明单例。声明你的班级时,只需将其设为object,如下所示:

object TokenHelper {
    var token: String? = null
    var appId: String? = null
    var installationId: String? = null
    var userId: String? = null
}

然后按如下方式访问它:TokenHelper.token 或来自 Java 的TokenHelper.INSTANCE.getToken()

【讨论】:

    【解决方案2】:

    您正在递归调用instance getter 方法。更改您的吸气剂定义以改用field

    var instance: TokenHelper? = null
        get() {
            if (field == null) {
                field = TokenHelper()
            }
            return field
        }
    

    文档的相关摘录:

    Kotlin 中的类不能有字段。然而,有时它是 使用自定义访问器时必须有一个支持字段。为了 为了这些目的,Kotlin 提供了一个自动支持字段,它可以 使用字段标识符访问:

    var counter = 0 // the initializer value is written directly to the backing field
      set(value) {
        if (value >= 0)
          field = value
      }
    

    字段标识符只能在属性的访问器中使用。

    【讨论】:

    • 谢谢。我刚刚搜索了“Kotlin Singleton”并提出了这个解决方案 (medium.com/@adinugroho/…):private object Holder { val INSTANCE = TokenHelper() } companion object { val instance: TokenHelper by lazy { Holder.INSTANCE } } 你认为这也符合 Kotlin 吗?顺便说一句:我的初始代码是在提出“转换为 Kotlin”命令时由 AS 生成的。
    • 是的,它是合规的。 IDE 转换器适用于非常简单的情况 - 使用前应始终检查其输出。
    • 救了我!谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-08
    • 2018-08-02
    • 2022-01-13
    • 2011-04-01
    相关资源
    最近更新 更多