如何使我的自定义对象 Parcelable?

Posted

技术标签:

【中文标题】如何使我的自定义对象 Parcelable?【英文标题】:How can I make my custom objects Parcelable? 【发布时间】:2011-11-03 03:16:30 【问题描述】:

我正在尝试使我的对象可包裹。但是,我有自定义对象,这些对象具有我制作的其他自定义对象的 ArrayList 属性。

最好的方法是什么?

【问题讨论】:

【参考方案1】:

您可以找到here、here (code is taken here) 和 here 的一些示例。

您可以为此创建一个 POJO 类,但您需要添加一些额外的代码来使其成为Parcelable。看看实现。

public class Student implements Parcelable
        private String id;
        private String name;
        private String grade;

        // Constructor
        public Student(String id, String name, String grade)
            this.id = id;
            this.name = name;
            this.grade = grade;
       
       // Getter and setter methods
       .........
       .........

       // Parcelling part
       public Student(Parcel in)
           String[] data = new String[3];

           in.readStringArray(data);
           // the order needs to be the same as in writeToParcel() method
           this.id = data[0];
           this.name = data[1];
           this.grade = data[2];
       

       @Оverride
       public int describeContents()
           return 0;
       

       @Override
       public void writeToParcel(Parcel dest, int flags) 
           dest.writeStringArray(new String[] this.id,
                                               this.name,
                                               this.grade);
       
       public static final Parcelable.Creator CREATOR = new Parcelable.Creator() 
           public Student createFromParcel(Parcel in) 
               return new Student(in); 
           

           public Student[] newArray(int size) 
               return new Student[size];
           
       ;
   

一旦你创建了这个类,你就可以像这样通过Intent轻松地传递这个类的对象,并在目标活动中恢复这个对象。

intent.putExtra("student", new Student("1","Mike","6"));

在这里,学生是您从捆绑包中解包数据所需的密钥。

Bundle data = getIntent().getExtras();
Student student = (Student) data.getParcelable("student");

此示例仅显示 String 类型。但是,您可以打包任何类型的数据。试试看。

编辑:另一个example,由Rukmal Dias 建议。

【讨论】:

@Rukmal Dias 10x。事实上,我必须编辑我的答案并添加一些代码,因为这些链接在未来的某一天将不再有效。 OP 询问如何传递自定义对象而不是常规字符串。任何人都可以传递常规字符串。你能解释一下如何用 CUSTOM OBJECT 创建它 如果我只使用 LocalBroadcastManager 发送编码/解码部分,我是否必须实际实现它们?实现 Parcelable 和 put as extra 就够了吗? 为什么要使用字符串数组而不是逐个写入字符串? writeToParcel 方法中创建字符串数组时成员的顺序是否重要?【参考方案2】:

这是一个从您创建的类创建 Parcelable 类的网站:

http://www.parcelabler.com/

【讨论】:

【参考方案3】:

IntelliJ IDEA 和 android Studio 有插件:

★Android Parcelable code generator(阿帕奇License2.0) Auto Parcel(麻省理工学院License) SerializableParcelable Generator(麻省理工学院License) Parcelable Code Generator (for Kotlin) (Apache License 2.0)

这些插件根据类中的字段生成 Android Parcelable 样板代码。

【讨论】:

用一种新的方式来做这些事情,太棒了!【参考方案4】:

1。导入Android Parcelable code generator

2。创建一个类

public class Sample 
    int id;
    String name;

3。 Generate > Parcelable from menu

完成。

【讨论】:

对于那些不知道浏览存储库对话框在哪里的人:File > Settings... > Plugins 并点击Browse repositories... 按钮。 谢谢,帮了大忙!【参考方案5】:

怎么样?带注释。

您只需使用特殊注释对 POJO 进行注释,其余的由库完成。

警告!

我不确定 Hrisey、Lombok 和其他代码生成库是否与 Android 的新构建系统兼容。他们可能会也可能不会很好地使用热交换代码(即 jRebel、Instant Run)。

优点:

代码生成库将您从样板源代码中解救出来。 注释让你的课堂更漂亮。

缺点:

它适用于简单的类。使复杂的类可打包可能很棘手。 Lo​​mbok 和 AspectJ 不能很好地配合使用。 [details] 查看我的警告。

赫里斯

警告!

Hrisey 在 Java 8 中存在一个已知问题,因此目前无法用于 Android 开发。 见#1 Cannot find symbol errors (JDK 8)。

Hrisey 基于Lombok。使用Hrisey的Parcelable类:

@hrisey.Parcelable
public final class POJOClass implements android.os.Parcelable 
    /* Fields, accessors, default constructor */

现在你不需要实现 Parcelable 接口的任何方法。 Hrisey 将在预处理阶段生成所有需要的代码。

Gradle 依赖项中的 Hrisey:

provided "pl.mg6.hrisey:hrisey:$hrisey.version"

See here 用于支持的类型。 ArrayList 就是其中之一。

为您的 IDE 安装一个插件 - Hrisey xor Lombok* - 并开始使用其惊人的功能!

* 不要同时启用 Hrisey 和 Lombok 插件,否则在 IDE 启动期间会出现错误。


打包机

使用Parceler的Parcelable类:

@java.org.parceler.Parcel
public class POJOClass 
    /* Fields, accessors, default constructor */

要使用生成的代码,您可以直接引用生成的类,或通过Parcels 实用程序类使用

public static <T> Parcelable wrap(T input);

要取消引用@Parcel,只需调用Parcels类的以下方法

public static <T> T unwrap(Parcelable input);

Gradle 依赖项中的 Parceler:

compile "org.parceler:parceler-api:$parceler.version"
provided "org.parceler:parceler:$parceler.version"

查看README 以获得支持的attribute types。


自动包裹

AutoParcel 是一个AutoValue 扩展,可以生成 Parcelable 值。

只需将 implements Parcelable 添加到您的 @AutoValue 注释模型中:

@AutoValue
abstract class POJOClass implements Parcelable 
    /* Note that the class is abstract */
    /* Abstract fields, abstract accessors */

    static POJOClass create(/*abstract fields*/) 
        return new AutoValue_POJOClass(/*abstract fields*/);
    

Gradle 构建文件中的 AutoParcel:

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'

repositories 
    /*...*/
    maven url "https://clojars.org/repo/"


dependencies 
    apt "frankiesardo:auto-parcel:$autoparcel.version"


纸包

PaperParcel 是一个注解处理器,可以自动为 Kotlin 和 Java 生成类型安全的 Parcelable 样板代码。 PaperParcel 通过 AutoValue 扩展支持 Kotlin 数据类、Google 的 AutoValue,或者只是普通的 Java bean 对象。

来自docs的用法示例。 使用@PaperParcel 注释您的数据类,实现PaperParcelable,并添加PaperParcelable.Creator 的JVM 静态实例,例如:

@PaperParcel
public final class Example extends PaperParcelable 
    public static final PaperParcelable.Creator<Example> CREATOR = new PaperParcelable.Creator<>(Example.class);

    private final int test;

    public Example(int test) 
        this.test = test;
    

    public int getTest() 
        return test;
    

对于 Kotlin 用户,请参阅 Kotlin Usage;对于 AutoValue 用户,请参阅AutoValue Usage。


ParcelableGenerator

ParcelableGenerator (README 是用中文写的,我看不懂。欢迎讲中文的开发者对此答案的贡献)

来自README 的用法示例。

import com.baoyz.pg.Parcelable;

@Parcelable
public class User 

    private String name;
    private int age;

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public int getAge() 
        return age;
    

    public void setAge(int age) 
        this.age = age;
    



android-apt 插件有助于将注释处理器与 Android Studio 结合使用。

【讨论】:

【参考方案6】:

在 Android Studio 中创建不带插件的 Parcelable 类

在你的类中实现 Parcelable,然后将光标放在“implements Parcelable”上并点击Alt+Enter 并选择Add Parcelable implementation(见图)。就是这样。

【讨论】:

【参考方案7】:

我找到了创建 Parcelable 类

的最简单方法

【讨论】:

它适用于小数据,但如果我们采用复杂数据,这将不起作用【参考方案8】:

很简单,你可以使用android studio上的一个插件来制作对象Parcelables。

public class Persona implements Parcelable 
String nombre;
int edad;
Date fechaNacimiento;

public Persona(String nombre, int edad, Date fechaNacimiento) 
    this.nombre = nombre;
    this.edad = edad;
    this.fechaNacimiento = fechaNacimiento;


@Override
public int describeContents() 
    return 0;


@Override
public void writeToParcel(Parcel dest, int flags) 
    dest.writeString(this.nombre);
    dest.writeInt(this.edad);
    dest.writeLong(fechaNacimiento != null ? fechaNacimiento.getTime() : -1);


protected Persona(Parcel in) 
    this.nombre = in.readString();
    this.edad = in.readInt();
    long tmpFechaNacimiento = in.readLong();
    this.fechaNacimiento = tmpFechaNacimiento == -1 ? null : new Date(tmpFechaNacimiento);


public static final Parcelable.Creator<Persona> CREATOR = new Parcelable.Creator<Persona>() 
    public Persona createFromParcel(Parcel source) 
        return new Persona(source);
    

    public Persona[] newArray(int size) 
        return new Persona[size];
    
;

【讨论】:

你是什么插件?【参考方案9】:

现在您可以使用 Parceler 库将您的任何自定义类转换为 parcelable。只需使用 @Parcel 注释您的 POJO 类。 例如

    @Parcel
    public class Example 
    String name;
    int id;

    public Example() 

    public Example(int id, String name) 
        this.id = id;
        this.name = name;
    

    public String getName()  return name; 

    public int getId()  return id; 

您可以创建 Example 类的对象并通过 Parcels 包装并通过 Intent 作为捆绑发送。例如

Bundle bundle = new Bundle();
bundle.putParcelable("example", Parcels.wrap(example));

现在要获取自定义类对象,只需使用

Example example = Parcels.unwrap(getIntent().getParcelableExtra("example"));

【讨论】:

【参考方案10】:

Android parcable 有一些独特的东西。这些在下面给出:

    您必须按照在包裹上放置数据的相同顺序读取包裹。 从包裹读取后包裹将清空。也就是说,如果您的包裹上有 3 个数据。然后在读取 3 次后包裹将是空的。

示例: 要创建一个 Parceble 类,它必须实现 Parceble。 Percable 有两种方法:

int describeContents();
void writeToParcel(Parcel var1, int var2);

假设你有一个 Person 类,它有 3 个字段,firstName、lastName 和 age。实现 Parceble 接口后。该界面如下:

import android.os.Parcel;
import android.os.Parcelable;
public class Person implements Parcelable
    private String firstName;
    private String lastName;
    private int age;

    public void setFirstName(String firstName) 
        this.firstName = firstName;
    

    public String getFirstName() 
        return firstName;
    

    public void setLastName(String lastName) 
        this.lastName = lastName;
    

    public String getLastName() 
        return lastName;
    

    public void setAge(int age) 
        this.age = age;
    

    public int getAge() 
        return age;
    

    @Override
    public int describeContents() 
        return 0;
    

    @Override
    public void writeToParcel(Parcel parcel, int i) 
        parcel.writeString(firstName);
        parcel.writeString(lastName);
        parcel.writeInt(age);
    


writeToParcel 方法中,我们正在按顺序在 Parcel 上写入/添加数据。在此之后,我们必须添加以下代码以从包裹中读取数据:

protected Person(Parcel in) 
        firstName = in.readString();
        lastName = in.readString();
        age = in.readInt();
    

    public static final Creator<Person> CREATOR = new Creator<Person>() 
        @Override
        public Person createFromParcel(Parcel in) 
            return new Person(in);
        

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

这里,Person 类在写入过程中以相同的顺序接收包裹并获取数据。

现在在意图getExtraputExtra 代码如下:

放入额外的

Person person=new Person();
                person.setFirstName("First");
                person.setLastName("Name");
                person.setAge(30);

                Intent intent = new Intent(getApplicationContext(), SECOND_ACTIVITY.class);
                intent.putExtra()
                startActivity(intent); 

获得额外奖励:

Person person=getIntent().getParcelableExtra("person");

下面给出了完整的 Person 类

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

public class Person implements Parcelable
    private String firstName;
    private String lastName;
    private int age;



    public void setFirstName(String firstName) 
        this.firstName = firstName;
    

    public String getFirstName() 
        return firstName;
    

    public void setLastName(String lastName) 
        this.lastName = lastName;
    

    public String getLastName() 
        return lastName;
    

    public void setAge(int age) 
        this.age = age;
    

    public int getAge() 
        return age;
    

    @Override
    public int describeContents() 
        return 0;
    

    @Override
    public void writeToParcel(Parcel parcel, int i) 
        parcel.writeString(firstName);
        parcel.writeString(lastName);
        parcel.writeInt(age);
    

    protected Person(Parcel in) 
        firstName = in.readString();
        lastName = in.readString();
        age = in.readInt();
    

    public static final Creator<Person> CREATOR = new Creator<Person>() 
        @Override
        public Person createFromParcel(Parcel in) 
            return new Person(in);
        

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



Hope this will help you 
Thanks :)

【讨论】:

【参考方案11】:

说: bundle.putSerializable("key",(Serializable) object);

要获得: List&lt;Object&gt; obj = (List&lt;Object&gt;)((Serializable)bundle.getSerializable("key"));

【讨论】:

如果对象没有实现Serializable,这将导致ClassCastException 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性的 cmets 挤满你的代码,这会降低代码和解释的可读性!

以上是关于如何使我的自定义对象 Parcelable?的主要内容,如果未能解决你的问题,请参考以下文章

在 XAML 中调用时,如何使我的自定义依赖项属性排序到顶部?

如何使我的自定义 HTML 小部件针对不同的屏幕尺寸显示不同?

如何使我的自定义 ViewModifier 仅适用于 SwiftUI 中符合(可识别和视图)的内容/视图?

Android Parcelable 和 Serializable

通过 Parcelable 发送嵌套 ArrayList 时出现 NullPointerException

如何修复横向截止的自定义 SearchView 背景?