解决How to use Parcel in Android?
2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址:https://cloud.tencent.com/act/cps/redirect?redirect=1062
2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址:https://www.aliyun.com/minisite/goods
android 中Parcel 的使用,他是一个存储基本数据类型和引用数据类型的容器,在andorid 中通过IBinder来绑定数据在进程间传递数据。 Parcel parcel = Parcel.obta
I'm trying to use Parcel
to write and then read back a Parcelable
. For some reason, when I read the object back from the file, it's coming back as null
.
public void testFoo() {
final Foo orig = new Foo("blah blah");
// Wrote orig to a parcel and then byte array
final Parcel p1 = Parcel.obtain();
p1.writeValue(orig);
final byte[] bytes = p1.marshall();
// Check to make sure that the byte array seems to contain a Parcelable
assertEquals(4, bytes[0]); // Parcel.VAL_PARCELABLE
// Unmarshall a Foo from that byte array
final Parcel p2 = Parcel.obtain();
p2.unmarshall(bytes, 0, bytes.length);
final Foo result = (Foo) p2.readValue(Foo.class.getClassLoader());
assertNotNull(result); // FAIL
assertEquals( orig.str, result.str );
}
protected static class Foo implements Parcelable {
protected static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
public Foo createFromParcel(Parcel source) {
final Foo f = new Foo();
f.str = (String) source.readValue(Foo.class.getClassLoader());
return f;
}
public Foo[] newArray(int size) {
throw new UnsupportedOperationException();
}
};
public String str;
public Foo() {
}
public Foo( String s ) {
str = s;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int ignored) {
dest.writeValue(str);
}
}
What am I missing?
UPDATE: To simplify the test I've removed the reading and writing of files in my original example.
android parcel|
this question edited Nov 5 '09 at 2:41 asked Oct 26 '09 at 18:53 emmby 55.9k 50 147 208
|
5 Answers
5
解决方法
Ah, I finally found the problem. There were two in fact.
- CREATOR must be public, not protected. But more importantly,
- You must call
setDataPosition(0)
after unmarshalling your data.
Here is the revised, working code:
public void testFoo() {
final Foo orig = new Foo("blah blah");
final Parcel p1 = Parcel.obtain();
final Parcel p2 = Parcel.obtain();
final byte[] bytes;
final Foo result;
try {
p1.writeValue(orig);
bytes = p1.marshall();
// Check to make sure that the byte stream seems to contain a Parcelable
assertEquals(4, bytes[0]); // Parcel.VAL_PARCELABLE
p2.unmarshall(bytes, 0, bytes.length);
p2.setDataPosition(0);
result = (Foo) p2.readValue(Foo.class.getClassLoader());
} finally {
p1.recycle();
p2.recycle();
}
assertNotNull(result);
assertEquals( orig.str, result.str );
}
protected static class Foo implements Parcelable {
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
public Foo createFromParcel(Parcel source) {
final Foo f = new Foo();
f.str = (String) source.readValue(Foo.class.getClassLoader());
return f;
}
public Foo[] newArray(int size) {
throw new UnsupportedOperationException();
}
};
public String str;
public Foo() {
}
public Foo( String s ) {
str = s;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int ignored) {
dest.writeValue(str);
}
}
|
this answer answered Nov 5 '09 at 2:58 emmby 55.9k 50 147 208 2 you just saved my day. THANKS. – Matthias Aug 26 '10 at 16:43 Just don't try this with Bitmaps inside your Parcel(able) :( – Bojan Radivojevic Bomber Feb 8 '13 at 18:08 setDataPosition(0) saved me! thanks ;) – andrea.rinaldi.spot Jun 22 '15 at 10:12 Cool. thanks , I have more coverage now – Akshat Jan 23 at 20:59
|
Beware! Dont use Parcel for serialization to a file
Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.
from http://developer.android.com/reference/android/os/Parcel.html
|
this answer edited Aug 24 '11 at 7:50 b_yng 9,985 4 24 33 answered Jun 8 '10 at 15:50 Carl D'Halluin 697 7 13 13 How is that helpful? – skaffman Nov 25 '10 at 12:16 1 Can you suggest an alternative serialization mechanism? – aaronsnoswell Jun 20 '12 at 1:00 2 @aaronsnoswell I recommend using Kryo, or implementing the Java Externalizable interface (if your object isn't complex) – nobre Oct 8 '12 at 13:23 1 @DShaw you shouldnt use Serializable for this; it will cause tons of trouble when upgrading java version & reading old serialized data, or when upgrading your software – Carl D'Halluin Dec 17 '13 at 22:30
|
I find that Parcelable is most often used in Android within data Bundles, but more specifically within a Handler that is sending and receiving messages. As an example, you might have an AsyncTask
or a Runnable
that needs to run in the background but post resulting data to the Main thread or Activity
.
Here's a simple example. If I have a Runnable
that looks like this:
package com.example;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.example.data.ProductInfo;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.OkHttpClient;
public class AsyncRunnableExample extends Thread {
public static final String KEY = "AsyncRunnableExample_MSG_KEY";
private static final String TAG = AsyncRunnableExample.class.getSimpleName();
private static final TypeToken<ProductInfo> PRODUCTINFO =
new TypeToken<ProductInfo>() {
};
private static final Gson GSON = new Gson();
private String productCode;
OkHttpClient client;
Handler handler;
public AsyncRunnableExample(Handler handler, String productCode)
{
this.handler = handler;
this.productCode = productCode;
client = new OkHttpClient();
}
@Override
public void run() {
String url = "http://someserver/api/" + productCode;
try
{
HttpURLConnection connection = client.open(new URL(url));
InputStream is = connection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
// Deserialize HTTP response to concrete type.
ProductInfo info = GSON.fromJson(isr, PRODUCTINFO.getType());
Message msg = new Message();
Bundle b = new Bundle();
b.putParcelable(KEY, info);
msg.setData(b);
handler.sendMessage(msg);
}
catch (Exception err)
{
Log.e(TAG, err.toString());
}
}
}
As you can see, this runnable takes a Handler in its constructor. This is called from some Activity
like this:
推荐:Android - Parcel & Parcelable
对于Parcel的理解: 在Android系统中,定位为针对内存受限的设备,因此对性能要求更高,另外系统中采用了新的IPC(进程间通信)机制,必然要求使用性能更出色的对
static class MyInnerHandler extends Handler{
WeakReference<MainActivity> mActivity;
MyInnerHandler(MainActivity activity) {
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
MainActivity theActivity = mActivity.get();
ProductInfo info = (ProductInfo) msg.getData().getParcelable(AsyncRunnableExample.KEY);
// use the data from the Parcelable 'ProductInfo' class here
}
}
}
private MyInnerHandler myHandler = new MyInnerHandler(this);
@Override
public void onClick(View v) {
AsyncRunnableExample thread = new AsyncRunnableExample(myHandler, barcode.getText().toString());
thread.start();
}
Now, all that is left is the heart of this question, how you define a class as Parcelable
. I've chosen a fairly complex class to show because there are some things you would not see with a simple one. Here is the ProductInfo
class, which Parcels and unParcels cleanly:
public class ProductInfo implements Parcelable {
private String brand;
private Long id;
private String name;
private String description;
private String slug;
private String layout;
private String large_image_url;
private String render_image_url;
private String small_image_url;
private Double price;
private String public_url;
private ArrayList<ImageGroup> images;
private ArrayList<ProductInfo> related;
private Double saleprice;
private String sizes;
private String colours;
private String header;
private String footer;
private Long productcode;
// getters and setters omitted here
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeLong(id);
dest.writeString(name);
dest.writeString(description);
dest.writeString(slug);
dest.writeString(layout);
dest.writeString(large_image_url);
dest.writeString(render_image_url);
dest.writeString(small_image_url);
dest.writeDouble(price);
dest.writeString(public_url);
dest.writeParcelableArray((ImageGroup[])images.toArray(), flags);
dest.writeParcelableArray((ProductInfo[])related.toArray(), flags);
dest.writeDouble(saleprice);
dest.writeString(sizes);
dest.writeString(colours);
dest.writeString(header);
dest.writeString(footer);
dest.writeLong(productcode);
}
public ProductInfo(Parcel in)
{
id = in.readLong();
name = in.readString();
description = in.readString();
slug = in.readString();
layout = in.readString();
large_image_url = in.readString();
render_image_url = in.readString();
small_image_url = in.readString();
price = in.readDouble();
public_url = in.readString();
images = in.readArrayList(ImageGroup.class.getClassLoader());
related = in.readArrayList(ProductInfo.class.getClassLoader());
saleprice = in.readDouble();
sizes = in.readString();
colours = in.readString();
header = in.readString();
footer = in.readString();
productcode = in.readLong();
}
public static final Parcelable.Creator<ProductInfo> CREATOR = new Parcelable.Creator<ProductInfo>() {
public ProductInfo createFromParcel(Parcel in) {
return new ProductInfo(in);
}
public ProductInfo[] newArray(int size) {
return new ProductInfo[size];
}
};
@Override
public int describeContents() {
return 0;
}
}
The CREATOR
is critical, as is the resulting constructor taking a Parcel. I included the more complex data types so you could see how to Parcel and unParcel Arrays of Parcelable objects. This is a common thing when using Gson to convert JSON into objects with children as in this example.
|
this answer answered Nov 19 '13 at 16:58 David Shaw 2,850 1 8 26
|
To get a better understanding of the Parcel concept Try the below Link
http://prasanta-paul.blogspot.com/2010/06/android-parcelable-example.html
hope this helps :)
|
this answer answered Feb 23 '11 at 22:48 kAnNaN 1,903 2 20 34
|
I too had similar problem. only the following snippet from emmby and this helped me out.
public static final Parcelable.Creator<Foo> CREATOR = new Parcelable.Creator<Foo>() {
public Foo createFromParcel(Parcel source) {
final Foo f = new Foo();
f.str = (String) source.readValue(Foo.class.getClassLoader());
return f;
}
public Foo[] newArray(int size) {
throw new UnsupportedOperationException();
}
It should be kept in each of the class that implements Parcelable
|
this answer answered Dec 11 '15 at 9:46 A_rmas 172 2 14
|
一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应
一.先从Serialize说起 我们都知道JAVA中的Serialize机制,译成串行化、序列化……,其作用是能将数据对象存入字节流当中,在需要时重新生成对象。主要应
相关阅读排行
- 1Android Https相关完全解析 当OkHttp遇到Https
- 2Android APK反编译详解(附图)
- 3[置顶] Android APK反编译就这么简单 详解(附图)
- 4Android Fragment 真正的完全解析(上)
- 5Android RecyclerView 使用完全解析 体验艺术般的控件