美文网首页
kotlin Parcelable实现

kotlin Parcelable实现

作者: hao_developer | 来源:发表于2023-08-04 11:34 被阅读0次

kotlin-parcelize插件

首先,需要在gradle里面添加此插件:

plugins {
    id 'kotlin-parcelize'
}

然后,在需要 Parcelable 的数据类上添加 @kotlinx.parcelize.Parcelize 注解就行了。

改造前面的例子:

import kotlinx.parcelize.Parcelize

@Parcelize
data class User(
    val name: String?,
    val updatedTime: Long
): Parcelable {
    override fun toString(): String = "new: $name - [${
        DateFormat.getInstance().format(Date(updatedTime))
    }]"
}

看看上述代码对应的字节码吧:

@Metadata(
   mv = {1, 6, 0},
   k = 1,
   d1 = {"\u0000:\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\n\u0002\u0010\t\n\u0002\b\t\n\u0002\u0010\b\n\u0000\n\u0002\u0010\u000b\n\u0000\n\u0002\u0010\u0000\n\u0002\b\u0003\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\b\u0087\b\u0018\u00002\u00020\u0001B\u0017\u0012\b\u0010\u0002\u001a\u0004\u0018\u00010\u0003\u0012\u0006\u0010\u0004\u001a\u00020\u0005¢\u0006\u0002\u0010\u0006J\u000b\u0010\u000b\u001a\u0004\u0018\u00010\u0003HÆ\u0003J\t\u0010\f\u001a\u00020\u0005HÆ\u0003J\u001f\u0010\r\u001a\u00020\u00002\n\b\u0002\u0010\u0002\u001a\u0004\u0018\u00010\u00032\b\b\u0002\u0010\u0004\u001a\u00020\u0005HÆ\u0001J\t\u0010\u000e\u001a\u00020\u000fHÖ\u0001J\u0013\u0010\u0010\u001a\u00020\u00112\b\u0010\u0012\u001a\u0004\u0018\u00010\u0013HÖ\u0003J\t\u0010\u0014\u001a\u00020\u000fHÖ\u0001J\b\u0010\u0015\u001a\u00020\u0003H\u0016J\u0019\u0010\u0016\u001a\u00020\u00172\u0006\u0010\u0018\u001a\u00020\u00192\u0006\u0010\u001a\u001a\u00020\u000fHÖ\u0001R\u0013\u0010\u0002\u001a\u0004\u0018\u00010\u0003¢\u0006\b\n\u0000\u001a\u0004\b\u0007\u0010\bR\u0011\u0010\u0004\u001a\u00020\u0005¢\u0006\b\n\u0000\u001a\u0004\b\t\u0010\n¨\u0006\u001b"},
   d2 = {"Lcom/jacee/example/parcelabletest/data/User;", "Landroid/os/Parcelable;", "name", "", "updatedTime", "", "(Ljava/lang/String;J)V", "getName", "()Ljava/lang/String;", "getUpdatedTime", "()J", "component1", "component2", "copy", "describeContents", "", "equals", "", "other", "", "hashCode", "toString", "writeToParcel", "", "parcel", "Landroid/os/Parcel;", "flags", "parcelable-test_debug"}
)
@Parcelize
public final class User implements Parcelable {
   @Nullable
   private final String name;
   private final long updatedTime;
   public static final android.os.Parcelable.Creator CREATOR = new User.Creator();

   @NotNull
   public String toString() {
      return "new: " + this.name + " - [" + DateFormat.getInstance().format(new Date(this.updatedTime)) + ']';
   }

   @Nullable
   public final String getName() {
      return this.name;
   }

   public final long getUpdatedTime() {
      return this.updatedTime;
   }

   public User(@Nullable String name, long updatedTime) {
      this.name = name;
      this.updatedTime = updatedTime;
   }

   @Nullable
   public final String component1() {
      return this.name;
   }

   public final long component2() {
      return this.updatedTime;
   }

   @NotNull
   public final User copy(@Nullable String name, long updatedTime) {
      return new User(name, updatedTime);
   }

   // $FF: synthetic method
   public static User copy$default(User var0, String var1, long var2, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.name;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.updatedTime;
      }

