Android E/Parcel:解组时找不到类(仅在三星 Tab3 上)

Posted

技术标签:

【中文标题】Android E/Parcel:解组时找不到类(仅在三星 Tab3 上)【英文标题】:Android E/Parcel﹕ Class not found when unmarshalling (only on Samsung Tab3) 【发布时间】:2015-04-19 19:15:04 【问题描述】:

我无法解决为什么会出现此错误,并且只能在运行 4.4.2 的三星 Tab3 设备上解决?当我的 MainActivity 启动另一个 Activity 并在 Intent 中传递 Parcelable 类时会发生这种情况:

    private void debugTest(TestParcel cfgOptions)
        TestParcel cfgOptions = new TestParcel();
        cfgOptions.setValue(15); //just to verify

        Intent intent = new Intent(MainActivity.this, TestActivity.class);
        intent.putExtra("cfgOptions", cfgOptions);
        startActivityForResult(intent, DBG_TEST);
    

TestActivity 获取 parcelable 数据如下:

protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test_activity);

    TestParcel cfgOptions = getIntent().getExtras().getParcelable("cfgOptions");

TestParcel 类:

    import android.os.Parcel;
    import android.os.Parcelable;

    public class TestParcel implements Parcelable 
    private long l_ucs_value = 0;
    private String s_rx_number = "";

    //constructor
    public TestParcel() 
        l_ucs_value = 0;
        s_rx_number = "";
    

    public void RxNumber(String s) 
        s_rx_number = s;
    
    public String RxNumber() 
        return s_rx_number;
    

    //-----------------------------------------------------------------------
    public void setValue(long v)
        l_ucs_value = v;
    
    public long getValue() return l_ucs_value; 


    protected TestParcel(Parcel in) 
        l_ucs_value = in.readLong();
        s_rx_number = in.readString();
    

    @Override
    public int describeContents() 
        return 0;
    

    @Override
    public void writeToParcel(Parcel dest, int flags) 
        dest.writeLong(l_ucs_value);
        dest.writeString(s_rx_number);
    

    @SuppressWarnings("unused")
    public static final Parcelable.Creator<TestParcel> CREATOR = new Parcelable.Creator<TestParcel>() 
        @Override
        public TestParcel createFromParcel(Parcel in) 
            return new TestParcel(in);
        

        @Override
        public TestParcel[] newArray(int size) 
            return new TestParcel[size];
        
    ;

再说一次,我只在三星 Tab3 设备上看到这个 - 但这是我们需要它工作的设备。这是三星logcat:

02-18 08:05:55.393    2235-2571/? E/Parcel? Class not found when unmarshalling: com.vms.android.VersatileDEX.TestParcel
java.lang.ClassNotFoundException: com.vms.android.VersatileDEX.TestParcel
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:251)
        at java.lang.Class.forName(Class.java:216)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
        at android.os.Parcel.readParcelable(Parcel.java:2097)
        at android.os.Parcel.readValue(Parcel.java:2013)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
        at android.os.Bundle.unparcel(Bundle.java:249)
        at android.os.Bundle.getString(Bundle.java:1118)
        at android.content.Intent.getStringExtra(Intent.java:5148)
        at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1467)
        at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1063)
        at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4134)
        at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4032)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2712)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)
 Caused by: java.lang.NoClassDefFoundError: com/vms/android/VersatileDEX/TestParcel
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:251)
        at java.lang.Class.forName(Class.java:216)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
        at android.os.Parcel.readParcelable(Parcel.java:2097)
        at android.os.Parcel.readValue(Parcel.java:2013)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
        at android.os.Bundle.unparcel(Bundle.java:249)
        at android.os.Bundle.getString(Bundle.java:1118)
        at android.content.Intent.getStringExtra(Intent.java:5148)
        at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1467)
        at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1063)
        at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4134)
        at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4032)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2712)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)
 Caused by: java.lang.ClassNotFoundException: Didn't find class "com.vms.android.VersatileDEX.TestParcel" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:67)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:251)
        at java.lang.Class.forName(Class.java:216)
        at android.os.Parcel.readParcelableCreator(Parcel.java:2133)
        at android.os.Parcel.readParcelable(Parcel.java:2097)
        at android.os.Parcel.readValue(Parcel.java:2013)
        at android.os.Parcel.readArrayMapInternal(Parcel.java:2314)
        at android.os.Bundle.unparcel(Bundle.java:249)
        at android.os.Bundle.getString(Bundle.java:1118)
        at android.content.Intent.getStringExtra(Intent.java:5148)
        at com.android.server.am.ActivityStackSupervisor.startActivityLocked(ActivityStackSupervisor.java:1467)
        at com.android.server.am.ActivityStackSupervisor.startActivityMayWait(ActivityStackSupervisor.java:1063)
        at com.android.server.am.ActivityManagerService.startActivityAsUser(ActivityManagerService.java:4134)
        at com.android.server.am.ActivityManagerService.startActivity(ActivityManagerService.java:4032)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:159)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2712)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)

