2012-11-16 28 views
8

Trong dự án của tôi, tôi có một mô hình lưu giữ thông tin cơ bản về mô hình. Ví dụ, cho phép nói rằng mô hình là một chiếc xe hơi. Sau đó, có rất nhiều loại xe khác nhau và chúng có dữ liệu khác nhau được gán cho chúng. Tất cả các mô hình phải là bưu kiện.Khớp nối bên trong gói được thêm vào Bưu kiện

Sự khác biệt giữa các loại xe khác nhau là rất nhỏ, nó có thể chỉ là một vài trường dữ liệu. Vì vậy, điều này được giải quyết bằng cách tạo ra diễn giả (chỉ là một lớp chứa dữ liệu) cho những chiếc xe khác nhau. Người trình bày sau đó sẽ biết thêm dữ liệu nào cần lưu giữ. Bởi vì bản thân người trình bày không thể chuyển nhượng được, nó sẽ có một gói cho tất cả các dữ liệu của nó, sau đó lớp Car sau đó sẽ thêm vào bưu kiện. Tôi không muốn biến các diễn giả thành bưu kiện.

Vì vậy, Xe đưa Bundle từ người dẫn chương trình và đặt nó trong bưu kiện của nó:

public void writeToParcel(Parcel parcel, int flags) { 
    parcel.writeBundle(getPresenter().getBundle()); 
    } 

Và sau đó nó sẽ giải nén nó với:

public Car(Parcel parcel) {  
    getPresenter().setBundle(parcel.readBundle()); 
    } 

này hoạt động tốt cho đến khi một đối tượng parcelable được thêm cho nhóm bởi người trình bày. Sau đó, tôi nhận được lỗi này:

11-16 15:06:37.255: E/AndroidRuntime(15193): FATAL EXCEPTION: main 
11-16 15:06:37.255: E/AndroidRuntime(15193): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.activity}: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.model.engine 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2185) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2210) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.app.ActivityThread.access$600(ActivityThread.java:142) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1208) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Handler.dispatchMessage(Handler.java:99) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Looper.loop(Looper.java:137) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.app.ActivityThread.main(ActivityThread.java:4931) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at java.lang.reflect.Method.invokeNative(Native Method) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at java.lang.reflect.Method.invoke(Method.java:511) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at dalvik.system.NativeStart.main(Native Method) 
11-16 15:06:37.255: E/AndroidRuntime(15193): Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.model.engine 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Parcel.readParcelable(Parcel.java:2077) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Parcel.readValue(Parcel.java:1965) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Parcel.readMapInternal(Parcel.java:2226) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Bundle.unparcel(Bundle.java:223) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at android.os.Bundle.getString(Bundle.java:1055) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   at com.example.cars.CarPresenter.getExtraString(CarPresenter.java:34) 
11-16 15:06:37.255: E/AndroidRuntime(15193):   ... 11 more 

Vì vậy, bằng cách nào đó, không đọc được gì từ Gói.

Điều này có thể được giải quyết bằng cách thay đổi các cuộc gọi readBundle tới:

public Car(Parcel parcel) {  
    getPresenter().setBundle(parcel.readBundle(engine.class.getClassLoader())); 
    } 

Tuy nhiên, điều này sẽ không có nghĩa là tôi chỉ có thể có một loại parcelables trong bó của tôi? Ví dụ: nếu người trình bày khác muốn thêm một đối tượng có thể đặt hàng khác vào nhóm được thì sao?

Có ai có thể làm sáng tỏ điều này không?

Trả lời

15

Bạn đã viết trong nhận xét:

However, my question was ment to be more of why do I even have to specify a class loader in this case

Dianne Hackborn, kỹ sư khuôn khổ Android, writes rằng:

when the bundle reads from the parcel it just extracts the data. It doesn't actually unparcel from that data until later when you retrieve stuff from the bundle.

Trong Bundle source code, chúng ta thấy rằng phương pháp setClassLoader() bộ lĩnh vực mClassLoader:

public void setClassLoader(ClassLoader loader) { 
    mClassLoader = loader; 
} 

Nếu chúng ta không sử dụng setClassLoader() hoặc hàm tạo Bundle(ClassLoader loader), trường mClassLoader sẽ được đặt thành mặc định ClassLoader:

