Як читати / записувати булевий код при реалізації інтерфейсу Parcelable?


404

Я намагаюсь зробити " ArrayList Parcelableдля", щоб передати до активності список спеціальних об'єктів. Я починаю писати аmyObjectList клас, який розширює ArrayList<myObject>та впроваджує Parcelable.

Деякі атрибути MyObjectє, booleanалеParcel не мають жодного методу read/writeBoolean.

Який найкращий спосіб впоратися з цим?


3
Тому що всі читання, які я робив щодо проходження об'єкта між видами діяльності, передбачують використання parcelable замість serialisable.
гуркіт

10
@MisterSquonk Не слід використовувати Serializableінтерфейс для міждіяльної комунікації. Це повільно.
Октавіан А. Дам’ян

1
@grunk: Добре, це досить справедливо, але поки Intent.putExtra (назва рядка, значення Serializable) не буде позначено як застаріле в документах, я буду радий продовжувати його використовувати, якщо це полегшує мені життя. Просто думка.
Скуонк

3
@ Octavian: Але це залежить від конкретного дослідження та є відносним.
Сквонк

2
на мою думку, команда архітекторів андроїд лінива !!! де булевий !!!!!!!!
Матеус

Відповіді:


942

Ось як я це зробив би ...

writeToParcel:

dest.writeByte((byte) (myBoolean ? 1 : 0));     //if myBoolean == true, byte == 1

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0

38
Немає причин використовувати байт над int. байт є більш багатослівним через кастинг: dest.writeInt (myBoolean? 1: 0);
Мігель

Чому коментар @SiPlus отримав стільки відгуків? Ні 1, ні 0 взагалі не "завантажені". Це абсолютно не має різниці. І з тих пір, коли Java є слабко набраною мовою?
ніхто

