将对象转换为 Parcelable 超类的子类?

Posted

技术标签:

【中文标题】将对象转换为 Parcelable 超类的子类?【英文标题】:Casting objects to subclasses of a Parcelable superclass? 【发布时间】:2014-03-09 15:00:22 【问题描述】:

好的,所以我有一个课程SomeClass,即Parcelable

它有一个名为SuperClass 的另一个Parcelable 类的数组。在SomeClass 的构造函数中,我试图将SuperClass 对象的数组读入myArray 实例变量。这很简单;但是:

SuperClass 有两个子类FirstSubClassSecondSubClass。数组 temp 应该是所有 3 个的混合,但由于某种原因它只有 SuperClass 对象(ifelse if 语句似乎没有执行,因为 @987654335 的任何元素都没有@ 是子类的实例)。

public SomeClass(Parcel in) 

    myArray = new SuperClass[100];

    // this is probably where the problem is due to the classloader parameter:
    Object[] temp = in.readArray(SuperClass.class.getClassLoader());

    for(int i = 0; i < myArray.length; i++) 

        if(temp[i] instanceof FirstSubClass)
            myArray[i] = (FirstSubClass) temp[i];

        else if(temp[i] instanceof SecondSubClass)
            myArray[i] = (SecondSubClass) temp[i];

        else
            myArray[i] = (SuperClass) temp[i];
    


我想弄清楚的是如何读取可打包对象数组的元素,以便该对象的子类不会自动转换为超类。

(我想我的问题措辞可能很混乱,如果我这样做了,请告诉我)。

【问题讨论】:

Parcelable 是接口还是超类?和 SomeClass 在其构造函数中接受的 Parcel 一样吗? ParcelableSomeClassSuperClass 都实现的接口。 Parcel 是一个类。 包裹怎么写? 【参考方案1】:

我试图重现您的问题,但我无法...我使用了 writeParcelableArrayNOT writeTypedArray。以下是我创建的类:

public class SuperClass implements Parcelable 
    public static final Parcelable.Creator<SuperClass> CREATOR = new Creator<SuperClass>() 

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

        @Override
        public SuperClass createFromParcel(Parcel source) 
            return new SuperClass(source);
        
    ;

    private String label;

    public SuperClass() 
    

    protected SuperClass(Parcel source) 
        label = source.readString();
    

    @Override
    public void writeToParcel(Parcel dest, int flags) 
        dest.writeString(label);
    

    @Override
    public int describeContents() 
        // TODO Auto-generated method stub
        return 0;
    

及其子类:

public class FirstSubClass extends SuperClass 
    public static final Parcelable.Creator<FirstSubClass> CREATOR = new Creator<FirstSubClass>() 

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

        @Override
        public FirstSubClass createFromParcel(Parcel source) 
            return new FirstSubClass(source);
        
    ;

    public FirstSubClass() 
        super();
    

    public FirstSubClass(Parcel source) 
        super(source);
    


和:

public class SecondSubClass extends SuperClass 
    public static final Parcelable.Creator<SecondSubClass> CREATOR = new Creator<SecondSubClass>() 

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

        @Override
        public SecondSubClass createFromParcel(Parcel source) 
            return new SecondSubClass(source);
        
    ;

    public SecondSubClass() 
        super();
    

    public SecondSubClass(Parcel source) 
        super(source);
    


还有SomeClass:

public class SomeClass implements Parcelable 
    public static final Parcelable.Creator<SomeClass> CREATOR = new Creator<SomeClass>() 

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

        @Override
        public SomeClass createFromParcel(Parcel source) 
            return new SomeClass(source);
        
    ;

    private String name;
    private SuperClass[] array;

    public SomeClass(String name, SuperClass[] array) 
        this.name = name;
        this.array = array;
    

    protected SomeClass(Parcel source) 
        this.name = source.readString();
        Parcelable[] temp = source.readParcelableArray(SuperClass.class.getClassLoader());
        array = new SuperClass[temp.length];
        for (int i = 0; i < temp.length; i++) 
            array[i] = (SuperClass) temp[i];
        
    

    public String toString() 
        StringBuilder sb = new StringBuilder(name);
        if (array == null || array.length == 0) 
            sb.append(" Array is empty");
         else 
            sb.append(" Array:");
            for (SuperClass sc : array) 
                sb.append(sc.getClass().getSimpleName());
                sb.append(",");
            
            sb.setLength(sb.length() - 1);
        
        return sb.toString();
    

    public String getName() 
        return name;
    

    public SuperClass[] getArray() 
        return array;
    

    @Override
    public void writeToParcel(Parcel dest, int flags) 
        dest.writeString(name);
        dest.writeParcelableArray(array, flags);
    

    @Override
    public int describeContents() 
        return 0;
    

