Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Parcelable与Serializable

Parcelable与Serializable

作者头像
老马的编程之旅
发布于 2022-06-22 07:01:11
发布于 2022-06-22 07:01:11
1.2K00
代码可运行
举报
文章被收录于专栏:深入理解Android深入理解Android
运行总次数:0
代码可运行

由于 Java 的 Serializable 的性能较低,Parcelable 正式在这个背景下产生的,它核心作用就是为了解决 Android 中大量跨进程通信的性能问题。

Serializable使用大量反射和临时变量,而Parcelable少许反射

通过启动 Activity 过程分析 Parcelable 序列化过程:

熟悉这一过程的朋友过程肯定知道,startActivity 方法最终会通过 AMS(ActivityManagerService)完成跨进程通信调用,但是在通信之前先要将数据序列化后进行传输

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
        String resolvedType, IBinder resultTo, String resultWho, int requestCode,
        int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
    //负责写出
    Parcel data = Parcel.obtain();
    //负责读取
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(callingPackage);
    //我们分析Parcelable序列化重点在这里
    intent.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(resultTo);
    data.writeString(resultWho);
    data.writeInt(requestCode);
    data.writeInt(startFlags);
    if (profilerInfo != null) {
        data.writeInt(1);
        profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
    } else {
        data.writeInt(0);
    }
    if (options != null) {
        data.writeInt(1);
        options.writeToParcel(data, 0);
    } else {
        data.writeInt(0);
    }
    //开始跨进程通信
    mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
    reply.readException();
    int result = reply.readInt();
    reply.recycle();
    data.recycle();
    return result;
}

其中 intent.writeToParcel 是我们要重点跟踪的方法,先来看下它的参数 Parcel 类型,其实从这里的获取方式大家也能猜测的出内部使用了复用机制,就类似于 Message.obtain。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static Parcel obtain() {
    //当前缓存池,sOwnedPool是一个静态变量
    final Parcel[] pool = sOwnedPool;
    synchronized (pool) {
        Parcel p;
        //获取可以被复用的Parcel, //POOL_SIZE默认大小为6
        for (int i = 0; i < POOL_SIZE; i++) {
            p = pool[i];
            if (p != null) {
                //获取到复用对象,将该位置置为null
                pool[i] = null;
                if (DEBUG_RECYCLE) {
                    p.mStack = new RuntimeException();
                }
                //这是一个默认辅助读写
                p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
                return p;
            }
        }
    }
    //无可复用,直接创建
    return new Parcel(0);
}

从 for 循环获取可复用的 Parcel 过程,不知大家是否能够看得出这一个队列的数据结构如果从复用池获取不到则直接创建 Parcel

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private Parcel(long nativePtr) {
    if (DEBUG_RECYCLE) {
        mStack = new RuntimeException();
    }
    //初始化Parcel
    init(nativePtr);
}

//调用init
private void init(long nativePtr) {
    if (nativePtr != 0) {
        mNativePtr = nativePtr;
        mOwnsNativeParcelObject = false;
    } else {
        //此时传递为0,Parcel内存区域由我们自己创建
        //Native层Parcel地址指针
        mNativePtr = nativeCreate();
        mOwnsNativeParcelObject = true;
    }
}

实际上 Parcel 的核心实现都在 Parcel.cpp,Java 层 Parcel 只是对 native 层接口的调用封装,我们先看下 native 层 Parcel 的创建过程:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private static native long nativeCreate();

//jni注册
{"nativeCreate", "()J",(void*)android_os_Parcel_create},

//nativeCreate的具体实现
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
   //创建native层Parcel对象
   Parcel* parcel = new Parcel();
   return reinterpret_cast<jlong>(parcel);
}

有复用就一定有回收的逻辑,看下 Parcel 的回收逻辑:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final void recycle() {
    if (DEBUG_RECYCLE) mStack = null;
    //释放其native内存
    freeBuffer();

    final Parcel[] pool;
    //使用new Parcel() 默认为true
    //表示我们对它的生命周期负责
    if (mOwnsNativeParcelObject) {
        pool = sOwnedPool;
    } else {
        mNativePtr = 0;
        pool = sHolderPool;
    }

    synchronized (pool) {
        for (int i = 0; i < POOL_SIZE; i++) {
            //获取可以被缓存的位置
            if (pool[i] == null) {
                pool[i] = this;
                return;
            }
        }
    }
}

