làm thế nào để triển khai đúng Parcelable với ArrayList <Parcelable>?


76

Tôi gặp khó khăn khi xếp lớp Parcelable. Vấn đề là, tôi đang cố gắng ghi vào bưu kiện một thành viên trong lớp là một ArrayList<Parcelable>đối tượng. Các ArrayListSerializable, và các đối tượng ( ZigBeeDev) trong danh sách là Parcelable.

Đây là mã liên quan:

package com.gnychis.coexisyst;

import java.util.ArrayList;
import java.util.Iterator;

import android.os.Parcel;
import android.os.Parcelable;

public class ZigBeeNetwork implements Parcelable {

    public String _mac;             // the source address (of the coordinator?)
    public String _pan;             // the network address
    public int _band;               // the channel
    ArrayList<Integer> _lqis;       // link quality indicators (to all devices?)
    ArrayList<ZigBeeDev> _devices;  // the devices in the network

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(_mac);
        out.writeString(_pan);
        out.writeInt(_band);
        out.writeSerializable(_lqis);
        out.writeParcelable(_devices, 0);  // help here
    }

    private ZigBeeNetwork(Parcel in) {
        _mac = in.readString();
        _pan = in.readString();
        _band = in.readInt();
        _lqis = (ArrayList<Integer>) in.readSerializable();
        _devices = in.readParcelable(ZigBeeDev.class.getClassLoader());  // help here
    }

    public int describeContents() {
        return this.hashCode();
    }

    public static final Parcelable.Creator<ZigBeeNetwork> CREATOR = 
            new Parcelable.Creator<ZigBeeNetwork>() {
        public ZigBeeNetwork createFromParcel(Parcel in) {
            return new ZigBeeNetwork(in);
        }

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

    //...
}

Tôi đã đánh dấu hai điểm "// help here" để hiểu cách ghi đúng vào bưu kiện và cách tái tạo lại nó. Nếu ZigBeeDevđược Parcelable(kiểm tra đúng cách), tôi phải làm thế nào để làm điều này đúng cách?

Câu trả lời:


143

Bạn gần như đã hiểu nó!

Bạn chỉ cần làm:

public void writeToParcel(Parcel out, int flags) {
    out.writeString(_mac);
    out.writeString(_pan);
    out.writeInt(_band);
    out.writeSerializable(_lqis);
    out.writeTypedList(_devices);
}

private ZigBeeNetwork(Parcel in) {
    _mac = in.readString();
    _pan = in.readString();
    _band = in.readInt();
    _lqis = (ArrayList<Integer>) in.readSerializable();
    in.readTypedList(_devices, ZigBeeDev.CREATOR);
}

Đó là tất cả!

Đối với danh sách Số nguyên của bạn, bạn cũng có thể thực hiện:

out.writeList(_lqis);
_lqis = new ArrayList<>();
in.readList(_lqis Integer.class.getClassLoader());

Nó sẽ hoạt động.


2
Để tham khảo trong tương lai, và tôi không chắc đó có phải là lỗi đánh máy mà không ai để ý hay không, nhưng ZigBeeDev.Creatornên có ZigBeeDev.CREATOR. Lần nào tôi cũng gặp lỗi cho đến khi tôi nhận ra rằng có hai người sáng tạo khác nhau mà tôi có thể sử dụng trong dự án của riêng mình.
gatlingxyz

@ NitroG42 Cách tiếp cận thứ hai cho kết quả danh sách đã đọc thànhcannot convert from void to ArrayList<Integer>
AlexAndro

8
Tôi cũng cần khởi tạo mảng trước đó, ví dụ mã của tôi sẽ giống như sau: _devices = new ArrayList <ZigBeeDev> (); in.readTypedList (_devices, ZigBeeDev.Creator);
sgarman

@sgarman Không cần phải nhanh chóng nguyên nhân mảng sau đó bạn nhận được cảnh báo: Explicit ZigBeeDev loại đối số có thể được thay thế bằng <> kiểm tra này báo cáo tất cả các biểu thức mới với các đối số loại có thể được thay thế bằng loại kim cương <>
crubio

Xác nhận đang làm việc với generic Hashtablesử dụng các loại nguyên thủy (bao gồm String) cho một trong các khóa hoặc giá trị của anh ấy.
Eido95,

17

Trong trường hợp của tôi in.readTypedList(_devices, ZigBeeDev.CREATOR);đã cho tôi một NullPointerExceptiontrên _devices. Vì vậy, tôi đã sử dụng cái này:

_devices = in.createTypedArrayList(ZigBeeDev.CREATOR);

3
fwiw - lý do bạn nhận được NPE là bởi vì nếu bạn sử dụng, trước tiên in.readTypedList()bạn cần tạo một ArrayList () mới và sau đó chuyển nó cho in.readTypedList(yourNewArrayList, YourObj.CREATOR)nếu không, nó sẽ chỉ cố gắng đưa dữ liệu vào danh sách rỗng.
rf43

Vâng đúng rồi. Tôi đã đọc mã nguồn trước khi sử dụng nó. Cảm ơn bạn vì thông tin bổ sung mà tôi đã quên viết.
osrl

@osrl khi chúng tôi làm theo giải pháp của bạn đã nhận được ngoại lệ java.lang.OutOfMemoryError: Không phân bổ được phân bổ byte 13893804 với 11004100 byte miễn phí và 10MB cho đến khi OOM
Ajit Kumar Dubey

Mảng của bạn có chứa tệp hoặc thứ gì đó lớn không? @Ajit
osrl


2

Trong hàm tạo, bạn nên sử dụng

_lqis = in.createTypedArrayList(ZigBeeDev.CREATOR);

Và trong "writeToParcel" sử dụng

out.writeTypedList(_lqis);

0

Một chút muộn nhưng tôi cũng có vấn đề này. Sau một thời gian dài lãng phí, tôi tình cờ gặp parcelabler.com trang web tự động tạo bưu kiện cho bạn.

Nó cho phép tôi tạo một lô đất lồng nhau với danh sách mảng bên trong rất dễ dàng và giúp tôi tiết kiệm rất nhiều thời gian.

Về cơ bản cách thức hoạt động của trang web là bạn nhập đối tượng của mình với ArrayList trong đó và nó sẽ tự động thêm các phương thức cần thiết để làm cho nó có thể chuyển thành bưu kiện (đọc từ bưu kiện, ghi vào bưu kiện, mô tả nội dung và trình tạo bưu kiện đều được tạo tự động). Điều này đặc biệt hữu ích khi tạo các bưu kiện phức tạp, chẳng hạn như câu hỏi ở đây yêu cầu, chứa các bưu kiện, mảng và danh sách lồng nhau.

CHỈNH SỬA: Ngoài ra IntelliJ IDEA và Android Studio có các plugin cho việc này, thực hiện một điều tương tự như trang web được liệt kê:

Các plugin này tạo mã soạn sẵn Android Parcelable dựa trên các trường trong lớp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.