Bagaimana cara membaca / menulis boolean ketika mengimplementasikan antarmuka Parcelable?

404

Saya mencoba untuk membuat ArrayList Parcelableagar suatu aktivitas dapat mengirimkan daftar objek khusus. Saya mulai menulis myObjectListkelas yang diperluas ArrayList<myObject>dan diimplementasikan Parcelable.

Beberapa atribut MyObjectare booleantetapi Parceltidak memiliki metode apa pun read/writeBoolean.

Apa cara terbaik untuk menangani ini?

grunk
sumber
3
Karena semua bacaan yang saya lakukan tentang melewati objek antara kegiatan mendahului penggunaan parcelable bukannya serialisable.
grunk
10
@MisterSquonk Anda tidak boleh menggunakan Serializableantarmuka untuk komunikasi antar aktivitas. Itu lambat.
Octavian A. Damiean
1
@grunk: OK, itu cukup adil tetapi sampai Intent.putExtra (nama string, nilai Serializable) ditandai sebagai usang dalam dokumen, saya akan senang untuk terus menggunakannya jika membuat hidup lebih mudah bagi saya. Hanya pemikiran saja.
Squonk
3
@Octavian: Tapi itu tergantung pada studi per kasus dan bersifat relatif.
Squonk
2
menurut pendapat saya, tim arsitek android malas !!! dimana boolean !!!!!!!!
Mateus

Jawaban:

942

Begini cara saya melakukannya ...

writeToParcel:

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

readFromParcel:

myBoolean = in.readByte() != 0;     //myBoolean == true if byte != 0
b_yng
sumber
38
Tidak ada alasan untuk menggunakan byte lebih dari int. byte lebih verbose karena para pemain: dest.writeInt (myBoolean? 1: 0);
miguel
Mengapa komentar @SiPlus mendapatkan begitu banyak upvotes? Baik 1, maupun 0 tidak "dimuat" sama sekali. Sama sekali tidak ada bedanya. Dan sejak kapan Java merupakan bahasa yang diketik dengan lemah?
noone
13
@ sotrh menulis byte hanya menulis 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 apakah itu dari dokumentasi? Jika demikian maka abaikan komentar saya. Tampaknya tidak jujur ​​untuk api memiliki fungsi yang mengatakan writeByte, tetapi sebenarnya menulis int.
sotrh
1
@ sotrh itu adalah salin-tempel dari kode sumber. Buka sumber android.os.Parcel dan lihat sendiri.
Yaroslav Mytkalyk
66

Anda juga dapat menggunakan metode writeValue . Menurut pendapat saya itu solusi yang paling mudah.

dst.writeValue( myBool );

Setelah itu Anda dapat dengan mudah mengambilnya dengan gips sederhana ke Boolean:

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

Di bawah tenda Kerangka Android akan menanganinya sebagai bilangan bulat:

writeInt( (Boolean) v ? 1 : 0 );
Taig
sumber
Sumber android menunjukkan bagian "di bawah tenda" (l. 1219). Meskipun sedikit lebih tidak efisien (karena pemanggilan metode dan sakelar) metode ini membaca lebih mudah.
desseim
6
Kode yang ditulis di sini tidak akan dikompilasi. readValue membutuhkan classloader tetapi itu tidak diperlukan untuk Boolean. Seharusnya membaca "boolean myBool = (Boolean) source.readValue (null);" Reviewer yang tidak tahu apa yang mereka lakukan dan menolak edit saya untuk jawaban ini: @hemang, jeeped, DavidRR.
miguel
1
@miguel Itu benar, perbaiki :)
Taig
15

Anda menyatakan seperti ini

 private boolean isSelectionRight;

menulis

 out.writeInt(isSelectionRight ? 1 : 0);

Baca

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

tipe boolean perlu dikonversi ke sesuatu yang didukung Parcel dan agar kita dapat mengubahnya menjadi int.

Shaista Naaz
sumber
Ini menyebabkan kesalahan, tipe yang tidak kompatibel, diperlukan boolean ditemukan int?
Paul Okeke
12

AndroidStudio (menggunakan 2,3 atm), setelah menerapkan Parcelable di kelas Anda, Anda dapat dengan mudah memegang pointer mouse di atas nama kelas Anda dan meminta Anda untuk menambahkan implementasi parcelable:

masukkan deskripsi gambar di sini

Dari empat bidang, ini menghasilkan yang berikut:

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
sumber
Ini berguna :)
Dino Tw
8

Saya biasanya memilikinya dalam sebuah array dan panggilan writeBooleanArraydanreadBooleanArray

Jika itu adalah boolean tunggal yang harus Anda bungkus, Anda bisa melakukan ini:

parcel.writeBooleanArray(new boolean[] {myBool});
Geobit
sumber
Pernahkah Anda menghadapi masalah ketika Anda perlu membagi beberapa boolean ... saya punya. Bisakah Anda tolong saya>? stackoverflow.com/questions/13463727/… . Terima kasih.
Roger Alien
8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read
Meghna
sumber
5