13
@sotrh, що пише байт, просто пише int:/** * Write a byte value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeByte(byte val) { writeInt(val); }
Даллас,

3
@Dallas це з документації? Якщо так, то ігноруйте мій коментар. Здається, що api має функцію, яка говорить writeByte, але насправді пише int.
sotrh

1
@sotrh, що є копією-вставкою з вихідного коду. Відкрийте android.os.Parcel-джерело і переконайтеся самі.
Ярослав Миткалик

66

Ви також можете скористатися методом writeValue . На мою думку, це найпростіше рішення.

dst.writeValue( myBool );

Після цього ви можете легко отримати його за допомогою простого кастингу до Boolean:

boolean myBool = (Boolean) source.readValue( null );

Під капотом Android Framework обробляє це як ціле число:

writeInt( (Boolean) v ? 1 : 0 );

андроїд-джерело, що показує частину "під капотом" (л. 1219). Хоча крихітний трохи менш ефективний (через виклик методу та комутатор) цей метод читає трохи простіше.
дессеїм

6
Код, як написано тут, не збирається. readValue вимагає завантажувача класів, але він не потрібен булевим. Він повинен читати "boolean myBool = (Boolean) source.readValue (null);" Рецензенти, які не мають поняття, що вони роблять, і відхилили мою редакцію на цю відповідь: @hemang, jeeped, DavidRR.
Мігель

1
@miguel Це правда, виправлено :)
Taig

15

ти заявляєш так

 private boolean isSelectionRight;

писати

 out.writeInt(isSelectionRight ? 1 : 0);

читати

isSelectionRight  = (in.readInt() == 0) ? false : true;

булевий тип потрібно перетворити на те, що підтримує Parcel, і ми можемо перетворити його на int.


Це викликає помилку, несумісні типи, потрібні булеві знаходження int?
Пол Океке

12

AndroidStudio (використовуючи 2,3 атм), після впровадження Parcelable у своєму класі ви можете просто утримувати вказівник миші над назвою вашого класу, і він попросить вас додати реалізацію парцеляції:

введіть тут опис зображення

З чотирьох полів воно генерує наступне:

public class YourClass implements Parcelable{

String someString;
int someInt;
boolean someBoolean;
List<String> someList;

protected YourClass(Parcel in) {
    someString = in.readString();
    someInt = in.readInt();
    someBoolean = in.readByte() != 0;
    someList = in.createStringArrayList();
}

@Override
public void writeToParcel(Parcel dest, int flags) {
    dest.writeString(someString);
    dest.writeInt(someInt);
    dest.writeByte((byte) (someBoolean ? 1 : 0));
    dest.writeStringList(someList);
}

...

Це зручно :)
Dino Tw

8

Я, як правило, маю їх у масиві і дзвоню, writeBooleanArrayіreadBooleanArray

Якщо вам потрібно запакувати один булевий, ви можете зробити це:

parcel.writeBooleanArray(new boolean[] {myBool});

Ви коли-небудь стикалися з проблемою, коли вам потрібно розібрати кілька булевих ... у мене є. Чи можете ви мені допомогти? stackoverflow.com/questions/13463727/… . Дякую.
Роджер Чужий


5

Я запропонував вам найпростіший спосіб реалізувати Parcelable, якщо ви використовуєте Android Studio.

Просто перейдіть у меню Файл-> Налаштування-> Плагіни-> Огляд сховища та пошук парцелябельного зображення. Перегляньте зображення

введіть тут опис зображення Це автоматично створить Parcelable.

І для цього є веб-система. http://www.parcelabler.com/


4

Коротка та проста реалізація в Котліні з незмінною підтримкою:

Додайте методи до посилки

fun Parcel.writeBoolean(flag: Boolean?) {
    when(flag) {
        true -> writeInt(1)
        false -> writeInt(0)
        else -> writeInt(-1)
    }
}

fun Parcel.readBoolean(): Boolean? {
    return when(readInt()) {
        1 -> true
        0 -> false
        else -> null
    }
}

І використовуйте:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false

@AliKazi ви не можете зробити це в однорядковому операторі на Java з підтримкою додаткових типів. Вам слід зберегти 3 штати. Думаю, ви забули про null.
Павло Шорохов

@ comm1x, IDE не любить це рішення. `Не вдається отримати доступ до" readBoolean "до виклику конструктора надкласового класу.
Адам Гурвіц

@ comm1x Я вирішив проблему. Для роботи додані методи повинні знаходитися в межах супутнього об’єкта
Адам Гурвіц,

3

Ви можете запакувати булеві значення в байт, використовуючи маскування та зсув. Це був би найефективніший спосіб зробити це, і це, мабуть, те, що вони очікують від вас.


+1. Правда, збереження значення в байті було б ефективнішим. Чи не заперечуєте ви, щоб я редагував моє запитання, щоб представити вашу ідею?
Октавіан А. Дам’ян

Можна, але те, що ви написали, насправді не те, що я мав на увазі. Він буде працювати, але хіба найефективніший. Ви можете упакувати 8 балів в байт, використовуючи маски та булева алгебра
floetway76

У більшості випадків я згоден з вами, однак у мене є випадки, які час від часу виповзають, коли мені потрібні три стани, з якими буде працювати Булева робота. Такі як необов'язкове питання "так" / "ні". Мені потрібна нульова інформація, чи було явно вказано булеве значення чи ні.
Чад Горшинг

Немає жодної причини використовувати байт над int, оскільки writeByte()метод посилки безпосередньо викликаєwriteInt()
Ярослав Миткалик

3

Тут важко визначити справжнє питання. Я думаю, це як боротися з булевими елементами при реалізації Parcelableінтерфейсу.

Деякі атрибути MyObject булі, але у Parcel немає жодного методу читання / записуBoolean.

Значення доведеться зберігати як рядок або як байт. Якщо ви перейдете за рядком, то вам доведеться використовувати статичний методString класу, який називається valueOf()для розбору булевого значення. Це не так ефективно, як збереження в байті.

String.valueOf(theBoolean);

Якщо ви перейдете на байт, вам доведеться самостійно реалізувати логіку перетворення.

byte convBool = -1;
if (theBoolean) {
    convBool = 1;
} else {
    convBool = 0;
}

Під час видалення Parcelоб'єкта ви повинні подбати про перетворення в початковий тип.


Абсолютно немає причин використовувати String. Немає жодної причини використовувати байт через int, оскільки writeByte()метод Parcel безпосередньо викликає writeInt(). Логіка перетворення занадто багатослівна. Просто зробіть writeInt(boolean ? 1 : 0)іboolean = readInt() != 0
Ярослав Миткалик

1

На це питання вже чудово відповіли інші люди, якщо ви хочете зробити це самостійно.

Якщо ви віддаєте перевагу інкапсулювати або приховувати більшу частину коду посилки низького рівня, можете подумати про використання коду, який я написав деякий час тому для спрощення обробки парцелянтів.

Написання на посилку так само просто:

parcelValues(dest, name, maxSpeed, weight, wheels, color, isDriving);

де колір є перерахунком, а isDriving - булевим, наприклад.

Читати з посилки також не набагато складніше:

color = (CarColor)unparcelValue(CarColor.class.getClassLoader());
isDriving = (Boolean)unparcelValue();

Просто погляньте на "ParceldroidExample", який я додав до проекту.

Нарешті, він також тримає ініціалізатор CREATOR коротким:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);

Дякуємо за .class.getClassLoader().
CoolMind

0

У джерелах Android (AOSP) є багато прикладів. Наприклад,PackageInfo клас має булевий член requiredForAllUsersі він серіалізується наступним чином:

public void writeToParcel(Parcel dest, int parcelableFlags) {
    ...
    dest.writeInt(requiredForAllUsers ? 1 : 0);
    ...
}

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.