parceler

parceler

[TOC]

https://github.com/johncarl81/parceler

背景

Parcelable 有很多冗余代码;用 Java 的 Annotation Processor 生成样板代码

基本使用

相关注解

  1. 如果没有设置 ParcelConverter,那么会用 value
  2. value 默认是 Serialization.FIELD,直接 read/write 字段,Serialization.BEAN 通过 setter/getter,
  1. 作用于构造器上
  2. 用于非空构造器,指定该构造器参与 Parceler 的序列化代码生成
@Parcel(Serialization.BEAN)
public class Example {
    private final String name;
    private final int age;
    private boolean enabled;

    @ParcelConstructor
    public Example(int age, String name, boolean enabled) {
        this.age = age;
        this.name = name;
        this.enabled = enabled;
    }

    public String getName() { return name; }

    public int getAge() { return age; }

    public boolean isEnabled() { return enabled; }
}

属性和 getter/setter 混用,未搞明白

不需要序列化的字段加上

Parcels 支持的类型

byte

double

float

int

long

char

boolean

String

IBinder

Bundle

SparseArray of any of the mapped types*

SparseBooleanArray

ObservableField

List, ArrayList and LinkedList of any of the mapped types*

Map, HashMap, LinkedHashMap, SortedMap, and TreeMap of any of the mapped types*

Set, HashSet, SortedSet, TreeSet, LinkedHashSet of any of the mapped types*

Parcelable

Serializable

Array of any of the mapped types

Any other class annotated with @Parcel
List testList;

报错

Parceler: Unable to find read/write generator for type java.util.List for me.hacket.assistant.samples.三方库.parcels.Example.testList

单个 Parcelable

// wrap
intent.putExtra(KEY_DATA, Parcels.wrap(parcelModel));
// unwrap
ParcelModel mParcelModel = Parcels.unwrap(intent.getParcelableExtra(KEY_DATA));

集合

对集合类型支持友好

Parcelable listParcelable = Parcels.wrap(new ArrayList<Example>());
Parcelable mapParcelable = Parcels.wrap(new HashMap<String, Example>());

多态 (继承)

https://github.com/johncarl81/parceler#polymorphism

  1. Parceler 不能 unwrap 子类,所以任何多态字段 unwrap 后都是实例化为其基类实例,为了性能因为这不是运行时,而是编译时,不会检测 .getClass()
  2. 子类不能继承父类的@Parcel 注解,子类需要单独声明 @Parcel 注解

Serialization techniques

注意

Error:(29, 33) 错误: Parceler: Unable to find read/write generator for type android.view.View.OnClickListener for me.hacket.thirdpart.parceler.ParcelModel.mOnClickListener

默认@Parcel,测试是可以的,会反射暴力获取设置值,前提是需要有默认构造器,不建议用 private,用了暴力反射可能会出 bug

No @ParcelConstructor annotated constructor and no default empty bean constructor found.
@Parcel(Serialization.BEAN)
public class Example {
    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; }
}
位置: 程序包 club.jinmei.mgvoice.core.arouter.provider.gift
/Users/zengfansheng/Hacket/Workspace/salam/m_room/build/generated/source/kapt/devDebug/club/jinmei/mgvoice/m_room/model/message/RoomGiftMessage$Parcelable.java:86: 错误: 找不到符号
            GiftBean giftBean$0 = club.jinmei.mgvoice.core.arouter.provider.gift.GiftBean$Parcelable.read(parcel$3, identityMap$1);
For attributes that should not be serialized with Parceler, the attribute field, getter or setter may be annotated by @Transient.

非空构造器

@Parcel(Serialization.BEAN)
public class Example {
    private final String name;
    private final int age;

    @ParcelConstructor
    public Example(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public String getName() { return name; }

    public int getAge() { return age; }
}
# Parceler library
-keep interface org.parceler.Parcel
-keep @org.parceler.Parcel class * { *; }
-keep class **$Parcelable { *; }

常见问题

Kotlin 中使用 Parcel

使用 data class 时会报错

 Parceler: No @ParcelConstructor annotated constructor and noefault empty bean constructor found.

解决:

1. 将所有的构造参数都设置个默认值

kotlin 的 data class 所有参数都设置个默认值才有空构造器

@Parcel
data class User(
        val name: String? = "",
        val age: Int = 0,
        val g: Boolean = true
)

2. 加上 @ParcelConstructor,这个没测试过

https://github.com/johncarl81/parceler/issues/275

@Parcel
data class  User @ParcelConstructor constructor(
        val name: String,
        val age: Int,
        val g: Boolean
)

3. 用 Kotlin 的 @Parcelize

org.parceler.ParcelerRuntimeException: Unable to find generated Parcelable class

org.parceler.ParcelerRuntimeException: Unable to find generated Parcelable class for club.jinmei.mgvoice.m_userhome.model.UserHomeInfo, verify that your class is configured properly and that the Parcelable class club.jinmei.mgvoice.m_userhome.model.UserHomeInfo$Parcelable is generated by Parceler.

类以及加了 @Parcel 注解,但还是报错,这是因为没有添加 kapt 注解编译器

kapt commons["parceler-compiler"]