Saya menyarankan Anda cara termudah untuk mengimplementasikan Parcelable jika Anda menggunakan Android Studio.

Cukup buka File-> Pengaturan-> Plugins-> Browse Repository dan cari parcelable. Lihat gambar

masukkan deskripsi gambar di sini Ini akan secara otomatis membuat Parcelable.

Dan ada webiste juga untuk melakukan ini. http://www.parcelabler.com/

Zar E Ahmer
sumber
4

Implementasi singkat dan sederhana di Kotlin , dengan dukungan nullable:

Tambahkan metode ke Parcel

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

Dan gunakan itu:

parcel.writeBoolean(isUserActive)

parcel.readBoolean()        // For true, false, null
parcel.readBoolean()!!      // For only true and false
Pavel Shorokhov
sumber
@ AliKazi Anda tidak dapat melakukan ini dalam pernyataan 1 baris di Jawa dengan dukungan tipe opsional. Anda harus bertahan 3 negara. Saya pikir Anda lupa tentang null.
Pavel Shorokhov
@ comm1x, IDE tidak menyukai solusi ini. `Tidak dapat mengakses" readBoolean "sebelum konstruktor superclass dipanggil.
Adam Hurwitz
@ comm1x Saya menyelesaikan masalah ini. Agar dapat bekerja, metode yang ditambahkan harus berada dalam objek pendamping
Adam Hurwitz
3

Anda bisa mengemas nilai boolean Anda ke dalam byte menggunakan masking dan shifting. Itu akan menjadi cara paling efisien untuk melakukannya dan mungkin itulah yang mereka harapkan Anda lakukan.

fleetway76
sumber
+1. Benar, menyimpan nilai dalam satu byte akan lebih efisien. Maukah Anda mengedit pertanyaan saya untuk mewakili ide Anda?
Octavian A. Damiean
Anda bisa, tetapi apa yang Anda tulis bukanlah yang saya maksud. Ini akan bekerja tetapi bukan yang paling efisien. Anda dapat mengemas 8 boolean ke dalam byte menggunakan masker dan aljabar boolean
fleetway76
Pada kebanyakan kasus saya setuju dengan Anda, namun saya memiliki kasus yang merayap dari waktu ke waktu di mana saya membutuhkan tiga negara bagian yang akan bekerja dengan Boolean. Seperti pertanyaan ya / tidak opsional. Saya perlu nol untuk mengetahui apakah Boolean telah secara eksplisit ditentukan atau tidak.
Chad Gorshing
Tidak ada alasan menggunakan byte over int, karena metode Parcel writeByte()langsung memanggilwriteInt()
Yaroslav Mytkalyk
3

Sulit untuk mengidentifikasi pertanyaan sebenarnya di sini. Saya kira itu adalah bagaimana berurusan dengan boolean saat mengimplementasikan Parcelableantarmuka.

Beberapa atribut MyObject adalah boolean tetapi Parcel tidak memiliki metode baca / tulisBoolean.

Anda harus menyimpan nilai sebagai string atau sebagai byte. Jika Anda mencari string maka Anda harus menggunakan metode statis dari Stringkelas yang dipanggil valueOf()untuk mem-parsing nilai boolean. Ini tidak seefektif menyimpannya dalam byte yang sulit.

String.valueOf(theBoolean);

Jika Anda menggunakan byte, Anda harus mengimplementasikan sendiri logika konversi.

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

Saat menghapus Parcelobjek, Anda harus menjaga konversi ke tipe aslinya.

Oktavianus A. Damiean
sumber
Sama sekali tidak ada alasan menggunakan String. Tidak ada alasan menggunakan byte over int, karena metode Parcel writeByte()langsung memanggil writeInt(). Logika konversi terlalu bertele-tele. Lakukan writeInt(boolean ? 1 : 0)danboolean = readInt() != 0
Yaroslav Mytkalyk
1

Pertanyaan ini sudah dijawab dengan sempurna oleh orang lain, jika Anda ingin melakukannya sendiri.

Jika Anda lebih memilih untuk merangkum atau menyembunyikan sebagian besar kode parcel tingkat rendah, Anda dapat mempertimbangkan menggunakan beberapa kode yang saya tulis beberapa waktu lalu untuk menyederhanakan penanganan parcelable.

Menulis ke paket semudah:

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

di mana warna adalah enum dan isDriving adalah boolean, misalnya.

Membaca dari parsel juga tidak jauh lebih sulit:

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

Lihat saja "ParceldroidExample" yang saya tambahkan ke proyek.

Akhirnya, itu juga membuat initializer CREATOR singkat:

public static final Parcelable.Creator<Car> CREATOR =
    Parceldroid.getCreatorForClass(Car.class);
Michael Geier
sumber
Terima kasih untuk .class.getClassLoader().
CoolMind
0

Ada banyak contoh di sumber Android (AOSP). Sebagai contoh, PackageInfokelas memiliki anggota boolean requiredForAllUsersdan diserialisasi sebagai berikut:

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

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
FireAphis
sumber