public Bundle(int capacity) { 
    //... 
    mClassLoader = getClass().getClassLoader(); 
} 

mClassLoader sau đó được sử dụng để unmarshal dữ liệu parceled trong phương pháp unparcel():

mParcelledData.readMapInternal(mMap, N, mClassLoader); 
mParcelledData.recycle(); 
mParcelledData = null; 

Net, nếu bạn không thiết lập các ClassLoader nó sẽ mặc định hệ thống ClassLoader khi unmarshalling dữ liệu parceled của nó, và chúng tôi sẽ nhận được ClassNotFoundException khi không sửa đổi dữ liệu đối tượng tùy chỉnh Parcelable của chúng tôi,

+0

Tôi biết những điều cơ bản về bưu kiện và nó đang hoạt động ở mọi nơi khác trong ứng dụng của tôi. Engine thực thi Parcelable. Vấn đề là nếu tôi đặt một kiện trong một bó, và sau đó các gói trong một bưu kiện, tôi không thể giải nén các hình thức có thể thửa gói (hoặc bất kỳ lĩnh vực khác trong gói). – Heinrisch

+0

Có, tôi đã thử điều đó và tôi nghĩ rằng nó không hoạt động. Tuy nhiên, câu hỏi của tôi đã được ment để được nhiều hơn lý do tại sao tôi thậm chí phải chỉ định một bộ nạp lớp trong trường hợp này. – Heinrisch

+0

Tôi đã cập nhật câu trả lời của mình. –

-3

Đây là mẫu của tôi mà thực hiện Parcelable:

public class ProgramModel implements Parcelable 
{ 
    private int id = -1; 
    private String title = ""; 
    private String time = ""; 
    private String day = ""; 
    private String organization = ""; 
    private String participants = ""; 
    private String description = ""; 
    private String descriptionFull = ""; 
    private String location = ""; 
    private String locationCaption = ""; 
    private int locationCode = 0; 
    private String locationMap = ""; 
    private String imageUrl = ""; 
    private String color = ""; 
    private int colorId = -1; 
    private int columnId = -1; 
    private String startTime = ""; 
    private String endTime = ""; 
    private Date convertedTimeStart = null; 
    private Date convertedTimeEnd = null; 
    private String theme = ""; 
    private ArrayList<TagModel> tags = new ArrayList<TagModel>(); 
    private ArrayList<Integer> tagsId = new ArrayList<Integer>(); 

    public ProgramModel() 
    { 
    } 

    private ProgramModel(Parcel in) 
    { 
     id = in.readInt(); 
     title = in.readString(); 
     time = in.readString(); 
     day = in.readString(); 
     organization = in.readString(); 
     participants = in.readString(); 
     description = in.readString(); 
     descriptionFull = in.readString(); 
     location = in.readString(); 
     locationCaption = in.readString(); 
     locationCode = in.readInt(); 
     locationMap = in.readString(); 
     imageUrl = in.readString(); 
     color = in.readString(); 
     colorId = in.readInt(); 
     columnId = in.readInt(); 
     startTime = in.readString(); 
     endTime = in.readString(); 
     convertedTimeStart = new Date(in.readLong()); 
     convertedTimeEnd = new Date(in.readLong()); 
     theme = in.readString(); 
     in.readTypedList(tags, TagModel.CREATOR); 
     in.readList(tagsId, Integer.class.getClassLoader()); 
    } 

    public int getId() 
    { 
     return id; 
    } 

    public void setId(int id) 
    { 
     this.id = id; 
    } 

    // Other getters and setters 

    @Override 
    public int describeContents() 
    { 
     return 0; 
    } 

    // this is used to regenerate your object 
    public static final Parcelable.Creator<ProgramModel> CREATOR = new Parcelable.Creator<ProgramModel>() 
    { 
     public ProgramModel createFromParcel(Parcel in) 
     { 
      return new ProgramModel(in); 
     } 

     public ProgramModel[] newArray(int size) 
     { 
      return new ProgramModel[size]; 
     } 
    }; 

