偶尔收到 WarningContextClassLoader 而不是 PathClassLoader 导致 flyway 崩溃
Occasionally receiving WarningContextClassLoader instead of PathClassLoader causing flyway to crash
上下文
在我的 android 应用程序中,我使用 flyway 来更新我的 Db 模式。到目前为止,我只有一个迁移,它创建了 3 个表。 flyway 的简单和常规业务。它确实工作得很好......大多数时候!有时它会因这个错误而崩溃(下面是完整的堆栈):
java.lang.ClassCastException: android.app.LoadedApk$WarningContextClassLoader
cannot be cast to dalvik.system.PathClassLoader
我有几个与该错误相关的问题:
- 什么是 LoadedApk.WarningContextClassLoader?
- 为什么有时用它代替 dalvik.system.PathClassLoader?
- 这是我的应用程序、Android 系统或 Flyway 中的错误吗?
我还注意到我可以在 flyway 中显式注入 classloader (Flyway.setClassLoader() )
- 我怎样才能确定正确的 classloader ?
请注意,我在 Flyway 中注入了应用程序上下文,而不是特定的 activity 上下文。
版本
我使用 org.flywaydb:flyway-core:4.0.2
我在 Android 4.2.2(JellyBean,api 级别 17)和 4.4(KitKat,api 级别 19)中注意到了这个问题。据我所知,它从未出现在更高版本上。
堆栈跟踪
Exception java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycompany.myapp.free.debug/com.mycompany.MainActivity}: java.lang.ClassCastException: android.app.LoadedApk$WarningContextClassLoader cannot be cast to dalvik.system.PathClassLoader
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2306)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2358)
android.app.ActivityThread.access0 (ActivityThread.java:156)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1340)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loop (Looper.java:153)
android.app.ActivityThread.main (ActivityThread.java:5299)
java.lang.reflect.Method.invokeNative (Method.java)
java.lang.reflect.Method.invoke (Method.java:511)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:833)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:600)
dalvik.system.NativeStart.main (NativeStart.java)
Caused by java.lang.ClassCastException: android.app.LoadedApk$WarningContextClassLoader cannot be cast to dalvik.system.PathClassLoader
org.flywaydb.core.internal.util.scanner.classpath.android.AndroidScanner.<init> (AndroidScanner.java:46)
org.flywaydb.core.internal.util.scanner.Scanner.<init> (Scanner.java:38)
org.flywaydb.core.Flyway.execute (Flyway.java:1353)
org.flywaydb.core.Flyway.info (Flyway.java:1040)
com.mycompany.db.FlywayHelper.info (FlywayHelper.java:54)
com.mycompany.db.FlywayHelper.migrate (FlywayHelper.java:45)
com.mycompany.db.GW2DatabaseHelper.migrate (GW2DatabaseHelper.java:56)
com.mycompany.db.DbInit.initKeyGuild (DbInit.java:62)
com.mycompany.db.DbInit.init (DbInit.java:42)
com.mycompany.business.BootApp.boot (BootApp.java:79)
com.mycompany.MainActivity.onCreate (MainActivity.java:51)
android.app.Activity.performCreate (Activity.java:5122)
android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1081)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2270)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2358)
android.app.ActivityThread.access0 (ActivityThread.java:156)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1340)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loop (Looper.java:153)
android.app.ActivityThread.main (ActivityThread.java:5299)
java.lang.reflect.Method.invokeNative (Method.java)
java.lang.reflect.Method.invoke (Method.java:511)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:833)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:600)
dalvik.system.NativeStart.main (NativeStart.java)
研究更新
虽然我不清楚它的目的,LoadedApk.WarningContextClassLoader 似乎是一个有效的 class 加载器,然后 Flyway 应该支持它。 pull request 已提交。
在两者之间,需要实施变通方法,以注入预期的 class 加载器:
private void injectClassLoader(Flyway flyway) {
ClassLoader classLoader = flyway.getClassLoader();
if (classLoader != null && !(classLoader instanceof PathClassLoader)){
flyway.setClassLoader(classLoader.getParent());
}
}
commit message adding WarningContextClassLoader 有不错的信息。我想传递 activity 的上下文可能会有帮助。
What is LoadedApk.WarningContextClassLoader ?
Why is it sometimes used instead of dalvik.system.PathClassLoader ?
不太确定,但是这个特定的 class 加载器的目的似乎是警告用户它的包可能正在与其他包共享它的虚拟机。 More info here,感谢@orip。
Is it a bug in my app, in Android system or in Flyway ?
无论如何,WarningContextClassLoader 仍然是一个有效的 class 加载器,并且必须被 flyway 接受。在 AndroidScanner 中制作的 cast 毫无用处。
解决方案
上下文
在我的 android 应用程序中,我使用 flyway 来更新我的 Db 模式。到目前为止,我只有一个迁移,它创建了 3 个表。 flyway 的简单和常规业务。它确实工作得很好......大多数时候!有时它会因这个错误而崩溃(下面是完整的堆栈):
java.lang.ClassCastException: android.app.LoadedApk$WarningContextClassLoader
cannot be cast to dalvik.system.PathClassLoader
我有几个与该错误相关的问题:
- 什么是 LoadedApk.WarningContextClassLoader?
- 为什么有时用它代替 dalvik.system.PathClassLoader?
- 这是我的应用程序、Android 系统或 Flyway 中的错误吗?
我还注意到我可以在 flyway 中显式注入 classloader (Flyway.setClassLoader() )
- 我怎样才能确定正确的 classloader ?
请注意,我在 Flyway 中注入了应用程序上下文,而不是特定的 activity 上下文。
版本
我使用 org.flywaydb:flyway-core:4.0.2
我在 Android 4.2.2(JellyBean,api 级别 17)和 4.4(KitKat,api 级别 19)中注意到了这个问题。据我所知,它从未出现在更高版本上。
堆栈跟踪
Exception java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mycompany.myapp.free.debug/com.mycompany.MainActivity}: java.lang.ClassCastException: android.app.LoadedApk$WarningContextClassLoader cannot be cast to dalvik.system.PathClassLoader
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2306)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2358)
android.app.ActivityThread.access0 (ActivityThread.java:156)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1340)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loop (Looper.java:153)
android.app.ActivityThread.main (ActivityThread.java:5299)
java.lang.reflect.Method.invokeNative (Method.java)
java.lang.reflect.Method.invoke (Method.java:511)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:833)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:600)
dalvik.system.NativeStart.main (NativeStart.java)
Caused by java.lang.ClassCastException: android.app.LoadedApk$WarningContextClassLoader cannot be cast to dalvik.system.PathClassLoader
org.flywaydb.core.internal.util.scanner.classpath.android.AndroidScanner.<init> (AndroidScanner.java:46)
org.flywaydb.core.internal.util.scanner.Scanner.<init> (Scanner.java:38)
org.flywaydb.core.Flyway.execute (Flyway.java:1353)
org.flywaydb.core.Flyway.info (Flyway.java:1040)
com.mycompany.db.FlywayHelper.info (FlywayHelper.java:54)
com.mycompany.db.FlywayHelper.migrate (FlywayHelper.java:45)
com.mycompany.db.GW2DatabaseHelper.migrate (GW2DatabaseHelper.java:56)
com.mycompany.db.DbInit.initKeyGuild (DbInit.java:62)
com.mycompany.db.DbInit.init (DbInit.java:42)
com.mycompany.business.BootApp.boot (BootApp.java:79)
com.mycompany.MainActivity.onCreate (MainActivity.java:51)
android.app.Activity.performCreate (Activity.java:5122)
android.app.Instrumentation.callActivityOnCreate (Instrumentation.java:1081)
android.app.ActivityThread.performLaunchActivity (ActivityThread.java:2270)
android.app.ActivityThread.handleLaunchActivity (ActivityThread.java:2358)
android.app.ActivityThread.access0 (ActivityThread.java:156)
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1340)
android.os.Handler.dispatchMessage (Handler.java:99)
android.os.Looper.loop (Looper.java:153)
android.app.ActivityThread.main (ActivityThread.java:5299)
java.lang.reflect.Method.invokeNative (Method.java)
java.lang.reflect.Method.invoke (Method.java:511)
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:833)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:600)
dalvik.system.NativeStart.main (NativeStart.java)
研究更新
虽然我不清楚它的目的,LoadedApk.WarningContextClassLoader 似乎是一个有效的 class 加载器,然后 Flyway 应该支持它。 pull request 已提交。
在两者之间,需要实施变通方法,以注入预期的 class 加载器:
private void injectClassLoader(Flyway flyway) {
ClassLoader classLoader = flyway.getClassLoader();
if (classLoader != null && !(classLoader instanceof PathClassLoader)){
flyway.setClassLoader(classLoader.getParent());
}
}
commit message adding WarningContextClassLoader 有不错的信息。我想传递 activity 的上下文可能会有帮助。
What is LoadedApk.WarningContextClassLoader ?
Why is it sometimes used instead of dalvik.system.PathClassLoader ?
不太确定,但是这个特定的 class 加载器的目的似乎是警告用户它的包可能正在与其他包共享它的虚拟机。 More info here,感谢@orip。
Is it a bug in my app, in Android system or in Flyway ?
无论如何,WarningContextClassLoader 仍然是一个有效的 class 加载器,并且必须被 flyway 接受。在 AndroidScanner 中制作的 cast 毫无用处。
解决方案