Jak czytać / pisać wartość logiczną podczas implementacji interfejsu Parcelable?

404

Próbuję utworzyć ArrayList Parcelablew celu przekazania do działania listy niestandardowego obiektu. Zaczynam pisaćmyObjectList zajęcia, które rozszerzają ArrayList<myObject>i wdrażają Parcelable.

Niektóre atrybuty MyObjectbooleanaleParcel nie mają żadnej metody read/writeBoolean.

Jaki jest najlepszy sposób, aby sobie z tym poradzić?

grunk
źródło
3
Ponieważ wszystkie czytanie, które zrobiłem na temat przekazywania obiektu między działaniami, poprzedza użycie paczkowatego zamiast serializowalnego.
grunk
10
@MisterSquonk Nie należy używać Serializableinterfejsu do komunikacji między działaniami. To jest wolne.
Octavian A. Damiean
1
@grunk: OK, to wystarcza, ale dopóki Intent.putExtra (nazwa ciągu, wartość Serializable) nie zostanie oznaczona jako przestarzała w dokumentach, chętnie będę ją używać, jeśli to ułatwi mi życie. Tylko myśl.
Squonk
3
@Octavian: Ale to zależy od studium przypadku i jest względne.
Squonk
2
w moim przekonaniu zespół architektów Androida jest leniwy !!! whereis boolean !!!!!!!!
Mateus,

Odpowiedzi:

942

Oto jak bym to zrobił ...

writeToParcel:

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

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0
b_yng
źródło
38
Nie ma powodu, aby używać bajtu zamiast int. bajt jest bardziej szczegółowy ze względu na obsadę: dest.writeInt (myBoolean? 1: 0);
Miguel
Dlaczego komentarz @SiPlus otrzymał tak wiele pozytywnych opinii? Ani 1, ani 0 nie są w ogóle „ładowane”. To absolutnie nie ma znaczenia. A od kiedy Java jest słabo pisanym językiem?
nikt
13
@sotrh pisze bajt właśnie pisze int:/** * Write a byte value into the parcel at the current dataPosition(), * growing dataCapacity() if needed. */ public final void writeByte(byte val) { writeInt(val); }
Dallas
3
@Dallas jest to z dokumentacji? Jeśli tak, zignoruj ​​mój komentarz. Wydaje się nieuczciwe, że interfejs API ma funkcję, która mówi writeByte, ale w rzeczywistości zapisuje int.
sotrh
1
@sotrh, czyli kopiuj-wklej z kodu źródłowego. Otwórz źródło android.os.Parcel i przekonaj się sam.
Yaroslav Mytkalyk
66

Możesz także skorzystać z metody writeValue . Moim zdaniem jest to najprostsze rozwiązanie.

dst.writeValue( myBool );

Następnie możesz go łatwo odzyskać za pomocą prostej obsady, aby Boolean:

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

Pod maską system Android będzie traktował go jako liczbę całkowitą:

writeInt( (Boolean) v ? 1 : 0 );
Taig
źródło
źródło Androida pokazujące część „pod maską” (w. 1219). Choć nieco mniej wydajna (z powodu wywołania metody i przełącznika) ta metoda jest nieco prostsza.
desseim
6
Kod napisany tutaj nie będzie się kompilował. Funkcja readValue wymaga modułu ładującego klasy, ale nie jest ona potrzebna w przypadku wartości logicznych. Powinien brzmieć „boolean myBool = (Boolean) source.readValue (null);” Recenzenci, którzy nie mają pojęcia, co robią, odrzucili moją edycję tej odpowiedzi: @hemang, jeeped, DavidRR.
Miguel
1
@miguel To prawda, naprawiono to :)
Taig
15

deklarujesz w ten sposób

 private boolean isSelectionRight;

pisać

 out.writeInt(isSelectionRight ? 1 : 0);

czytać

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

typ logiczny należy przekonwertować na coś, co obsługuje Parcel, abyśmy mogli przekonwertować go na int.

Shaista Naaz
źródło
Powoduje to błąd, niezgodne typy, wymagany boolean znaleziono int?
Paul Okeke
12

AndroidStudio (przy użyciu 2,3 ​​atm), po wdrożeniu Parcelable w swojej klasie, możesz po prostu przytrzymać wskaźnik myszy nad nazwą klasy i poprosi Cię o dodanie implementacji paczkowej:

wprowadź opis zdjęcia tutaj

Z czterech pól generuje:

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);
}

...
Henk-Martijn
źródło
Jest to przydatne :)
Dino Tw
8

Zwykle mam je w tablicy i wołam writeBooleanArrayireadBooleanArray

Jeśli potrzebujesz jednego logicznego loga, który musisz spakować, możesz to zrobić:

parcel.writeBooleanArray(new boolean[] {myBool});
Geobity
źródło
Czy kiedykolwiek spotkałeś się z problemem, kiedy musisz spakować kilka booleanów ... mam. Czy możesz mi pomóc>? stackoverflow.com/questions/13463727/... . Dzięki.
Roger Alien,
8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read
Meghna
źródło
5