    @Override 
    public void writeToParcel(Parcel out, int flags) 
    { 
     out.writeInt(id); 
     out.writeString(title); 
     out.writeString(time); 
     out.writeString(day); 
     out.writeString(organization); 
     out.writeString(participants); 
     out.writeString(description); 
     out.writeString(descriptionFull); 
     out.writeString(location); 
     out.writeString(locationCaption); 
     out.writeInt(locationCode); 
     out.writeString(locationMap); 
     out.writeString(imageUrl); 
     out.writeString(color); 
     out.writeInt(colorId); 
     out.writeInt(columnId); 
     out.writeString(startTime); 
     out.writeString(endTime); 
     out.writeLong(convertedTimeStart.getTime()); 
     out.writeLong(convertedTimeEnd.getTime()); 
     out.writeString(theme); 
     out.writeTypedList(tags); 
     out.writeList(tagsId); 
    } 
} 

Viết dữ liệu vào mục đích trong Hoạt động:

Intent intent = new Intent(FirstActivity.this, SecondActivity.class); 
intent.putExtra("ProgramModel", programDetailsModel); 
startActivity(intent); 

đọc dữ liệu từ bó trong Hoạt động:

@Override 
public void onCreate(Bundle savedInstanceState) 
{ 
    super.onCreate(savedInstanceState); 
    savedInstanceState = getIntent().getExtras(); 
    if (savedInstanceState != null) 
    { 
     fromBundleModel = savedInstanceState.getParcelable("ProgramModel"); 
    } 
} 
+1

Tôi có rất nhiều mô hình thực hiện gói được ... cho tôi không có gì mới. – Heinrisch

3

Bạn đã viết:

This can be solved by modifying the readBundle call to:

public Car(Parcel parcel) { getPresenter().setBundle(parcel.readBundle(engine.class.getClassLoader())); }

However, wouldn't this mean that I could only have one type of parcelables in my bundle? For example, what if another presenter wanted to add another parcelable object to the bundle?

Thực ra, không. Khi bạn đặt classLoader thành engine.class.getClassLoader(), bạn đang thực sự cung cấp trình tải lớp để biết cách tải tất cả các lớp từ APK của bạn. Vì vậy, bạn có thể sử dụng cùng một trình nạp lớp để loại bỏ tất cả các lớp tùy chỉnh khác trong ứng dụng của bạn thực hiện Parcelable.

Vấn đề bạn đang thấy là khi bạn không chỉ định trình nạp lớp, trình nạp lớp hệ thống (mặc định) được sử dụng để tách biệt Bundle. Trình nạp lớp hệ thống chỉ biết cách tải các lớp được biết đến với hệ thống Android và không biết cách tải bất kỳ lớp ứng dụng cụ thể nào.

Chỉ cần làm rõ, (nói chung) không có "trình nạp lớp cho mỗi lớp", có trình nạp lớp hệ thống và sau đó có "trình nạp lớp cho mỗi ứng dụng". Tôi mong bạn trả lời câu hỏi này.

12

Trình nạp lớp là một trong những tính năng ít được hiểu nhất của Java. Họ cung cấp "Không gian tên", và trên thực tế, các không gian tên đó có thể "lồng ghép" bằng thực tế là nếu một lớp không được tìm thấy bởi ClassLoader hiện tại, nó có thể kiểm tra một ClassLoader "cha mẹ".

Trong trường hợp ứng dụng Android có hai Trình nạp lớp. Có một cách biết cách tải các lớp học từ APK của bạn và một lớp học biết cách tải các lớp học từ khung công tác Android.Cái cũ có cái sau được đặt làm bộ nạp lớp "Cha mẹ" nên nói chung bạn không nhận thấy. Tuy nhiên, vì Bundle là một lớp khung công tác và được tải bởi trình nạp lớp khung công tác, bạn cần phải nói cho nó biết về ClassLoader đang được sử dụng để tìm các lớp trong APK của bạn. Trình tải lớp mà Gói được sử dụng theo mặc định là Trình nạp lớp khung làm việc, là không gian tên "thấp hơn" so với lớp có các lớp APK trong đó.

Vì vậy, bằng cách yêu cầu nhóm sử dụng Trình tải lớp nào bạn nói rằng cần phải kiểm tra Trình nạp lớp APK cho các lớp học. Nó mặc định để kiểm tra APK khuôn khổ vì đó là ClassLoader đã tải lớp Bundle, và do đó là "Không gian tên" duy nhất mà nó biết cách tìm các lớp.

Các vấn đề liên quan