Как сериализовать нулевое значение при использовании интерфейса Parcelable

что касается моего примера кода, что мне делать, если одна переменная Locable равна нулю? Например, теперь, если l.getZoom() возвращает null, я получаю исключение NullPointerException.

@Override
public void writeToParcel(Parcel parcel, int arg1) {
    parcel.writeInt(count);
    for(Locable l:locableArr){
        parcel.writeInt(l.getOriginId());
        parcel.writeInt(l.getLocableType());
        parcel.writeInt(l.getZoom());
        parcel.writeDouble(l.getLatituda());
        parcel.writeDouble(l.getLongituda());
        parcel.writeString(l.getTitle());
        parcel.writeString(l.getSnipet());
    }

}

Спасибо!


person igor.beslic    schedule 05.05.2011    source источник
comment
Кажется, NPE является результатом автоматической распаковки. Возможно, мне следует просто проверить нулевое значение и установить его на 0?   -  person igor.beslic    schedule 06.05.2011
comment
Если масштаб имеет значения 0+, рассмотрите возможность представления нуля как -1.   -  person JAL    schedule 06.05.2011
comment
На данный момент я делаю то же самое, если значения равны NULL, я пишу некоторые значения, такие как -1 или пустая строка, которую я во время десериализации устанавливаю в NULL. Уродливо... Я бы хотел, чтобы кто-нибудь подтвердил, что это правильно, и я был бы более доволен своим кодом.   -  person igor.beslic    schedule 25.05.2011
comment
хорошо, что примитивы не имеют концепции нуля (или цели C nil). В качестве общего решения мне интересно, можете ли вы отправить пары примитивов для представления объекта, скажем, Int для int, сначала логическое значение isNull, а затем примитив int, позволяющий вам создать Integer ( int) или Integer(null).   -  person JAL    schedule 26.05.2011


Ответы (4)


Вы можете использовать Parcel.writeValue для сортировки универсального объекта с нулевым значением.

person artch    schedule 26.05.2012
comment
и прочитать значение обратно... s = (String) in.readValue(String.class.getClassLoader()); - person Sofi Software LLC; 11.01.2013
comment
@SofiSoftwareLLC, глядя на исходный код посылки.readValue, ему нужен только загрузчик классов для типов Map, Parcelable, ArrayList, Object[] и Parcelable[]. Для других типов вы можете передать null для загрузчика классов. github.com/android/platform_frameworks_base/ блоб/ - person miguel; 04.02.2015
comment
Должен быть принят ответ с интеграцией комментариев @SofiSoftwareLLC - person ArteFact; 22.03.2019

Я использую класс Parcelable, который также имеет поля Integer и Boolean, и эти поля могут быть нулевыми.

У меня были проблемы с использованием общего метода Parcel.writeValue, особенно когда я пытался прочитать его обратно через Parcel.readValue. Я продолжал получать исключение времени выполнения, в котором говорилось, что он не может определить тип разделенного объекта.

В конечном итоге мне удалось решить проблему, используя Parcel.writeSerializable и Parcel.readSerializable с приведением типа, поскольку и Integer, и Boolean реализуют интерфейс Serializable. Методы чтения и записи обрабатывают для вас null значений.

person Justin Hong    schedule 01.05.2015
comment
Да, сериализуемый с приведением работает как шарм. - person arenaq; 05.02.2019

Это решение, которое я придумал для безопасной записи строк:

private void writeStringToParcel(Parcel p, String s) {
    p.writeByte((byte)(s != null ? 1 : 0));
    p.writeString(s);
}

private String readStringFromParcel(Parcel p) {
    boolean isPresent = p.readByte() == 1;
    return isPresent ? p.readString() : null;
}
person Felipe Lima    schedule 20.12.2012
comment
У меня были некоторые проблемы с этим после того, как я скопировал и вставил ваш код, не понимая, что в readStringFromParcel() мне пришлось привести 1 к байту, прежде чем сравнивать его с p.readByte(). В конце концов я выбрал p.writeInt((s != null ? 1 : 0)); и логическое значение isPresent = p.readInt() == 1; - person Matt; 21.04.2013
comment
Вы должны написать строку, используя строку p.writeString(s), только если она не равна нулю; в противном случае вы получите исключение NullPointerException в этой строке. - person Price; 18.07.2014
comment
Если вы используете p.writeParcelable вместо p.writeString, вы не сразу получите исключение NullPointerException, а только какое-то сомнительное исключение ClassCastException, вызванное смещенными последовательностями чтения и записи. Вы должны писать объект только в том случае, если он не равен нулю. - person Roland; 21.02.2018

В большинстве кодов сериализации, которые я видел, используются либо флаги для указания наличия/отсутствия значения, либо предшествующее значению поле счетчика (например, при записи массивов), где поле счетчика просто устанавливается в ноль, если значение не вообще не существует.

Изучение исходного кода базовых классов Android обнаруживает такой код (из класса Message):

    if (obj != null) {
        try {
            Parcelable p = (Parcelable)obj;
            dest.writeInt(1);
            dest.writeParcelable(p, flags);
        } catch (ClassCastException e) {
            throw new RuntimeException(
                "Can't marshal non-Parcelable objects across processes.");
        }
    } else {
        dest.writeInt(0);
    }

или это (из класса Intent):

    if (mCategories != null) {
        out.writeInt(mCategories.size());
        for (String category : mCategories) {
            out.writeString(category);
        }
    } else {
        out.writeInt(0);
    }

Мое предложение: Если в вашем коде нет функциональной разницы между "zoom == null" и "zoom == 0", я бы просто объявил масштабирование примитивным (int вместо Integer) ИЛИ инициализируйте его нулем в конструкторе и убедитесь, что вы никогда не устанавливаете его в нуль (тогда вы можете быть уверены, что он никогда не будет нулевым, и вам не нужно будет добавлять специальный код, чтобы справиться с этим в ваших методах сериализации/десериализации) .

person David Wasser    schedule 24.05.2012
comment
Вы можете написать код для ответа на часть чтения объекта. - person meszias; 09.08.2018