如何使自定义对象可拆分?


338

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

最好的方法是什么?

Answers:


431

您可以在此处此处(此处获取代码)此处找到一些示例。

您可以为此创建一个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类型。但是,您可以打包任何所需的数据。试试看。

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


@Rukmal Dias 10倍。实际上,我必须编辑我的答案并添加一些代码,因为这些链接在将来的某一天将不再有效。
小说

16
OP询问如何传递自定义对象而不是常规字符串。任何人都可以传递常规字符串。你能解释如何使用自定义对象创建

如果仅使用LocalBroadcastManager发送编码/解码部分,是否真的需要实现编码/解码部分?实现Parcelable并额外放置是否足够?
JohnyTex

为什么使用字符串数组而不是仅连续写入字符串?
昆汀·罗伊

writeToParcel方法内部创建字符串数组时成员的顺序重要吗?
Prakhar Mohan Srivastava'2



56

1.进口 Android Parcelable code generator

在此处输入图片说明

2.创建一个班级

public class Sample {
    int id;
    String name;
}

3.从菜单生成>可打包

在此处输入图片说明 在此处输入图片说明

做完了


7
对于那些不知道“浏览存储库”对话框在哪里的人:File > Settings... > Plugins,然后单击Browse repositories...按钮。
DaedalusAlpha

谢谢,帮了很多忙!
Strahinja Ajvaz

21

怎么样?带注释。

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

警告!

我不确定Hrisey,Lombok和其他代码生成库是否与Android的新构建系统兼容。它们在热插拔代码(即jRebel,Instant Run)上可能不能很好地玩。

优点:

  • 代码生成库使您免于样板源代码。
  • 注释使您的班级变得美丽。

缺点:

  • 它适用于简单的类。使一个复杂的类可拆分可能是棘手的。
  • 龙目岛和AspectJ的配合不好。[细节]
  • 看到我的警告。

赫里西

警告!

Hrisey在Java 8中存在一个已知问题,因此目前不能用于Android开发。请参阅#1找不到符号错误(JDK 8)

赫里斯岛是基于龙目岛。使用Hrisey的可包裹类:

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

现在,您无需实现任何Parcelable接口方法。Hrisey将在预处理阶段生成所有必需的代码。

Hrisey在Gradle依赖项中:

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

有关支持的类型,请参见此处。该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中的包裹依赖:

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

README中查找支持的属性类型


自动包裹

AutoParcelAutoValue扩展,可启用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支持Kotlin数据类,通过AutoValue扩展的Google AutoValue或仅常规Java Bean对象。

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

@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用法;对于AutoValue用户,请参见AutoValue用法


包裹生成器

ParcelableGenerator (自述文件是用中文编写的,我不理解。欢迎英语为英语的开发人员对此答案做出的贡献)

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的贴切与注解处理器工作结合的Android Studio插件助攻。



1

这很容易,您可以使用android studio上的插件将对象设为可打包对象。

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];
    }
};}

4
你是什​​么意思的插件?
naXa

0

现在,您可以使用Parceler库转换可打包的任何自定义类。只需使用@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类的对象并包装包裹,并通过intent捆绑发送。例如

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

现在要获取Custom Class对象,只需使用

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

0

Android parcable具有一些独特之处。以下是这些:

  1. 您必须按照将数据放在包裹上的相同顺序读取包裹。
  2. 从宗地读取后,宗地将为空。就是说您的地块上有3个数据。然后读取3次后,包裹将为空。

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

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方法是我们按顺序在宗地上写入/添加数据。之后,我们必须添加以下代码以从包裹中读取数据:

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代码下面给出:

放入Extra中

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");

全人课程如下

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 :)

0

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

在您的课程中实现Parcelable,然后将光标置于“ implements Parcelable”上,然后单击 Alt+Enter并选择Add Parcelable implementation(参见图片)。而已。

在此处输入图片说明


-3

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

要得到: List<Object> obj = (List<Object>)((Serializable)bundle.getSerializable("key"));


3
ClassCastException如果对象未实现,则将导致此错误Serializable
naXa 2014年

1
尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。也请尽量不要在代码中加入解释性注释,这会降低代码和解释的可读性!
Ashish Ahuja,2016年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.