指定为非空的参数为空 - 在 Kotlin 中加载图像
Parameter specified as non-null is null - loading Image in Kotlin
我正在使用 Picassos Target 从 Internet 加载图像并从中生成调色板。当图像不再存在时,我会因 Logcat:
中的错误而发生以下崩溃
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter placeHolderDrawable
at .ActivityThread.performLaunchActivity(ActivityThread.java:3260)
at .ActivityThread.handleLaunchActivity(ActivityThread.java:3396)
at .servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at .servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at .servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at .ActivityThread$H.handleMessage(ActivityThread.java:2009)
at .Handler.dispatchMessage(Handler.java:107)
at .Looper.loop(Looper.java:214)
at .ActivityThread.main(ActivityThread.java:7319)
at .reflect.Method.invoke(Native Method)
at .os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at .os.ZygoteInit.main(ZygoteInit.java:934)
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter placeHolderDrawable
at .LoadImage$onCreate.onPrepareLoad(Unknown Source:2)
at com.squareup.picasso.RequestCreator.into(RequestCreator.java:559)
at .LoadImage.onCreate(LoadImage.kt:154)
**at .LoadImage.onCreate(LoadImage.kt:154)**
好的,我明白发生了什么事 - Picasso 加载了图像,图像为空,因此应用程序崩溃了。但是如何用一行代码解决这个问题呢?
这是出现问题的部分,我为您标记了第154行:
Picasso.get()
.load(eventimgurl)
**.into(object : com.squareup.picasso.Target {**
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
assert(iconImg != null)
iconImg!!.setImageBitmap(bitmap)
Palette.from(bitmap)
.generate(Palette.PaletteAsyncListener { palette ->
val dividerswatch_dom = palette!!.dominantSwatch
val dividerswatch_sub = palette.lightVibrantSwatch
if (dividerswatch_dom == null || dividerswatch_sub == null) {
return@PaletteAsyncListener
}
val gd = GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,
intArrayOf(dividerswatch_dom.rgb, dividerswatch_sub.rgb))
gd.cornerRadius = 0f
gd.gradientType = GradientDrawable.RADIAL_GRADIENT
gd.gradientRadius = 700.0f
eventdividerheader.background = gd
eventdividerdjstart.background = gd
eventdivider_detail_top.background = gd
eventdivider_detail_bottom.background = gd
})
}
override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) {
}
override fun onPrepareLoad(placeHolderDrawable: Drawable) {
}
})
像这样加载图像之前检查条件
if (isNullOrEmpty(eventimgurl)) {
// display default image
}
else {
// load you image from url that is eventimgurl
Picasso.with(YourActivity::this)
.load(eventimgurl)
.into(imgView, object: com.squareup.picasso.Callback {
override fun onSuccess() {
// done
}
override fun onError() {
// load default image or do something
}
})
}
实际上,问题在于库代码与 Kotlin 不完全兼容。或者事实上,更多的是关于您使用的 IDE 而不是图书馆。
为什么?
interface Target {
void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
void onBitmapFailed(Exception e, Drawable errorDrawable)
void onPrepareLoad(Drawable placeHolderDrawable)
}
上面的界面就是Target的java界面。
由于在 Kotlin 代码中没有空注释,因此使用它可能会非常棘手,因为我们不知道 placeHolderDrawable
(和其他变量)的类型是否可为空。
因此,此接口的 kotlin 实现如下:
object : Target {
// ...
override fun onPrepareLoad(placeHolderDrawable: Drawable) {
}
}
或...
object : Target {
// ...
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
}
}
我们到了。
当 Kotlin 编译为 Java 字节码时,它会为 not-null types
:
添加 not-null checks
kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull(param)
因此,要使您的代码正常工作...只需将 Drawable
更改为 Drawable?
。然后,不会有Intrinsics
调用,也不会有异常。
因此,即使您的方法为空,编译器也会在方法的开头添加 Intrinsics
检查所有非空参数。随时反编译您的代码并在空方法中找到这些调用:)
结论
问题是 IDE 没有正确生成没有 nullability annotations
的代码,因为类型被转换为非空类型而不是可空类型。
我正在使用 Picassos Target 从 Internet 加载图像并从中生成调色板。当图像不再存在时,我会因 Logcat:
中的错误而发生以下崩溃 java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter placeHolderDrawable
at .ActivityThread.performLaunchActivity(ActivityThread.java:3260)
at .ActivityThread.handleLaunchActivity(ActivityThread.java:3396)
at .servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at .servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at .servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at .ActivityThread$H.handleMessage(ActivityThread.java:2009)
at .Handler.dispatchMessage(Handler.java:107)
at .Looper.loop(Looper.java:214)
at .ActivityThread.main(ActivityThread.java:7319)
at .reflect.Method.invoke(Native Method)
at .os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at .os.ZygoteInit.main(ZygoteInit.java:934)
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter placeHolderDrawable
at .LoadImage$onCreate.onPrepareLoad(Unknown Source:2)
at com.squareup.picasso.RequestCreator.into(RequestCreator.java:559)
at .LoadImage.onCreate(LoadImage.kt:154)
**at .LoadImage.onCreate(LoadImage.kt:154)**
好的,我明白发生了什么事 - Picasso 加载了图像,图像为空,因此应用程序崩溃了。但是如何用一行代码解决这个问题呢?
这是出现问题的部分,我为您标记了第154行:
Picasso.get()
.load(eventimgurl)
**.into(object : com.squareup.picasso.Target {**
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
assert(iconImg != null)
iconImg!!.setImageBitmap(bitmap)
Palette.from(bitmap)
.generate(Palette.PaletteAsyncListener { palette ->
val dividerswatch_dom = palette!!.dominantSwatch
val dividerswatch_sub = palette.lightVibrantSwatch
if (dividerswatch_dom == null || dividerswatch_sub == null) {
return@PaletteAsyncListener
}
val gd = GradientDrawable(
GradientDrawable.Orientation.LEFT_RIGHT,
intArrayOf(dividerswatch_dom.rgb, dividerswatch_sub.rgb))
gd.cornerRadius = 0f
gd.gradientType = GradientDrawable.RADIAL_GRADIENT
gd.gradientRadius = 700.0f
eventdividerheader.background = gd
eventdividerdjstart.background = gd
eventdivider_detail_top.background = gd
eventdivider_detail_bottom.background = gd
})
}
override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) {
}
override fun onPrepareLoad(placeHolderDrawable: Drawable) {
}
})
像这样加载图像之前检查条件
if (isNullOrEmpty(eventimgurl)) {
// display default image
}
else {
// load you image from url that is eventimgurl
Picasso.with(YourActivity::this)
.load(eventimgurl)
.into(imgView, object: com.squareup.picasso.Callback {
override fun onSuccess() {
// done
}
override fun onError() {
// load default image or do something
}
})
}
实际上,问题在于库代码与 Kotlin 不完全兼容。或者事实上,更多的是关于您使用的 IDE 而不是图书馆。
为什么?
interface Target {
void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from)
void onBitmapFailed(Exception e, Drawable errorDrawable)
void onPrepareLoad(Drawable placeHolderDrawable)
}
上面的界面就是Target的java界面。
由于在 Kotlin 代码中没有空注释,因此使用它可能会非常棘手,因为我们不知道 placeHolderDrawable
(和其他变量)的类型是否可为空。
因此,此接口的 kotlin 实现如下:
object : Target {
// ...
override fun onPrepareLoad(placeHolderDrawable: Drawable) {
}
}
或...
object : Target {
// ...
override fun onPrepareLoad(placeHolderDrawable: Drawable?) {
}
}
我们到了。
当 Kotlin 编译为 Java 字节码时,它会为 not-null types
:
not-null checks
kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull(param)
因此,要使您的代码正常工作...只需将 Drawable
更改为 Drawable?
。然后,不会有Intrinsics
调用,也不会有异常。
因此,即使您的方法为空,编译器也会在方法的开头添加 Intrinsics
检查所有非空参数。随时反编译您的代码并在空方法中找到这些调用:)
结论
问题是 IDE 没有正确生成没有 nullability annotations
的代码,因为类型被转换为非空类型而不是可空类型。