执行 intent.writeToParcel 将 Parcel 作为参数,由于采用 Intent 传递附加参数过程,最终都会保存到 Bundle 中,而 Bundle 用于实际存储数据的则是通过 Map 完成的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 //添加附加参数
 public @NonNull Intent putExtra(String name, Parcelable value) {
    if (mExtras == null) {
        //创建Bundle实例
        mExtras = new Bundle();
    }
    //实际保存在Bundle中
    mExtras.putParcelable(name, value);
    return this;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
    unparcel();
    //该mMap是一个ArrayMap实例
    mMap.put(key, value);
    mFlags &= ~FLAG_HAS_FDS_KNOWN;
}

startactivity源码中会调用writeToParcel 方法,这里实际操作在其父类 BaseBundle 的 writeToParcelInner 方法中,其中重点是 Parcelable 的序列化机制parcel.writeArrayMapInternal 方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void writeArrayMapInternal(ArrayMap<String, Object> val) {
    if (val == null) {
        writeInt(-1);
        return;
    }
    //附件参数的长度
    final int N = val.size();
    //写入时Map的长度
    writeInt(N);
    int startPos;
    for (int i = 0; i < N; i++) {
        //写入key
        writeString(val.keyAt(i));
        //写入value,每个value类型都会额外浪费4字节(Int)
        writeValue(val.valueAt(i));
    }
}

写入当前附加参数的总长度,遍历 Map 容器,由于 key 是固定类型 String,这里我们重点关注下 writeValue 方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final void writeValue(Object v) {
    if (v == null) {
        writeInt(VAL_NULL);
    } else if (v instanceof String) {
        //String类型
        writeInt(VAL_STRING);
        writeString((String) v);
    } else if (v instanceof Integer) {
        //Integer类型
        writeInt(VAL_INTEGER);
        writeInt((Integer) v);
    } else if (v instanceof Map) {
        //Map类型
        writeInt(VAL_MAP);
        writeMap((Map) v);
    } else if (v instanceof Bundle) {
        // Must be before Parcelable
        writeInt(VAL_BUNDLE);
        writeBundle((Bundle) v);
    } else if (v instanceof PersistableBundle) {
        writeInt(VAL_PERSISTABLEBUNDLE);
        writePersistableBundle((PersistableBundle) v);
    } else if (v instanceof Parcelable) {
        //Parcelable类型
        writeInt(VAL_PARCELABLE);
        writeParcelable((Parcelable) v, 0);
    } else if (v instanceof Short) {
        writeInt(VAL_SHORT);
        writeInt(((Short) v).intValue());
    } else if (v instanceof Long) {
        writeInt(VAL_LONG);
        writeLong((Long) v);
    }
    
    //... 省略
}

Value 的写入过程,系统自己定义了一套类型映射关系,每个 Value 写入都会额外附加 4 个字节的类型信息。用于表示当前 Value 的数据类型,这在后续反序列化时要根据该数据类型进行创建实例。

看下 Parcelable 的序列化过程 writeParcelable 方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final void writeParcelable(Parcelable p, int parcelableFlags) {
    if (p == null) {
        writeString(null);
        return;
    }
    //写入Parcelable的全限定名,反序列化时,需要根据该全限定名查找一个类:Classloader.loadClass
    writeParcelableCreator(p);
    //这里是否大家熟悉呢?其实回到了我们自定义的Parcelable中
    p.writeToParcel(this, parcelableFlags);
}

public final void writeParcelableCreator(Parcelable p) {
    //写入Parceable的全限定名
    String name = p.getClass().getName();
    writeString(name);
}

其中 p.writeToParcel 是否感到熟悉呢?其实这里就是回到了我们自定义 Parcelable 的 writeToParcel 方法中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void writeToParcel(Parcel dest, int flags){
    dest.writeInt(age);
    dest.writeString(name);
    dest.writeLong(serialUid);
    dest.writeCharArray(flag);
    dest.writeByteArray(like);
}