Zasugerowałem ci najprostszy sposób na wdrożenie Paczkowatego, jeśli korzystasz z Android Studio.

Po prostu przejdź do Plik-> Ustawienia-> Wtyczki-> Przeglądaj repozytorium i wyszukaj działkę. Zobacz obraz

wprowadź opis zdjęcia tutaj Automatycznie utworzy paczkę.

I jest do tego strona internetowa. http://www.parcelabler.com/

Zar E Ahmer
źródło
4

Krótka i prosta implementacja w Kotlinie , z zerowym wsparciem:

Dodaj metody do paczki

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
    }
}

I użyj tego:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false
Pavel Shorochow
źródło
@AliKazi nie można tego zrobić w instrukcji 1-wierszowej w Javie z obsługą opcjonalnych typów. Powinieneś zachować 3 stany. Myślę, że zapomniałeś o wartości null.
Pavel Shorochow
@ comm1x, IDE nie lubi tego rozwiązania. `Nie można uzyskać dostępu do„ readBoolean ”przed wywołaniem konstruktora nadklasy.
Adam Hurwitz
@ comm1x Rozwiązałem problem. Aby działać, dodane metody muszą znajdować się w obiekcie towarzyszącym
Adam Hurwitz
3

Możesz spakować swoje wartości logiczne do bajtu za pomocą maskowania i przesuwania. To byłby najbardziej skuteczny sposób na zrobienie tego i prawdopodobnie tego oczekują od ciebie.

fleetway76
źródło
+1. To prawda, że ​​zapisanie wartości w bajcie byłoby bardziej wydajne. Czy miałbyś coś przeciwko edycji mojego pytania w celu przedstawienia Twojego pomysłu?
Octavian A. Damiean
Możesz, ale to, co napisałeś, nie jest tym, co miałem na myśli. Będzie działać, ale nie jest najbardziej wydajny. Możesz spakować 8 bajtów w bajt za pomocą masek i algebry boolowskiej
fleetway76
W większości przypadków zgadzam się z tobą, ale mam przypadki, które od czasu do czasu pełzają, gdzie potrzebuję trzech stanów, z którymi współpracuje Boolean. Takich jak opcjonalne pytanie tak / nie. Potrzebuję null, aby wiedzieć, czy wartość logiczna została wyraźnie określona, ​​czy nie.
Chad Gorshing 9.11.11
Nie ma powodu, aby używać bajtu writeByte()writeInt()
zamiast
3

Trudno tutaj znaleźć prawdziwe pytanie. Myślę, że to jak radzić sobie z logicznymi wartościami przy implementacji Parcelableinterfejsu.

Niektóre atrybuty MyObject są logiczne, ale Parcel nie ma żadnej metody read / writeBoolean.

Musisz zapisać wartość jako ciąg znaków lub jako bajt. Jeśli wybierzesz ciąg znaków, będziesz musiał użyć metody statycznej Stringklasy wywoływanej valueOf()do parsowania wartości logicznej. Nie jest tak skuteczny, jak zapisywanie go w trudnych bajtach.

String.valueOf(theBoolean);

Jeśli wybierzesz bajt, musisz samodzielnie zaimplementować logikę konwersji.

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

Podczas demontażu Parcelobiektu musisz zadbać o konwersję do oryginalnego typu.

Oktawian A. Damiean
źródło
Nie ma absolutnie żadnego powodu, aby używać String. Nie ma powodu, aby używać bajtu zamiast int, ponieważ writeByte()metoda Parcela bezpośrednio wywołuje writeInt(). Logika konwersji jest zbyt wyczerpująca. Po prostu zrób writeInt(boolean ? 1 : 0)iboolean = readInt() != 0
Jarosław Mytkalyk
1

Na to pytanie inni ludzie już doskonale odpowiedzieli, jeśli chcesz to zrobić samodzielnie.

Jeśli wolisz enkapsulować lub ukryć większość niskopoziomowego kodu paczki, możesz rozważyć użycie kodu, który napisałem jakiś czas temu, w celu uproszczenia obsługi paczek.

Pisanie na paczce jest tak proste, jak:

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

gdzie kolor jest wyliczeniem, a isDriving to na przykład wartość logiczna.

Czytanie z paczki również nie jest trudniejsze:

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

Wystarczy spojrzeć na „ParceldroidExample”, który dodałem do projektu.

Wreszcie, utrzymuje także krótki czas inicjalizacji CREATOR:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);
Michael Geier
źródło
Dzięki za .class.getClassLoader().
CoolMind
0

Istnieje wiele przykładów w źródłach Androida (AOSP). Na przykład PackageInfoklasa ma element logiczny requiredForAllUsersi jest serializowana w następujący sposób:

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

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
FireAphis
źródło