首页 > 解决方案 > 除非我使用显式范围,否则为什么 Kotlin Synthetic 为 Null

问题描述

所以我在这里有一些代码在 1 个月前可以工作。

profile_clickable.throttleClicks {
  logger.logEvent(PageTags.MENU_PROFILE_NAV)
  edit_picture_button.visibility = View.GONE
  ProfileActivity.start(this@HomeMenuActivity, avatar.transition(), username.transition())
}

这段代码现在失败,NPE on edit_picture_button, avatar,username都是 Kotlin 合成的。

当我对这些项目中的每一个(见下文)添加一个显式调用时,它突然起作用了。

profile_clickable.throttleClicks {
  logger.logEvent(PageTags.MENU_PROFILE_NAV)
  this@HomeMenuActivity.edit_picture_button.visibility = View.GONE
  ProfileActivity.start(this@HomeMenuActivity, this@HomeMenuActivity.avatar.transition(), this@HomeMenuActivity.username.transition())
}

throttleClicks 是一个扩展方法,它可以做到这一点:

fun View.throttleClicks(
  windowDurationMs: Long = 800,
  onClick: View.() -> Unit
) {
  setOnClickListener(object : View.OnClickListener {

    // Set lastClickTime to - windowDurationMs to ensure the first click won't be throttled.
    var lastClickTime = -windowDurationMs

    override fun onClick(v: View?) {
      val time = SystemClock.elapsedRealtime()
      if (time - lastClickTime >= windowDurationMs) {
        lastClickTime = time
        onClick()
      }
    }
  })
}

为什么我突然必须使用显式范围来避免 NPE?

标签: androidkotlinnullpointerexception

解决方案


因为您在 type 的函数中使用合成View.() -> Unit

所以this在函数中是你应用这个函数(profile_clickable)的视图。

Kotlin 合成物的工作方式类似于

val View.profile_clickable: ImageView get() {
  if (cache exists) {
    return cache
  }
  return this.findViewById(R.id.profile_clickable)
}

profile_clickable没有孩子,所以会有例外。

您可以使用以下代码:

profile_clickable.throttleClicks {
  logger.logEvent(PageTags.MENU_PROFILE_NAV)
  this@HomeMenuActivity.run {
    edit_picture_button.visibility = View.GONE
    ProfileActivity.start(this, avatar.transition(), username.transition())
  }
}

推荐阅读