此时就是我们按照按照实际要序列化内容写入到 Parcel 内存了。

Parcelable 只是一个序列化规则,它向开发人员暴露 Parcel 操作对象,自行写入要序列化的数据。它的核心实现都在 native 层 Parcel.cpp,Java 层 Parcel 是对其接口的封装。

Parcelable 的反序列化过程 使用例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
final Bundle extra = getIntent().getExtras();
final WebParams params = extra.getParcelable(WebParams.EXTRA_PARAMS_KEY);

还是通过上面示例进行分析

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Nullable
public <T extends Parcelable> T getParcelable(@Nullable String key) {
    //解析Parcel数据
    unparcel();
    //解析数据会封装在该map中
    Object o = mMap.get(key);
    if (o == null) {
        return null;
    }
    try {
        return (T) o;
    } catch (ClassCastException e) {
        typeWarning(key, o, "Parcelable", e);
        return null;
    }
}

unparcel方法解析Parcel数据

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void unparcel() {
    synchronized (this) {
        final Parcel source = mParcelledData;
        if (source != null) {
            //这里开始从Parcel读取序列化的数据
            initializeFromParcelLocked(source, /*recycleParcel=*/ true, mParcelledByNative);
        } else {
            //...忽略
        }
    }
}

//在unparcel方法调用该方法
private void initializeFromParcelLocked(@NonNull Parcel parcelledData, boolean recycleParcel,
        boolean parcelledByNative) {

    //如果Parcel数据为空
    if (isEmptyParcel(parcelledData)) {
        if (mMap == null) {
            mMap = new ArrayMap<>(1);
        } else {
            //将Map中每个位置元素置为null,
            mMap.erase();
        }
        mParcelledData = null;
        mParcelledByNative = false;
        return;
    }
    //获取附加参数的长度,这里对应写入时Map的size
    final int count = parcelledData.readInt();
    if (count < 0) {
        return;
    }

    ArrayMap<String, Object> map = mMap;
    if (map == null) {
        //按照size创建ArrayMap
        map = new ArrayMap<>(count);
    } else {
        map.erase();
        //调整为新的长度
        map.ensureCapacity(count);
    }
    try {
        if (parcelledByNative) {
            parcelledData.readArrayMapSafelyInternal(map, count, mClassLoader);
        } else {
            parcelledData.readArrayMapInternal(map, count, mClassLoader);
        }
    } catch (BadParcelableException e) {
        if (sShouldDefuse) {
            map.erase();
        } else {
            throw e;
        }
    } finally {
        mMap = map;
        if (recycleParcel) {
            recycleParcel(parcelledData);
        }
        //解析过后一定置为null
        //避免后续get相关内容时再次发生解析
        mParcelledData = null;
        mParcelledByNative = false;
    }
}

重点在于parcelledData.readArrayMapInternal 方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void readArrayMapInternal(ArrayMap outVal, int N,
                                        ClassLoader loader) {
    if (DEBUG_ARRAY_MAP) {
        RuntimeException here = new RuntimeException("here");
        here.fillInStackTrace();
        Log.d(TAG, "Reading " + N + " ArrayMap entries", here);
    }
    int startPos;
    //根据写入时Map长度
    while (N > 0) {
        if (DEBUG_ARRAY_MAP) startPos = dataPosition();
        //读取key
        String key = readString();
        //读取Value
        Object value = readValue(loader);
        //追加到ArrayMap中,可以直接理解成put(key, valu)
        //append系统留给自己使用的
        outVal.append(key, value);
        N--;
    }
    outVal.validate();
    //此时一系列读取完毕之后,全部都保存在Bundle的Map中,
    //后续我们通过Bundle的get操作直接从该Map中获取
}

写入 Parcel 数据时,都是通过键值对的形式,key 是固定的 String 类型,所以读取时也是先通过 readString 读取 key,紧接着 readValue 方法读取对应的 value:

前面分析**序列化过程写入 value 数据时,先写入该 value 数据对应的 int 类型,该类型在反序列化时会用到,此时系统就是根据该 int 值对应的 value 类型反序列化对应数据。**我们以 readParcelable 类型为例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
    //获取对应Parcelable的Creator
    Parcelable.Creator<?> creator = readParcelableCreator(loader);
    if (creator == null) {
        return null;
    }
    if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
        //Creator也可以是ClassLoaderCreator
        //ClassLoaderCreator是Creator的子类
        Parcelable.ClassLoaderCreator<?> classLoaderCreator =
                (Parcelable.ClassLoaderCreator<?>) creator;
        return (T) classLoaderCreator.createFromParcel(this, loader);
    }
    //直接通过creatorFromParcel创建对应Parcelable
    //此时已经回到了自定义Parcelable中CREATOR内部类的createFromParcel方法
    return (T) creator.createFromParcel(this);
}

先来看 Parcelable 的 CREATOR 的获取方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public final Parcelable.Creator<?> readParcelableCreator(ClassLoader loader) {
    String name = readString();
    if (name == null) {
        return null;
    }
    Parcelable.Creator<?> creator;
    synchronized (mCreators) {
        //系统根据ClassLoader缓存Parcelable的Creator
        //获取当前类加载器缓存过的Parcelable的Creator实例
        HashMap<String, Parcelable.Creator<?>> map = mCreators.get(loader);
        if (map == null) {
            map = new HashMap<>();
            mCreators.put(loader, map);
        }
        //缓存中是否存在
        creator = map.get(name);
        if (creator == null) {
            try {
                ClassLoader parcelableClassLoader =
                        (loader == null ? getClass().getClassLoader() : loader);
                //反射获取该类对象
                Class<?> parcelableClass = Class.forName(name, false /* initialize */,
                        parcelableClassLoader);
                if (!Parcelable.class.isAssignableFrom(parcelableClass)) {
                    //必须是Parcelable类型
                    throw new BadParcelableException("Parcelable protocol requires subclassing "
                            + "from Parcelable on class " + name);
                }
                //反射获取Parcelable中CREATOR Field
                Field f = parcelableClass.getField("CREATOR");
                if ((f.getModifiers() & Modifier.STATIC) == 0) {
                    //必须是static的
                    throw new BadParcelableException("Parcelable protocol requires "
                            + "the CREATOR object to be static on class " + name);
                }
                Class<?> creatorType = f.getType();
                if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {
                    //必须是Parcelable.Creator类型
                    throw new BadParcelableException("Parcelable protocol requires a "
                            + "Parcelable.Creator object called "
                            + "CREATOR on class " + name);
                }
                //获取到该Parcelable对应的Creator实例。
                creator = (Parcelable.Creator<?>) f.get(null);
            } catch (IllegalAccessException e) {
                throw new BadParcelableException(
                        "IllegalAccessException when unmarshalling: " + name);
            } catch (ClassNotFoundException e) {
                throw new BadParcelableException(
                        "ClassNotFoundException when unmarshalling: " + name);
            } catch (NoSuchFieldException e) {
                throw new BadParcelableException("Parcelable protocol requires a "
                        + "Parcelable.Creator object called "
                        + "CREATOR on class " + name);
            }
            if (creator == null) {
                throw new BadParcelableException("Parcelable protocol requires a "
                        + "non-null Parcelable.Creator object called "
                        + "CREATOR on class " + name);
            }
            //注意,系统缓存每个使用到的Parcelable的Creator实例
            //这样下次创建对应的Parcelable时,直接通过Creator实例createFromParcel创建,
            //避免了再次反射
            map.put(name, creator);
        }
    }
    return creator;
}

系统首先根据 Classloader(不同的 Classloader 加载的 Class 对象不相等) 获取保存 CREATOR 的 Map 容器,然后根据 value 类型的全限定名在该 Map 中查找是否已经存在对应的 CREATOR 实例,否则通过 Classloader 加载该类,并反射获取该类的 CREATOR 字段;

从这里我们可以看出:Parcelable 中为什么要包含一个 CREATOR 的字段,并且一定要声明为 static,而且系统会缓存每个已经使用过的 Parcelable 的 CREATOR 实例,便于下次反序列化时直接通过 new 创建 该 Parcelable 实例。

