kanyun-inc / Kace

Kace: Kotlin Android Compatible Extensions, a framework for assisting in the seamless migration from kotlin-android-extensions
Apache License 2.0
263 stars 12 forks source link

接入使用编译报错,其中布局文件中使用了 OptionsPickerView<T> 和 androidx.appcompat.widget.SearchView$SearchAutoComplete #23

Closed Heart-Beats closed 1 year ago

Heart-Beats commented 1 year ago

如标题所述,其中:

image 对应第一种情况生成,UIKitOptionsExtPickerView<T> : OptionsPickerView<T>, OptionsPickerView 为开源库 com.github.zyyoona7:pickerview:1.0.9 中组件。

image 第二种相关生成报错,以下该种方式引入即会编译报错:

<view class="androidx.appcompat.widget.SearchView$SearchAutoComplete"
                  android:id="@+id/search_src_text"
                  android:layout_height="36dip"
                  android:layout_width="0dp"
                  android:layout_weight="1"
                  android:layout_gravity="center_vertical"
                  android:singleLine="true"
                  android:ellipsize="end"
                  android:background="@null"
                  android:inputType="text|textAutoComplete|textNoSuggestions"
                  android:imeOptions="actionSearch"
                  android:dropDownHeight="wrap_content"
                  android:dropDownAnchor="@id/search_edit_frame"
                  android:dropDownVerticalOffset="0dip"
                  android:dropDownHorizontalOffset="0dip" />
bennyhuo commented 1 year ago
  1. 这种情况看上去最多只能在生成的代码里面用星投影类型,布局里面应该不会有泛型参数的信息吧。
  2. 看上去生成的类型当中把 $ 改成 . 就行了?
bennyhuo commented 1 year ago
  1. 这种情况看上去最多只能在生成的代码里面用星投影类型,布局里面应该不会有泛型参数的信息吧。
  2. 看上去生成的类型当中把 $ 改成 . 就行了?

我们稍微分析了一下。

  1. 的情况实现起来比较困难,需要对生成的代码逻辑做较大的调整。这是因为 Kotlin 类型如果有泛型参数,使用处必须提供实参,而代码生成的时候我们只是处理布局问题,不清楚类型是否有泛型参数,因此现有的代码生成方案无法满足这样的需求。
  2. 我们目前没有专门对这种写法提供支持,布局文件可以改成更为常见的写法:<androidx.appcompat.widget.SearchView.SearchAutoComplete ... /> 。
bennyhuo commented 1 year ago

问题 1 转至 https://github.com/kanyun-inc/Kace/issues/24 跟进。

当前 issue 先关闭了,谢谢支持。

RicardoJiang commented 1 year ago

临时解决方案,可以把解析有问题的 layout 加入黑名单,这些 layout 就不会生成代码,用到这些 layout 的页面手动迁移一下,不影响其他页面

kace {
    whiteList = listOf() // When the whiteList is not empty, only the layout in the whiteList will be parsed
    blackList = listOf("activity_main.xml") // When the blackList is not empty, the layout in the blackList will not be parsed
}
Heart-Beats commented 1 year ago

临时解决方案,可以把解析有问题的 layout 加入黑名单,这些 layout 就不会生成代码,用到这些 layout 的页面手动迁移一下,不影响其他页面

kace {
    whiteList = listOf() // When the whiteList is not empty, only the layout in the whiteList will be parsed
    blackList = listOf("activity_main.xml") // When the blackList is not empty, the layout in the blackList will not be parsed
}

我知道可以使用黑名单避免,只是我把相关问题暴露显示出来。

对于

这种写法是 SearchView 自带的布局文件中使用该写法的,如果想自定义 SearchView 的布局就可以使用到该写法的。

以上的两种问题在使用 kae 插件时都不存在的

bennyhuo commented 1 year ago

在 1.8.20-1.2.0-SNAPSHOT 当中提供了支持,可以试试看

Heart-Beats commented 1 year ago

对泛型的支持仍然有问题,以下是通过 1.8.20-1.2.0-SNAPSHOT 生成的情况:

image

生成处没有错误,但是使用时: image image 可以看到由于类型被转换为 UIKitOptionsExtPickerView<*> 导致其相关的泛型方法参数变为 Nothing 了,无法进行调用。

这里我模拟了一下生成时的 findViewByIdCached 方法,效果如下: image findViewByIdCached() 插件生成的方法,报错一样。

findViewByIdCached2 为优化后的方法,可以正常传入泛型,若调用时第三个传入的参数为 uiKitOptionsExtPickerView 会与目前插件问题一样,返回值变为 UIKitOptionsExtPickerView<*>, 传入 pickerView2 需要使用方给其传入泛型,不符合插件自动生成,因此最佳方式是传入 UIKitOptionsExtPickerView,即可正常使用。

这里的 findViewByIdCached2 方法声明按目前插件生成的来看是可以实现的,至于内部实现应该和之前逻辑差距也不大。但是会给生成的 UIKitOptionsExtPickerView 强制指定泛型 Any,虽然不影响使用,但导致泛型的校验机制失效,比如: image

至于官方以前原有的 KAE 插件,我没看生成的类型是怎样的,但我感觉是泛型仍然保留的,建议看下官方原有效果,参考评估一下如何实现?

bennyhuo commented 1 year ago

这是符合预期的,布局文件当中没有泛型参数信息,更谈不上保留泛型信息了。

由于 Java/Kotlin 泛型都是擦除机制,运行时需要根据实际情况自己强转成需要的类型。

实际上,KAE 也是这样的,KAE 合成的属性直接是 Java raw 类型,与 Kace 最新的解决方案完全一致。以下是 KAE 的效果:

image image image

Heart-Beats commented 1 year ago

这是符合预期的,布局文件当中没有泛型参数信息,更谈不上保留泛型信息了。

由于 Java/Kotlin 泛型都是擦除机制,运行时需要根据实际情况自己强转成需要的类型。

实际上,KAE 也是这样的,KAE 合成的属性直接是 Java raw 类型,与 Kace 最新的解决方案完全一致。以下是 KAE 的效果:

image image image

我试了下 KAE 确实也是类型擦除了,以前这块我使用时应该是使用 findViewById 这种方式,所以默认也没问题。

在使用 KACE 中,我发现还是有一个迁移成本的,如下: image 这里引入了 KACE 中 com.kanyun.kace.AndroidExtensionsBase 独有的类,同时这部分并没有编译到包中: image 如果都在同一个项目中问题不大,但如果项目是作为 SDK 或者开源库引入 KACE 后,SDK 接入者还得必须使用 KACE 这个插件,否则使用到相关类地方的则会报错,这个有好的解决方案吗?

bennyhuo commented 1 year ago

kace 有个 runtime 库,默认情况下插件会自动引入。输出作为 sdk 的话, maven 依赖里面也会包含这个库的,但如果是作为独立的 aar 直接发给使用方,则需要引入 "com.kanyun.kace:kace-runtime:$kace_version"。

如果后续有与泛型 View 类型无关的问题,请新开 issue 讨论哈。