Как использовать посылку в Android?
Я пытаюсь использовать Parcel чтобы написать, а затем прочитать обратно a 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);
}
}
что я упустил?
обновление: для упрощения теста я удалил чтение и запись файлов в моем исходном примере.
5 ответов:
Ах, я, наконец, нашел проблему. На самом деле их было двое.
- создатель должен быть публичным, а не защищенным. Но что еще более важно,
- нужно позвонить
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 не является универсальным механизмом сериализации. Этот класс (и соответствующий Parcelable API для размещения произвольных объектов в посылке) разработан как высокопроизводительный транспорт IPC. Таким образом, нецелесообразно помещать какие-либо данные участка в постоянное хранилище: изменения в базовой реализации любых данных в участке могут отображать более старые данные нечитаемый.
от 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()); } } }как вы можете видеть, этот runnable принимает обработчик в своем конструкторе. Это называется от некоторых
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класс, который посылок и 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; } }The
CREATORимеет решающее значение, как и результирующий конструктор, принимающий посылку. Я включил более сложные типы данных, чтобы вы могли см. раздел как распределять и распаковывать массивы объектов с возможностью разбиения на части. Это обычная вещь при использовании Gson для преобразования JSON в объекты с дочерними элементами, как в этом примере.
чтобы лучше понять концепцию участка, попробуйте ссылку ниже
http://prasanta-paul.blogspot.com/2010/06/android-parcelable-example.html
надеюсь, что это помогает :)
У меня тоже была подобная проблема. только следующий фрагмент из emmby и этой помог мне.
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(); }Он должен храниться в каждом классе, который реализует Parcelable
Comments