[关闭]
@946898963 2020-07-09T08:16:30.000000Z 字数 2093 阅读 831

条条小小Kotlin使用过程中需要注意的问题

Kotlin


1. Java调用Kotlin方法时导致的空指针异常(类型安全问题)

出现原因

在Java中我们在接口中定义了一个这样的方法

此处输入图片的描述

在Kotlin中实现时, 我们可以有2种实现方式

此处输入图片的描述

此时Kotlin被编译成的Java代码是这样的

此处输入图片的描述

此处输入图片的描述

此时Kotlin被编译成的Java代码是这样的

此处输入图片的描述

对比两种方案, 会发现, 多了三行代码

此处输入图片的描述

进入checkParameterIsNotNull方法内部, 会发现如果传入的对象是null的话是会直接抛出异常的

此处输入图片的描述

那么问题来了
如果我使用的是方案一
但是Java在调用onFinish方法时homeDesigner articleFeedList imageList 中的任意一个参数传入了null, 那么就会抛出throwParameterIsNullException

解决方案

此处输入图片的描述

这样在Kotlin里实现一个Java定义的接口方法时会自动帮我们判断是否使用可空类型

2. 类型转换时 as 和 as?

使用as时如果转换失败则会直接抛出ClassCastException
使用as?时如果转换失败则会返回null

  1. fun methodAsTest(list: List<*>) {
  2. val v = list[0] as Int
  3. print(v) // 会Crash, 因为String无法转换成Int
  4. val v1 = list[0] as Int?
  5. print(v1) // 会Crash, 因为String无法转换成Int?
  6. val v2: Int? = list[0] as? Int
  7. print(v2) // 会输出null, 因此虽然转换类型为Int
  8. // 但是v2需要为Int?
  9. val v3: Int? = list[0] as? Int?
  10. print(v3) // 会输出null, 原因同上
  11. }
  12. methodAsTest(listOf("Hello World"))
  13. // 正确的使用方法
  14. fun methodAsTest(list: List<*>) {
  15. // as转换前需要使用is来判断一下, 如果不想判断则请使用as?
  16. if (list[0] is Int) {
  17. val v = list[0] as Int
  18. print(v)
  19. }
  20. if (list[0] is Int) {
  21. val v1 = list[0] as Int?
  22. print(v1)
  23. }
  24. val v2: Int? = list[0] as? Int
  25. print(v2)
  26. val v3: Int? = list[0] as? Int?
  27. print(v3)
  28. }

结论: as转换前需要使用is来判断一下, 如果不想判断则请使用as?

3. 使用by lazy时的注意事项

此处输入图片的描述

此处输入图片的描述

  1. // 构造的SynchronizedLazyImpl对象
  2. val i1: Int by lazy { 100 }
  3. // 构造的UnsafeLazyImpl对象
  4. val i2: Int by lazy(LazyThreadSafetyMode.NONE) { 100 }

**结论: ** 从图中我们可发现, 默认情况下by lazy构造的是线程安全的SynchronizedLazyImpl对象, 但是绝大多数情况下我们使用by lazy构造的对象都不涉及多线程调用, 因此, 如果你使用by lazy构造对象时, 如果确定不涉及到多线程时, 请加上LazyThreadSafetyMode.NONE参数

4. 使用kotlin-android-extensions的注意事项

当你使用 kotlin-android-extensions 来解析布局文件时, 默认只支持 自定义View Fragment 和Activity , 在 ViewHolder 中使用 kotlin-android-extensions 时需要继承LayoutContainer.

  1. // 方案一
  2. class CustomViewHolder(override val containerView: View)
  3. : RecyclerView.ViewHolder(containerView), LayoutContainer
  4. // 方案二
  5. class CustomViewHolder(view: View)
  6. : RecyclerView.ViewHolder(view), LayoutContainer {
  7. override val containerView: View?
  8. get() = itemView
  9. }

这样他才会在使用的时候会使用findCachedViewById方法来把View缓存起来, 否则他则会每次都使用findViewById方法, 这样ViewHolder就失去了他应有的价值

5. 对可空类型使用Delegates.observable监听时报错的问题

没问题: 我们需要手动指定observable中泛型的类型(即使编译器告诉我们可以省略, 也不能省略. 省略了就会报错, kotlin的bug)

此处输入图片的描述

有问题: 编译时会报错

此处输入图片的描述

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注