      return var0.copy(var1, var2);
   }

   public int hashCode() {
      String var10000 = this.name;
      return (var10000 != null ? var10000.hashCode() : 0) * 31 + Long.hashCode(this.updatedTime);
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof User) {
            User var2 = (User)var1;
            if (Intrinsics.areEqual(this.name, var2.name) && this.updatedTime == var2.updatedTime) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }

   public int describeContents() {
      return 0;
   }

   public void writeToParcel(@NotNull Parcel parcel, int flags) {
      Intrinsics.checkNotNullParameter(parcel, "parcel");
      parcel.writeString(this.name);
      parcel.writeLong(this.updatedTime);
   }

   @Metadata(
      mv = {1, 6, 0},
      k = 3
   )
   public static class Creator implements android.os.Parcelable.Creator {
      @NotNull
      public final User[] newArray(int size) {
         return new User[size];
      }

      // $FF: synthetic method
      // $FF: bridge method
      public Object[] newArray(int var1) {
         return this.newArray(var1);
      }

      @NotNull
      public final User createFromParcel(@NotNull Parcel in) {
         Intrinsics.checkNotNullParameter(in, "in");
         return new User(in.readString(), in.readLong());
      }

      // $FF: synthetic method
      // $FF: bridge method
      public Object createFromParcel(Parcel var1) {
         return this.createFromParcel(var1);
      }
   }
}

复杂的序列化逻辑

如果需要添加更复杂的序列化逻辑,就需要额外通过伴随对象实现,该对象需要实现接口 Parceler

interface Parceler<T> {
    /**
     * Writes the [T] instance state to the [parcel].
     */
    fun T.write(parcel: Parcel, flags: Int)

    /**
     * Reads the [T] instance state from the [parcel], constructs the new [T] instance and returns it.
     */
    fun create(parcel: Parcel): T

    /**
     * Returns a new [Array]<T> with the given array [size].
     */
    fun newArray(size: Int): Array<T> {
        throw NotImplementedError("Generated by Android Extensions automatically")
    }
}

看样子,Parceler 和原生 Parcelable.Creator 十分像啊,不过多了一个 write 函数 —— 其实就是对应了Parcelable.writeToParcel方法。

简单打印点日志模拟所谓的“复杂的序列化逻辑”:

@Parcelize
data class User(
    val name: String?,
    val updatedTime: Long
): Parcelable {
    override fun toString(): String = "new: $name - [${
        DateFormat.getInstance().format(Date(updatedTime))
    }]"

    private companion object : Parceler<User> {
        override fun create(parcel: Parcel): User {
            Log.d("p-test", "new: create")
            return User(parcel.readString(), parcel.readLong())
        }

        override fun User.write(parcel: Parcel, flags: Int) {
            Log.d("p-test", "new: write to")
            parcel.writeString("【${name}】")
            parcel.writeLong(updatedTime)
        }

    }
}

映射序列化

假如数据类不能直接支持序列化,那就可以通过自定义一个 **Parceler **,实现映射序列化。
怎么理解呢?假如有一个数据类A,是一个普通实现,不支持序列化(或者有其他原因,总之是不支持),但是呢,我们又有需求是将它序列化后使用,这时候就可以实现 ** Parceler<A> ** 类,然后用包裹A的类B来实现序列化 —— 即, **通过Parceler,将普通的A包裹成了序列化的B **。

// 目标数据类A
data class User(
    val name: String?,
    val updatedTime: Long
) {
    override fun toString(): String = "new: $name - [${
        DateFormat.getInstance().format(Date(updatedTime))
    }]"
}

// 实现的Parceler<A>
object UserParceler: Parceler<User> {
    override fun create(parcel: Parcel): User {
        Log.d("djx_test", "1 new: create")
        return User(parcel.readString(), parcel.readLong())
    }

    override fun User.write(parcel: Parcel, flags: Int) {
        Log.d("djx_test", "1 new: write to")
        parcel.writeString("【${name}】")
        parcel.writeLong(updatedTime)
    }
}

// 映射类B
@Parcelize
@TypeParceler<User, UserParceler>
class Target(val value: User): Parcelable // 这个类来实现Parcelable

上面的映射类B,还可以这么写:

@Parcelize
class Target(@TypeParceler<User, UserParceler> val value: User): Parcelable

// 或

@Parcelize
class Target(val value: @WriteWith<UserParceler> User): Parcelable

相关文章

网友评论

      本文标题:kotlin Parcelable实现

      本文链接:https://www.haomeiwen.com/subject/ykmvpdtx.html