【问题讨论】:

我在三星 Tab3 中遇到了同样的解组错误,并尝试了几乎所有可能的解决方案,包括你的解决方案,但似乎没有一个解决问题,直到我更新到最新版本的 Android Studio 1.3.1 最终解决了问题。更新到最新版本,清理项目并重建它应该可以解决问题。 【参考方案1】:

我有同样的问题。在我的情况下,intent 的附加功能有两个具有相同键的可分割对象。例如:

val intent = Intent()
val anotherIntent = Intent()

anotherIntent.putExtra("same_extra_key", MyParcelableObj())
intent.putExtra("same_extra_key", MyParcelableObj())

intent.putExtra("another_intent_extra_key", anotherIntent)

// ClassNotFoundError
intent.getParcelableExtra<MyParcelableObj>("same_extra_key")

您必须使用不同的密钥或getParcelableArrayListExtra 方法以避免错误。

intent.getParcelableArrayListExtra<MyParcelableObj>("same_extra_key")

【讨论】:

【参考方案2】:

可能对将 Java 与 Kotlin 混合使用的人有用。

我找到了一个简单的解决方案,它只允许使用 Kotlin 而无需样板。

val intent = Intent(this, TestActivity::class.java).apply 
    extras?.putParcellable("cfgOptions", cfgOptions)


startActivityForResult(intent, DBG_TEST);

然后检索您应该使用的值:

var cfgOptions = intent?.extras?.getParcellable<TestParcel>("cfgOptions")

【讨论】:

【参考方案3】:

刚刚发现此异常的另一个原因。出于某种原因,我只在活动恢复时才得到它,而不是在第一次创建它时得到它。 如果您的可打包实体是 kotlin data class,它是一些 class 的子实体,并且您尝试对其进行解包,则可能会在解组时收到 BadParcelableException, Class not found。 解决方案是让这样的课程只是class,而不是data class

【讨论】:

【参考方案4】:

对于在您的项目中同时使用 Java 和 Kotlin 的人,如果您在 kotlin 中创建 Parcelable Data Class 并在 Java Class eg Activity or something 中使用它,您可能会遇到这种错误,这似乎是一个问题,并且它的解决方案只是使用Java POJOs 来代替kotlin 数据类

【讨论】:

你知道这方面的任何参考/票吗?【参考方案5】:

最近的三星 S8 手机也发生了同样的问题。创建捆绑包明确为我工作。我使用了以下代码,它不需要捆绑的字符串标识符:

// Create the intent to start the activity.
Bundle bundle = new Bundle();
bundle.putParcelable("YOUR_PARCELABLE_ID", yourPacelable);
Intent intent = new Intent(context, YourActivity.class);
intent.putExtras(bundle);

然后在activity中读取parcelable:

// In your activity, read parcelable back.
YourParcelable p = getIntent().getParcelableExtra("YOUR_PARCELABLE_ID");

我希望这会有所帮助。

【讨论】:

已确认适用于三星 j5【参考方案6】:

在我的情况下,内部自动创建新包的 new Intent().putExtra(key,parcelable) 给了我解组错误,我不知道为什么,所以我不得不自己创建新包,在上面添加 parcelable并在意图上添加捆绑包。这样就解决了问题。

【讨论】:

非常感谢。您的解决方案非常简单【参考方案7】:

由于某些奇怪的原因,类加载器似乎没有正确设置。

TestActivity.onCreate() 中尝试以下操作之一:


TestParcel cfgOptions = getIntent().getParcelableExtra("cfgOptions");

Intent intent = getIntent();
intent.setExtrasClassLoader(TestParcel.class.getClassLoader());
TestParcel cfgOptions = intent.getParcelableExtra("cfgOptions");

Bundle extras = getIntent().getExtras();
extras.setClassLoader(TestParcel.class.getClassLoader());
TestParcel cfgOptions = extras.getParcelable("cfgOptions");

或者,将 Parcelable 包装成一个包:

Bundle b = new Bundle();
b.putParcelable("options", cfgOptions);
Intent intent = new Intent(MDex.this, TestActivity.class);
intent.putExtra("bundle", b);

得到:

Bundle b = getIntent().getBundleExtra("bundle");
TestParcel cfgOptions = b.getParcelable("options");

【讨论】:

我真的希望成功,但这些方案都没有解决问题。我想知道这是否真的是三星特有的问题?该应用程序在我之前不会崩溃(尽管我 感谢您的选择。我已经读过 Bundles 存储类名,所以我尝试了以下方法,它起作用了: 由于您的回复使我下定决心,我将在此给您功劳。发送:Bundle b = new Bundle(); b.putParcelable("选项", cfgOptions); Intent 意图 = new Intent(MDex.this, TestActivity.class); intent.putExtra("捆绑", b);获取:Bundle b = getIntent().getBundleExtra("bundle"); TestParcel cfgOptions = b.getParcelable("options"); 调用 getParcelable() 之前的行 bundle.setClassLoader(&lt;ClassName&gt;.class.getClassLoader()); 对我有用! 我只是在我们的三星测试设备上遇到这个错误 - 包装在一个 Bundle 中似乎可以确保 Android 的 ClassLoader 处理(取消)编组,而不是一些自定义的三星代码。【参考方案8】:

只是想在这里更简洁明了的答案-

//sending a parcelable class to another activity -----------------

MyParcelableOptionsClass mpoc = new MyParcelableOptionsClass();

Bundle b = new Bundle();
b.putParcelable("options", mpoc );

Intent intent = new Intent(MyActivity.this, OtherActivity.class);
intent.putExtra("bundle", b);

startActivityForResult(intent, 1);


//getting the parcelable class from OtherActivity------------------

protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.other_activity);

    Bundle b = getIntent().getBundleExtra("bundle");
    MyParcelableOptionsClass mpoc = b.getParcelable("options");



//returning the parcelable class back from OtherActivity -----------

 Bundle b = new Bundle();
 b.putParcelable("options", mpoc);

 Intent intent = new Intent();
 intent.putExtra("bundle", b);

 setResult(0, intent);


//and getting the parcelable class back in MyActivity --------------

onActivityResult(int requestCode, int resultCode, Intent data)
    if(null != data)
        Bundle b = data.getBundleExtra("bundle");
        MyParcelableOptionsClass mpoc = b.getParcelable("options");
    

【讨论】:

以上是关于Android E/Parcel:解组时找不到类(仅在三星 Tab3 上)的主要内容,如果未能解决你的问题,请参考以下文章

在 PreferenceFragment 中解组时找不到类

Parcelable:从不同应用程序调用时解组时找不到类

错误:解组时找不到类:com.facebook.login.Login 客户端请求

解组 Android Intent Parcelable 时找不到类

ClassNotFoundException 解组时真的不知道为啥

YouTube Android Player API 在解组时抛出“BadParcelableException ClassNotFoundException:asc”与新的 YouTube 版本