谷歌的bug:當 CompileSdk 33 遇上Kotlin
最近專案裡compose 要升級到1.3, 要求compile sdk 也要到33版本,大家都知道 一般情況下,我們修改compilesdk 都不會有什麼問題,最多就是一些api的適配,編譯不過啥的, 但是不會引發線上故障,但是這裡要注意了target sdk 的修改 就要複雜的多了, 這裡不多說,只介紹一下 我碰到的一個compilesdk 33的問題
在Compile sdk 33版本中,這個手勢監聽的介面 程式碼發生了一些變化:
在這些介面方法說 引數前面加上了一個NonNull的 註解,這個註解的意思就是 告訴開發者 這個引數不可能為空
注意了 在<=32的版本中 這個註解是沒有的
對於java的開發者來說,這個影響微乎其微,但是如果你跟我一樣是kotlin的開發者就要倒黴了,
因為在<=32的時候 你繼承這個介面的時候 會提示你引數要定義成可空的
但是當你升級到33的sdk的時候,你就會發現編譯不過了
為啥?
因為33的sdk 前面說過了,方法前面有了 不可空的註解了
要讓他編譯過很簡單 我們只要把? 去掉即可
到這裡還沒結束,最坑的地方來了, 雖然你能編譯過,但是在執行時,有可能會發生crash
為啥? 熟悉kotlin的人就知道了,當你定義一個引數為不可空的型別的時候,你如果傳了一個null給這個引數,他就會報這個crash了,這種情況常見於 java程式碼呼叫kotlin程式碼的時候 這是kotlin編譯器的魔法,有興趣的可以自己反編譯看一下位元組碼,實際上,當你定義一個變數為不可空的時候,如果傳值給他 他就會校驗這個值 是不是為null 為null 則直接拋異常
搞清楚問題所在以後 就得想想怎麼解決了,目前的情況就是 如果不改,就編譯不過,改了 在執行時會crash
另外: 這裡有個連結,可以看下該問題的討論,目前狀態是顯示 谷歌承認了該bug,看狀態顯示fixed,但是不知道為什麼 還沒有推送最新的33 sdk issueTracker
實際上解決這個問題的方法有很多,
方法1: 這個介面的實現 我們不用kotlin寫,用java寫,即可 這個方案最簡單,但是不太優雅
方法2: 魔改下android sdk 33版本的jar包,把註解去掉 這個方案也可以,但是有點麻煩
方法3: asm 位元組碼修改,把那個校驗引數為null 就拋異常的程式碼刪了就行了。 殺雞焉用牛刀
方法4: 寫一個delegate 即可,以後都用這個代理類去做監聽, 這個方法我認為是最簡單的,一勞永逸,而且成本極低
```
import android.content.Context; import android.os.Handler; import android.view.GestureDetector; import android.view.MotionEvent;
import androidx.annotation.Nullable;
/ * 在compile sdk 33 中 修復google的一個註解bug,該bug 會導致 要麼kotlin程式碼編譯失敗 * 要麼執行時crash,這裡用代理模式 簡單的規避此問題即可 * */ public class GestureDetectorDelegate extends GestureDetector { / * @param listener * @param handler * @deprecated */ public GestureDetectorDelegate(OnGestureListener listener, Handler handler) { super(listener, handler); }
/**
* @param listener
* @deprecated
*/
public GestureDetectorDelegate(OnGestureListener listener) {
super(listener);
}
public GestureDetectorDelegate(Context context, OnGestureListenerDelegate listener) {
super(context, listener);
}
public GestureDetectorDelegate(Context context, OnGestureListener listener, Handler handler) {
super(context, listener, handler);
}
public GestureDetectorDelegate(Context context, OnGestureListener listener, Handler handler, boolean unused) {
super(context, listener, handler, unused);
}
/**
* 主要修改點就是在這裡了,複寫這些方法 標記這些引數為可空的即可
*/
public interface OnGestureListenerDelegate extends OnGestureListener {
boolean onDown(@Nullable MotionEvent e);
void onShowPress(@Nullable MotionEvent e);
boolean onSingleTapUp(@Nullable MotionEvent e);
boolean onScroll(@Nullable MotionEvent e1, @Nullable MotionEvent e2, float distanceX, float distanceY);
void onLongPress(@Nullable MotionEvent e);
boolean onFling(@Nullable MotionEvent e1, @Nullable MotionEvent e2, float velocityX, float velocityY);
}
} ```
- Jetpack Compose - Effect與協程 (十五)
- 谷歌的bug:當 CompileSdk 33 遇上Kotlin
- Jetpack Compose - DrawModifier (十三)
- Jetpack Compose - Transition動畫 (十)
- Jetpack Compose - 慣性衰減動畫AnimateDecay(八)
- Jetpack Compose - AnimationSpec (七)
- Jetpack Compose - Animatable與animateAsState (六)
- Jetpack Compose - 淺談 CompositionLocal (五)
- ASM 修改位元組碼 引發的R8 編譯報錯
- Go語言 基於gin框架從0開始構建一個bbs server(二)-使用者登入
- Go語言 基於gin定義一個簡單的web server 開發框架(三)
- Go語言 基於gin定義一個簡單的web server 開發框架(二)
- Go語言 viper與web服務的關機,重啟
- Go語言 zap日誌系統與gin繼承
- Go語言 go-redis與watch
- Go 語言 MySql 基本操作
- Go 語言 常用標準庫 介紹
- Go語言 併發-select 與 鎖
- Go語言 併發-Channel
- Go語言 錯誤處理以及資源管理