Twitter Chill在Android上崩溃

时间:2016-07-14 11:18:19

标签: android scala proguard kryo

我正在尝试Kryo + Chill(com.twitter:chill_2.11:0.8.0和Scala版本为2.11.8)。以下代码在桌面上运行正常,但在Android上崩溃。

  case class TestDogRef(id: Int)

  case class TestDog(ref: TestDogRef, name: String, friends: Seq[TestDogRef])

  class TestHouse[T](val data: Seq[T])

  case class TestDogHouse(override val data: Seq[TestDog]) extends TestHouse[TestDog](data)

    def serialize[A](data: A): Array[Byte] = {
      val instantiator = new ScalaKryoInstantiator
      instantiator.setRegistrationRequired(false)
      val kryo = instantiator.newKryo()
      val bao = new ByteArrayOutputStream
      val output = new Output(bao)
      kryo.writeObject(output, data)
      output.close()
      bao.toByteArray
    }

    def deserialize[A](ser: Array[Byte], clazz: Class[A]): A = {
      val instantiator = new ScalaKryoInstantiator
      instantiator.setRegistrationRequired(false)
      val kryo = instantiator.newKryo()
      val input = new Input(new ByteArrayInputStream(ser))
      val deserData = kryo.readObject(input, clazz)
      deserData
    }

  override def run(): String = {
      val orig = TestDogHouse(Seq(TestDog(TestDogRef(4), "Doggy", Seq(TestDogRef(1)))))
      val serialized = serialize(orig)
      val deserialized = deserialize(serialized, classOf[TestDogHouse])
      deserialized.toString
    }

这是崩溃:

  07-14 11:55:42.053 6744-6764/x.y E/AndroidRuntime: FATAL EXCEPTION: GLThread 137
                                                                            java.lang.ExceptionInInitializerError
                                                                                at com.twitter.chill.java.PackageRegistrar.all(Unknown Source)
                                                                                at com.twitter.chill.AllScalaRegistrar.apply(Unknown Source)
                                                                                at com.twitter.chill.ScalaKryoInstantiator.newKryo(Unknown Source)
                                                                                at x.y.LibraryTests$KryoWithChillTest$.serialize(Unknown Source)
                                                                                at x.y.LibraryTests$KryoWithChillTest$.run(Unknown Source)
                                                                                at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source)
                                                                                at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source)
                                                                                at scala.collection.immutable.List.foreach(Unknown Source)
                                                                                at x.y.LibraryTests$.run(Unknown Source)
                                                                                at x.y.a.a(Unknown Source)
                                                                                at com.badlogic.gdx.backends.android.j.onSurfaceChanged(Unknown Source)
                                                                                at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1505)
                                                                                at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240)
                                                                             Caused by: com.esotericsoftware.kryo.KryoException: Error while getting field 'words' of bitSet
                                                                                at com.twitter.chill.java.BitSetSerializer.<clinit>(Unknown Source)
                                                                                at com.twitter.chill.java.PackageRegistrar.all(Unknown Source) 
                                                                                at com.twitter.chill.AllScalaRegistrar.apply(Unknown Source) 
                                                                                at com.twitter.chill.ScalaKryoInstantiator.newKryo(Unknown Source) 
                                                                                at x.y.LibraryTests$KryoWithChillTest$.serialize(Unknown Source) 
                                                                                at x.y.LibraryTests$KryoWithChillTest$.run(Unknown Source) 
                                                                                at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source) 
                                                                                at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source) 
                                                                                at scala.collection.immutable.List.foreach(Unknown Source) 
                                                                                at x.y.LibraryTests$.run(Unknown Source) 
                                                                                at x.y.a.a(Unknown Source) 
                                                                                at com.badlogic.gdx.backends.android.j.onSurfaceChanged(Unknown Source) 
                                                                                at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1505) 
                                                                                at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240) 
                                                                             Caused by: java.lang.NoSuchFieldException: words
                                                                                at java.lang.Class.getDeclaredField(Class.java:631)
                                                                                at com.twitter.chill.java.BitSetSerializer.<clinit>(Unknown Source) 
                                                                                at com.twitter.chill.java.PackageRegistrar.all(Unknown Source) 
                                                                                at com.twitter.chill.AllScalaRegistrar.apply(Unknown Source) 
                                                                                at com.twitter.chill.ScalaKryoInstantiator.newKryo(Unknown Source) 
                                                                                at x.y.LibraryTests$KryoWithChillTest$.serialize(Unknown Source) 
                                                                                at x.y.LibraryTests$KryoWithChillTest$.run(Unknown Source) 
                                                                                at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source) 
                                                                                at x.y.LibraryTests$$anonfun$run$1.apply(Unknown Source) 
                                                                                at scala.collection.immutable.List.foreach(Unknown Source) 
                                                                                at x.y.LibraryTests$.run(Unknown Source) 
                                                                                at x.y.a.a(Unknown Source) 
                                                                                at com.badlogic.gdx.backends.android.j.onSurfaceChanged(Unknown Source) 
                                                                                at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1505) 
                                                                                at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240) 

我怀疑这是因为ProGuard - 有些东西被破坏或掉线,但我不知道我还能做些什么。

相关的规则:

-keep class scala.collection.BitSet { *; }
-keepclassmembers class scala.collection.BitSet { *; }
-keep class scala.collection.immutable.BitSet { *; }
-keepclassmembers class scala.collection.immutable.BitSet { *; }
-keep class scala.collection.BitSetLike { *; }
-keepclassmembers class scala.collection.BitSetLike { *; }
-keep class scala.collection.immutable.BitSet.** { *; }
-keepclassmembers class scala.collection.immutable.BitSet.** { *; }
-keepnames class scala.** { *; }

我将不胜感激。

1 个答案:

答案 0 :(得分:2)

此问题与ProGuard无关。 chill java库有BitSetSerializerjava.util.BitSet类,它们通过反射访问字段(名为words)。现在Android中包含的java.util.BitSet实现(从Apache Harmony项目派生到Android 6,Android N将基于OpenJDK)没有这样的字段,您将获得运行时错误,如问题中所示

查看chill-scala库的源代码,使用ScalaKryoInstantiator也将注册所有与Java相关的序列化程序。您可以通过使用EmptyScalaKryoInstantiator代替并注册所有需要的序列化程序来规避问题:

 val instantiator = new EmptyScalaKryoInstantiator
 instantiator.setRegistrationRequired(false)
 val kryo = instantiator.newKryo()

 val col = new ScalaCollectionsRegistrar
 col(kryo)
 ScalaTupleSerialization.register(kryo)
 .... 
 // others as needed

另请参阅ScalaKryoInstantiator.scala以获取要包含的序列化程序的参考。