回到 readParcelable 方法:直接调用 CREATOR 的 createFromParcel 方法,此时就回到了我们自定义的 WebParams 中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
    public WebParams createFromParcel(Parcel in) {
        return new WebParams(in);
    }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
protected WebParams(Parcel in) {
    this.age = in.readInt();
    this.name = in.readString();
    this.serialUid = in.readLong();
    in.readCharArray(flag);
    in.readByteArray(like);
}

Parcelable 只会在内存中序列化操作,并不会将数据存储到磁盘里。一般来说,如果需要持久化存储的话,一般还是不得不选择性能更差的 Serializable 方案

虽然 Parcelable 默认不支持持久化存储,但是我们也可以通过一些取巧的方式实现,在 Parcel.java 中 marshall 接口获取 byte 数组,然后存储在文件中从而实现 Parcelable 的永久存储。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-02-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android 反序列化漏洞攻防史话
Java 在历史上出现过许多反序列化的漏洞,但大部分出自 J2EE 的组件。即便是 FastJSON 这种漏洞,似乎也很少看到在 Android 中被实际的触发和利用。本文即为对历史上曾出现过的 Android Java 反序列化漏洞的分析和研究记录。
evilpan
2023/03/27
1.9K0
Android 反序列化漏洞攻防史话
Android--Binder机制与AIDL
Binder机制核心点就是利用mmap开辟一块空间,使得多个进程可以访问,不仅接收端持有该映射,内核空间也持有,由于相当于内存,所以拷贝只需要一次:从发送端进程的工作内存(用户空间)到主内存(内核空间)的内存映射中,接收端也就相当于接收到了,想要深入理解可以查看Java--深入理解JMM模型、Java并发特性
aruba
2021/12/06
9110
Android--Binder机制与AIDL
Android开发之漫漫长途 X——Android序列化
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!另外,本系列文章知识可能需要有一定Android开发基础和项目经验的同学才能更好理解,也就是说该系列文章面向的是Android中高级开发工程师。
LoveWFan
2018/08/07
4020
彻底理解Serializable和Parcelable
这里有二个关键字,存储和传输,存储的场景比如对象的持久化,传输的场景比如将对象通过网络传输,然后在需要使用的时候,反序列化,重新创建对象。
三好码农
2019/03/15
1.2K0
Android 进阶6:两种序列化方式 Serializable 和 Parcelable
张拭心 shixinzhang
2018/01/05
1.6K0
Android 进阶6:两种序列化方式 Serializable 和 Parcelable
深入了解Bundle和Map
这篇博客是在Eugenio @workingkills Marletti的帮助下完成的。
望天
2022/01/08
8660
深入了解Bundle和Map
Android项目实战(十九):Android Studio 优秀插件: Parcelable Code Generator                       Android Studi
Android Studio 优秀插件系列: Android Studio 优秀插件(一):GsonFormat Android Studio 优秀插件(二): Parcelable Code Generator ----------------------------------------------------------------------------- Parcelable  , 这个词大家应该不陌生吧,用于序列化对象的一个接口 不清楚的可以看一下这篇博客:Intent传递对象的两种方法
听着music睡
2018/05/18
1.5K0
Intent传递数据全解
可以以直接通过调用Intent的putExtra()方法存入数据,然后在获得Intent后调用getXxxExtra获得 对应类型的数据;传递多个的话,可以使用Bundle对象作为容器,通过调用Bundle的putXxx先将数据 存储到Bundle中,然后调用Intent的putExtras()方法将Bundle存入Intent中,然后获得Intent以后, 调用getExtras()获得Bundle容器,然后调用其getXXX获取对应的数据。
小小工匠
2021/08/16
9820
Android开发笔记(二十七)对象序列化
程序中存储和传递信息,需要有个合适的数据结构,最简单的是定义几个变量,变量多了之后再分门别类,便成了聚合若干变量的对象。代码在函数调用时可以直接传递对象,但更多的场合例如与文件交互、与网络交互、组件之间交互等等,就无法直接使用未经处理的对象。因此Java引入了序列化的概念,用于把一个对象转换为字节序列,然后再对这个字节序列做存储和传递操作。与之对应的是反序列化,反序列化是把一个字节序列恢复为Java对象的过程,而序列化是把Java对象转化为字节序列的过程。
aqi00
2019/01/18
6620
【Android 应用开发】BluetoothClass详解
Java中的序列化方法 : 在Java中序列化有两种方法, 一种是实现Serializable接口, 一种是实现Parcelable接口, Serializable接口是J2SE固有支持的, Parcelable是Android支持的, 是Android中特有的, 效率比Serializable高;
韩曙亮
2023/03/27
2720
Serializable和Parcelable的再次回忆
自己开发Android也有些时间了,Serializable和Parcelable遇到过不止一次了。但是每次别人问起具体的内容自己偏偏记得不是很清晰。因为某些原因再次梳理一下,以文章的形式给自己存储下来。温故而知新!!
静默加载
2020/05/31
6100
Android中的序列化:Parcelable和Serializable
概述 序列化:将一个对象转换成 可存储或 可传输的状态。 Parcelable和Serializable的区别 作用 Serializable的作用是为了保存对象的属性到本地文件、数据库、网络流、rmi以方便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。 Parcelable的设计初衷是因为Serializable效率过慢,为了在程序内不同组件间以及不同Android程序间(AIDL)高效的传输数据而设计,这些数据仅在内存中存在,Parcelable是通过IBinder通信的消息的载体。 性能比
用户1205080
2018/12/21
7990
Android Parcelable
Interface for classes whose instances can be written to and restored from a Parcel. 
阳光岛主
2019/02/19
6260
Android技能树 — 多进程相关小结
这次是讲Android存储路径及IO的基本操作。因为我们在开发的时候会经常这种方便的需求。这篇文章的内容我写的可能很少,都没有细写。别吐槽。o( ̄︶ ̄)o
青蛙要fly
2018/08/29
4570
Android技能树 — 多进程相关小结
Parcel源码上手
Parcel作为Android Binder通信的基础,从源码的角度,了解下parcel的特性,还是很有必要的。
韦东锏
2021/09/29
7440
Android跨进程通信IPC之4——AndroidIPC基础1
这里强烈建议把前面两篇文章看一遍,因为前面两篇文章对后面大家对android的IPC的理解帮助很大,本片文章主要内容如下
隔壁老李头
2018/08/30
1.3K0
Android跨进程通信IPC之4——AndroidIPC基础1
【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )
右键点击 " aidl " 目录 , 选择 " New / AIDL / AIDL File " 文件 ;
韩曙亮
2023/03/29
1.2K0
【Binder 机制】AIDL 分析 ( 创建 AIDL 文件 | 创建 Parcelable 类 | AIDL 中使用 Parcelable 类 | 编译工程生成 AIDL 对应的Java源文件 )
Kotlin 序列化Parcelable/Serializable
开发中,序列化是常见操作,在java中,我们一般会用到Serializable或者Parcelable,优缺点就不赘述了,今天来看看kotlin中的序列化。
yechaoa
2022/06/10
2K0
Android入门之数据传递
Intent数据传递 List 传递List传递List的方法 ArrayList<String> info = new ArrayList<String>(); info.add(name); info.add(website); info.add(weibo); Intent intent = new Intent(MainActivity.this, ResultActivity.class); intent.putStringArrayListExtra("infoList"
xiangzhihong
2018/02/06
8660
parcel和parcelable
Parcel 在英文中有两个意思,其一是名词,为包裹,小包的意思; 其二为动词,意为打包,扎包。邮寄快递中的包裹也用的是这个词。Android采用这个词来表示封装消息数据。这个是通过IBinder通信的消息的载体。需要明确的是Parcel用来存放数据的是内存(RAM),而不是永久性介质(Nand等)。 Parcelable,定义了将数据写入Parcel,和从Parcel中读出的接口。一个实体(用类来表示),如果需要封装到消息中去,就必须实现这一接口,实现了这一接口,该实体就成为“可打包的”了。 接口的
xiangzhihong
2018/01/30
9250
推荐阅读
相关推荐
Android 反序列化漏洞攻防史话
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档