Android에서 Parcel을 사용하는 방법은 무엇입니까?
Parcel
을 쓰고 다시 읽는 데 사용하려고 합니다 Parcelable
. 어떤 이유로 파일에서 객체를 다시 읽으면 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);
}
}
내가 무엇을 놓치고 있습니까?
업데이트 : 테스트를 단순화하기 위해 원래 예제에서 파일 읽기 및 쓰기를 제거했습니다.
아, 드디어 문제를 찾았습니다. 사실 두 가지가있었습니다.
- CREATOR는 공개되어야하며 보호되지 않아야합니다. 하지만 더 중요한 것은
setDataPosition(0)
데이터를 비 정렬 화 한 후에 호출해야합니다 .
수정 된 작업 코드는 다음과 같습니다.
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);
}
}
조심하세요! 파일 직렬화에 Parcel을 사용하지 마십시오.
Parcel은 범용 직렬화 메커니즘이 아닙니다. 이 클래스 (및 임의의 개체를 Parcel에 배치하기위한 해당 Parcelable API)는 고성능 IPC 전송으로 설계되었습니다. 따라서 Parcel 데이터를 영구 저장소에 배치하는 것은 적절하지 않습니다. Parcel에있는 데이터의 기본 구현을 변경하면 오래된 데이터를 읽을 수 없게 될 수 있습니다.
에서 http://developer.android.com/reference/android/os/Parcel.html
Parcelable은 Android에서 데이터 번들 내에서 가장 자주 사용되지만보다 구체적으로는 메시지를 보내고받는 핸들러 내에서 사용됩니다. 예를 들어, 당신은있을 수 있습니다 AsyncTask
또는를 Runnable
요구 백그라운드에서 실행되지만 메인 스레드에 결과 데이터를 게시하거나 것을 Activity
.
여기에 간단한 예가 있습니다. Runnable
다음과 같이 보이는 경우 :
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());
}
}
}
보시다시피이 실행 파일은 생성자에서 Handler를 사용합니다. 이것은 다음 Activity
과 같은 일부에서 호출됩니다 .
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();
}
이제 남은 것은이 질문의 핵심입니다 Parcelable
. 클래스를 . 간단한 수업으로는 볼 수없는 것이 있기 때문에 꽤 복잡한 수업을 선택했습니다. ProductInfo
Parcels 및 UnParcels 클래스 는 다음과 같습니다 .
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;
}
}
는 CREATOR
소포를 복용 결과 생성자는 그대로 중요합니다. 더 복잡한 데이터 유형을 포함하여 Parcelable 객체의 배열을 Parcel 및 UnParcel하는 방법을 볼 수 있습니다. 이 예제에서와 같이 Gson을 사용하여 JSON을 자식이있는 객체로 변환 할 때 일반적입니다.
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 :)
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
ReferenceURL : https://stackoverflow.com/questions/1626667/how-to-use-parcel-in-android
'Nice programing' 카테고리의 다른 글
다양한 .NET Framework 버전에 대한 OS 호환성 (0) | 2021.01.06 |
---|---|
When should I use GCC's -pipe option? (0) | 2021.01.06 |
사용자가 UILabel에서 복사 할 텍스트를 선택하도록 허용 (0) | 2021.01.06 |
오류시 node.js가 종료되지 않도록 설정 (0) | 2021.01.06 |
시스템이 12 시간인지 24 시간인지 어떻게 확인합니까? (0) | 2021.01.06 |