YouTube Android播放器API在新版本YouTube中抛出“BadParcelableException ClassNotFoundException when unmarshalling: asc”的异常

8

向YouTube Android播放器API库工程师提交错误报告:请参考android-youtube-api标签

在过去一周半的时间里,我发现我们的应用程序中这个奇怪的BadParcelableException错误稳步增加,并将其归因于YouTube在Android上的新发布。

如果您的应用程序正在播放YouTube视频,将应用程序带到后台,强制停止YouTube应用程序,然后恢复您的应用程序,就会发生崩溃。在YouTube版本12.19.56上可以重现崩溃。还在较旧的YouTube版本12.05.21上进行了测试,没有发生崩溃。

堆栈跟踪:

main Exception: Unable to start activity ComponentInfo{com.myapp.MainActivity}: 
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: asc 
Stack: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.MainActivity}: 
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: asc 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2666) 
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) 
at android.app.ActivityThread.-wrap12(ActivityThread.java) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:154) 
at android.app.ActivityThread.main(ActivityThread.java:6121) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779) Caused by: 
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: asc 
at android.os.Parcel.readParcelableCreator(Parcel.java:2536) 
at android.os.Parcel.readParcelable(Parcel.java:2462) 
at android.os.Parcel.readValue(Parcel.java:2365) 
at android.os.Parcel.readSparseArrayInternal(Parcel.java:2813) 
at android.os.Parcel.readSparseArray(Parcel.java:2068) 
at android.os.Parcel.readValue(Parcel.java:2422) 
at android.os.Parcel.readArrayMapInternal(Parcel.java:2732) 
at android.os.BaseBundle.unparcel(BaseBundle.java:269) 
at android.os.Bundle.getSparseParcelableArray(Bundle.java:934) 
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1208) 
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1528) 
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1595) 
at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:2893) 
at android.support.v4.app.FragmentController.dispatchCreate(FragmentController.java:190) 
at android.support.v4.app.FragmentActivity.onCreate(FragmentActivity.java:353) 
at android.support.v7.app.AppCompatActivity.onCreate(AppCompatActivity.java:85) 
at com.myapp.BaseActivity.onCreate(BaseActivity.java:36) 
at com.myapp.MainActivity.onCreate(MainActivity.java:190) 
at android.app.Activity.performCreate(Activity.java:6682) 
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) 
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619) ... 9 more

Caused by: java.lang.ClassNotFoundException: Didn't find class "asc" on path: DexPathList[[zip file "/data/app/com.myapp-naA-_cCrz-w81rqx98ipcQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.myapp-naA-_cCrz-w81rqx98ipcQ==/lib/arm64, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:93)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 32 more

一些更多信息:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...
    super.onCreate(savedInstanceState); // Crashing here MainActivity.java:190
    ...
}

1
根据堆栈跟踪,似乎FragmentManager在初始化期间尝试从Bundle获取其一些内部状态,Bundle尝试解包自身,但失败了,因为Bundle内容以微妙的方式损坏。您能否在调用Activity#onSaveInstanceState结束时发布Activity状态Bundle的内容?覆盖该方法,在返回之前设置断点,然后从调试器中复制整个 Bundle内容(包括所有嵌套对象及其内容!),并将其粘贴到某个地方供我们查看(Github Gist等)。特别注意SparseArrays。 - user1643723
请注意,除了Bundle中的错误之外,您自己的代码很可能也有些问题。确保您没有在自己的Parcelable中犯了错误,以免某种方式损坏了Parcel数据。 - user1643723
也许可以看一下IntelliJ自定义渲染器?不管怎样,信息应该不会太多,就像我说的,只需查看SparseArray的内容即可。 - user1643723
你也可以使用LogCat来递归记录onSaveInstanceState期间Bundle中的所有内容(只要不在单行中记录以确保它适合)。 - user1643723
@ShadabAnsari 是的,我只是在 super.onCreate(...) 周围加了一个 try catch 块,并捕获了 BadParcelableException - mco
显示剩余2条评论
4个回答

4

视图状态的保存和恢复问题。Youtube应用程序存在一个错误,会存储包含来自Youtube apk的asc类实例的视图状态。因此,我们的应用程序无法恢复它,因为不了解这个类。我的解决方案是通过下面的代码在YouTubePlayerSupportFragment中防止对YoutubePlayerView进行视图状态保存:

@Override
public void onSaveInstanceState(Bundle bundle) {
    super.onSaveInstanceState(bundle);

    // disable view state saving to prevent saving states from youtube apk which cannot be restored.
    View view = getView();
    if (view instanceof ViewGroup) {
        ViewGroup viewGroup = ((ViewGroup) view);
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            viewGroup.getChildAt(i).setSaveFromParentEnabled(false);
        }
    }
}

这段代码应该添加到你子类化的YouTubePlayerSupportFragment中。 这个解决方案不会从bundle中删除YouTube播放器状态。因此,Youtube播放器将成功恢复。

经过尝试了很多不同的解决方案,这个是有效的。谢谢! - dtrejogo
@xkor:getView()是做什么的? - Saggy
@Saggy 这是 Fragment 类的一种方法,用于获取根视图。 - xkor
@xkor:我该如何在Activity中使用这个? - Saggy
@Saggy 你可以在activity布局中找到“YoutubePlayerView”,并为此视图执行“setSaveFromParentEnabled(false);”。 - xkor
@xkor: 覆盖 @Override public void onSaveInstanceState(Bundle bundle) { super.onSaveInstanceState(bundle); youTubeView.setSaveFromParentEnabled(false); } - Saggy

0
在你的onCreate中使用以下代码:
@Override
public void onCreate(Bundle b) {
  if (b != null) {
    final ClassLoader contextCl = getClassLoader();
    b.setClassLoader(contextCl);
  }
  super.onCreate(b);
}

这个问题可能是由于YouTube库代码在状态Bundle中存储自定义的Parcelable(YouTube库类可能被Proguard混淆,因此出现了像“asc”这样的奇怪名称)。

如果上面的建议不起作用,请遵循@Fitz建议的线路并放弃状态Bundle。不要在onCreate中尝试处理它(那样行不通),而是最好重写onSaveInstanceState,在播放进行时挂起您的应用程序时返回Bundle.EMPTY。


请注意,所涉及的错误在多个方面都非常棘手。如果您(或YouTube应用程序)将嵌套的Bundle存储在彼此内部,则这些Bundle也需要设置适当的ClassLoader...有人应该告诉Google要有一些常识,并且只需在Bundle内使用Thread#getContextClassLoader来解决这个问题。

我在我的MainActivity上尝试了这个,但没有成功,仍然遇到同样的崩溃。我的MainActivity中包含一个带有ViewPager的Fragment,ViewPager的其中一个项是包含YouTubePlayerSupportFragment的Fragment。 - dtrejogo

0

我找到了一个适合我的解决方案。在我的onCreate方法中,我捕获由于YouTube播放器中的ClassNotFoundException而抛出的RuntimeException。视频会失去它的状态。按下播放按钮会导致重新开始。否则一切照常。


-1

我最终使用了一个对我有效的try catch块。

try {
    super.onCreate(savedInstanceState);

} catch (BadParcelableException e) {
    // Maybe put an analytic here to see if it is still being thrown.
    // So when youtube fixes the issue in the future we can remove this 
    // ugly try catch.
    Log.e(TAG, e.toString);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接