从一个活动中,我点击一个按钮,创建一个SomeClass 对象,附加到我启动一个新活动的意图,并从那里记录传递的值。启动活动的函数:

@Override
public void onClick(View v) 
    SuperClass[] array = new SuperClass[]  new SuperClass(), new FirstSubClass(), new SecondSubClass(), new SuperClass() ;
    SomeClass cl = new SomeClass("My Label", array);
    Intent intent = new Intent(this, NextActivity.class);
    intent.putExtra("PASS", cl);
    startActivity(intent);

来自NextActivity

public class NextActivity extends Activity 
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        //set some content if you wish
        Log.d("LOG_TAG", "Passed value: " + getIntent().getParcelableExtra("PASS"));
    

我可以在日志中看到:

Passed value: My Label Array:SuperClass,FirstSubClass,SecondSubClass,SuperClass

正是我从以前的活动中传递的内容...检查与您的代码的差异,我怀疑您没有为FirstSubClassSecondSubClass 编写CREATOR

【讨论】:

我在所有 3 个类中都有 CREATOR 变量,所以不可能。我将尝试将您的其余代码与我的课程进行比较;如果我仍然找不到问题,我会发布我的代码 - 感谢您的帮助! 我看了你的代码几次才发现问题!问题是我使用的方法是writeTypedArray而不是writeParcelableArray,它允许传递具有多种类型对象的数组;您能否更新您的答案以强调这是解决方案,以防万一其他人遇到此问题? 我的超类是一个抽象类..你认为我应该为我的结构做些什么..? 谢谢,很好的解决方案!【参考方案2】:

不确定为什么需要在 readArray 方法中获取类加载器,但我试了一下并为您的代码制作了一个示例 - 所以整个示例有几段代码。

示例 Parcelable 类 - 示例中其他一些类的基类

/**
 */
public class Parcelable 

public String parcel() 
    return "in Parcelable.parcel()...";
    

示例 SomeClass - 更改为强制数组匹配我从 Parcel 类返回的硬编码大小。如果数组只包含这些类型,那么您可以只转换为 Parcelable 而不必转换为 FirstSubClass、SecondSubClass 和 SuperClass。

/**
 */
public class SomeClass extends Parcelable 

private Parcelable[] myArray;

public SomeClass(Parcel in) 
    myArray = new SuperClass[3];
    // this is probably where the problem is due to the classloader parameter:
    //Object[] temp = in.readArray(SuperClass.class.getClassLoader());
    Object[] temp = in.readArray();

    /*
    for(int i = 0; i < 3; i++) 
        if(temp[i] instanceof FirstSubClass)
            myArray[i] = (FirstSubClass) temp[i];
        else if(temp[i] instanceof SecondSubClass)
            myArray[i] = (SecondSubClass) temp[i];
        else
            myArray[i] = (SuperClass) temp[i];
    */
    for(int i = 0; i < 3; i++) 
        myArray[i] = (Parcelable) temp[i];
    


public String parcel() 
    return "In SomeClass.parcel()...";


public void show() 
    for (Parcelable p : myArray) 
        System.out.println (p.parcel());
    


public static void main(String[] args )
    SomeClass sc = new SomeClass(new Parcel());
    sc.show();
    

示例包裹类 - 由于没有信息而不得不伪造。

/**
 */
public class Parcel 

public Object[] readArray() 
    Object[] array = new Object[3];
    array[0] = new SuperClass();
    array[1] = new FirstSubClass();
    array[2] = new SecondSubClass();
    return array;
    

示例超类

/**
 */
public class SuperClass extends Parcelable 

public String parcel() 
    return "In SuperClass.parcel()...";
    

FirtSubClass 示例

/**
 */
public class FirstSubClass extends SuperClass 

public String parcel() 
    return "In FirstSubClass.parcel()...";
    

示例 SecondSubClass

/**
 */
public class SecondSubClass extends SuperClass 

public String parcel() 
    return "In SecondSubClass.parcel()...";
    

【讨论】:

以上是关于将对象转换为 Parcelable 超类的子类?的主要内容,如果未能解决你的问题,请参考以下文章

继承

Java中类的继承

当您将对象数组转换为字符串数组时,它叫啥?

Java 只返回超类的属性

如何检查哪个子类是超类的对象? [复制]

为啥在声明子类的对象时会调用超类的构造函数? (爪哇)