【问题标题】:Attempt to invoke interface method 'java.lang.Object kotlin.Lazy.getValue()' on a null object reference尝试在空对象引用上调用接口方法“java.lang.Object kotlin.Lazy.getValue()”
【发布时间】:2021-10-13 16:00:21
【问题描述】:

对不起,我的愚蠢问题。

我有谷歌这个问题,但答案对我不起作用。

这是我的代码。

  data class Article(val id: Long, val title: String, val ingress: String, val image: String,
                       val dateTime: String, val tags: List<String>, val content: List<Item>, val created: Long, val changed: Long) {

        @delegate:Transient
        val formatDateString: String by lazy {
            val sdf = SimpleDateFormat("dd.MM.yyyy HH.mm")
            val date: Date = sdf.parse(dateTime)
            var time: String?
            if (date.year == Date().year) {
                time = SimpleDateFormat("dd MM,HH:mm", Locale.US).format(date)
            } else {
                time = SimpleDateFormat("dd MM yyyy,HH:mm", Locale.US).format(date)
            }
            time!!
        }

    }

当我尝试获取 formatDateString 值时,会发生上述异常。

访问formatDateString的代码如下

  override fun getCustomAdapter(): BaseQuickAdapter<CarListResponseBody.Article, BaseViewHolder> {
        return object : BaseQuickAdapter<CarListResponseBody.Article, BaseViewHolder>( R.layout.app_item_cars_list,dataList) {
            override fun convert(helper: BaseViewHolder, item: CarListResponseBody.Article) {
                helper.setText(R.id.tv_ingress,item.ingress)
                helper.setText(R.id.tv_date_time,item.formatDateString)
                helper.setText(R.id.tv_title,item.title)
                ImageLoadUtil.loadImgToView(context,item.image,helper.getView(R.id.img_car),null)
            }
        }
    }

我认为这个异常是由 Gson 引起的,但我不知道为什么

【问题讨论】:

    标签: android kotlin


    【解决方案1】:

    我不是专业人士,但我想告诉你我的发现。让我们创建一个简单的类来看看 Kotlin 中的委托是如何工作的。以防万一,我正在使用 Kotlin 1.3.70。这是我们的简单类:

    class Test {
        val test by lazy { "test" }
    }
    

    在 Idea 或 Android Studio 中,您可以检查字节码。但至少对我来说,阅读 JVM 字节码非常困难 :) 让我们将其转换为类似于 Java 的内容:

    ...
    public final class Test {
       @NotNull
       private final Lazy test$delegate;
    
       @NotNull
       public final String getTest() {
          Lazy var1 = this.test$delegate;
          Object var3 = null;
          boolean var4 = false;
          return (String)var1.getValue();
       }
    
       public Test() {
          this.test$delegate = LazyKt.lazy((Function0)null.INSTANCE);
       }
    }
    ...
    

    如您所见,Kotlin 为 lazy 委托创建了一个特殊字段,该字段在构造函数中初始化。问题是 Gson 使用 UnsafeAllocator 并且不调用构造函数。你可以阅读更多关于它的信息,例如here。因此,当您反序列化您的 Article 对象时,它包含 null 而不是适当的 lazy 委托。这就是为什么在尝试调用此 del 时出现空指针异常的原因

    【讨论】:

    • 谢谢,您有什么想法可以解决这个问题吗?或formatDateString的更好解决方案
    • 作为一个快速解决方案,您可以编写一个扩展函数。但是,如果您要经常调用formatDateString,它会导致一些开销。此外,您可以使用带有formatDateString 的包装器。但是使用起来不会很方便。也许你可以考虑从 Gson 迁移到 Moshi 或 kotlinx.serialization,但这是一个相当大的工作量
    【解决方案2】:

    我在使用Gson 未填充的属性时遇到了同样的问题。我使用了以下解决方法

    var myString: String? = null
        get() {
            if (field == null) {
                field = "myInitialValue"
            }
            return field
        }
    

    我猜在你的例子中是这样的:

    val formatDateString: String? = null
        get() {
            if (field == null) {
                val sdf = SimpleDateFormat("dd.MM.yyyy HH.mm")
                val date: Date = sdf.parse(dateTime)
                var time: String?
                if (date.year == Date().year) {
                    time = SimpleDateFormat("dd MM,HH:mm", Locale.US).format(date)
                } else {
                    time = SimpleDateFormat("dd MM yyyy,HH:mm", Locale.US).format(date)
                }
                field = time!!
            }
            return field
        }
            
    

    我不知道这是否是不好的做法,但它似乎对我有用

    【讨论】:

      【解决方案3】:

      尝试在数据中编写方法时,我也遇到了异常“java.lang.NullPointerException:尝试在空对象引用上调用接口方法'java.lang.Object kotlin.Lazy.getValue()'”类(用于 Gson)。

      data class SomeResponse(
          override val success: Int,
          override val errors: ErrorsResponse?
      ) {
      
          data class ErrorsResponse(
              @SerializedName("id")
              val id: Int?
          ) {
      
              private val errorUtil by lazy { ErrorUtil() }
      
              fun getErrorMessage(): String? =
                  errorUtil.getErrorMessage(id)
          }
      }
      

      不管是errorUtil by lazy { ErrorUtil() } 还是errorUtil = ErrorUtil(),当我们调用getErrorMessage 时都会是null。不会这么快初始化的。

      要克服这个问题,请在调用时初始化变量。

      private var errorUtil: ErrorUtil? = null
      
      fun getErrorMessage(): String? {
          if (errorUtil == null) errorUtil = ErrorUtil()
          return errorUtil!!.getErrorMessage(id)
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-01
        • 2023-03-25
        • 1970-01-01
        • 2016-06-28
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        • 1970-01-01
        相关资源
        最近更新 更多