Làm thế nào để đọc / ghi boolean khi thực hiện giao diện Parcelable?


404

Tôi đang cố gắng thực hiện ArrayList Parcelableđể chuyển đến một hoạt động một danh sách các đối tượng tùy chỉnh. Tôi bắt đầu viết một myObjectListlớp học mở rộng ArrayList<myObject>và thực hiện Parcelable.

Một số thuộc tính của MyObjectbooleannhưng Parcelkhông có bất kỳ phương pháp read/writeBoolean.

cách tốt nhất để xử lý này là gì?


3
Bởi vì tất cả các bài đọc tôi đã thực hiện về việc chuyển đối tượng giữa các hoạt động tạo tiền đề cho việc sử dụng bưu kiện thay vì nối tiếp.
grunk

10
@MisterSquonk Bạn không nên sử dụng Serializablegiao diện để liên lạc giữa các hoạt động. Nó chậm.
Octavian A. Damiean

1
@grunk: OK, điều đó đủ công bằng nhưng cho đến khi Intent.putExtra (Tên chuỗi, giá trị nối tiếp) được đánh dấu là không dùng trong tài liệu, tôi sẽ vui lòng tiếp tục sử dụng nếu điều đó giúp tôi dễ dàng hơn. Chỉ là một ý nghĩ.
Squonk

3
@Octavian: Nhưng điều đó phụ thuộc vào nghiên cứu từng trường hợp và là tương đối.
Squonk

2
trong ý kiến ​​của tôi, đội ngũ kiến ​​trúc sư của Android là lười biếng !!! boolean !!!!!!!!
Mateus

Câu trả lời:


942

Đây là cách tôi làm điều đó ...

writeToParcel:

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

đọcFromParcel:

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

38
Không có lý do để sử dụng byte trên int. byte dài dòng hơn bởi vì cast: Dest.writeInt (myBoolean? 1: 0);
miguel

Tại sao bình luận @SiPlus nhận được nhiều lượt upvote như vậy? Cả 1 và 0 đều không được "tải". Nó làm cho hoàn toàn không có sự khác biệt. Và từ khi nào Java là một ngôn ngữ được đánh máy yếu?
không có ai vào

13
@sotrh viết một byte chỉ cần viết một 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 là từ tài liệu? Nếu vậy thì bỏ qua bình luận của tôi. Có vẻ không thích hợp cho api có chức năng nói writeByte, nhưng thực sự viết một int.
sotrh

1
@sotrh đó là một bản sao-dán từ mã nguồn. Mở nguồn android.os.Parcel và tự mình xem.
Yaroslav Mytkalyk

66

Bạn cũng có thể sử dụng phương thức writeValue . Theo tôi đó là giải pháp đơn giản nhất.

dst.writeValue( myBool );

Sau đó, bạn có thể dễ dàng truy xuất nó với một diễn viên đơn giản để Boolean:

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

Dưới vỏ bọc, Android Framework sẽ xử lý nó như một số nguyên:

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

nguồn android hiển thị phần "dưới mui xe" (l. 1219). Mặc dù ít hiệu quả hơn một chút (vì gọi phương thức và chuyển đổi), phương thức này đọc đơn giản hơn một chút.
desseim

6
Mã như được viết ở đây sẽ không biên dịch. readValue yêu cầu trình nạp lớp nhưng nó không cần thiết cho Booleans. Nó nên đọc "boolean myBool = (Boolean) source.readValue (null);" Những người đánh giá không biết họ đang làm gì và từ chối chỉnh sửa của tôi cho câu trả lời này: @hemang, jeeped, DavidRR.
miguel

1
@miguel Đó là sự thật, đã sửa nó :)
Taig

15

bạn tuyên bố như thế này

 private boolean isSelectionRight;

viết

 out.writeInt(isSelectionRight ? 1 : 0);

đọc

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

loại boolean cần được chuyển đổi thành một cái gì đó mà Parcel hỗ trợ và vì vậy chúng ta có thể chuyển đổi nó thành int.


Điều này gây ra lỗi, các loại không tương thích, yêu cầu boolean tìm thấy int?
Paul Okeke

12

AndroidStudio (sử dụng 2,3 atm), sau khi triển khai Parcelable trên lớp của bạn, bạn chỉ cần giữ con trỏ chuột trên tên lớp của mình và nó yêu cầu bạn thêm triển khai có thể phân loại:

nhập mô tả hình ảnh ở đây

Từ bốn trường, nó tạo ra như sau:

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

...

Điều này rất tiện lợi :)
Dino Tw

8

Tôi thường có chúng trong một mảng và gọi writeBooleanArrayreadBooleanArray

Nếu đó là một boolean duy nhất bạn cần đóng gói, bạn có thể làm điều này:

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

Bạn đã bao giờ phải đối mặt với vấn đề khi bạn cần bưu kiện vài booleans ... tôi có. Bạn có thể vui lòng giúp tôi>? stackoverflow.com/questions/13463727/ . Cảm ơn.
Roger Alien

8
out.writeInt(mBool ? 1 : 0); //Write
this.mBool =in.readInt()==1; //Read

5

Tôi đã gợi ý cho bạn cách dễ nhất để triển khai Parcelable nếu bạn đang sử dụng Android Studio.

Chỉ cần truy cập Tệp-> Cài đặt-> Trình cắm- > Duyệt Kho lưu trữ và tìm kiếm có thể phân loại. Xem hình ảnh

nhập mô tả hình ảnh ở đây Nó sẽ tự động tạo Parcelable.

Và có một webiste cũng để làm điều này. http://www.parcelabler.com/


4

Việc triển khai ngắn và đơn giản trong Kotlin , với sự hỗ trợ vô giá trị:

Thêm phương thức vào 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
    }
}

Và sử dụng nó:

parcel.writeBoolean(isUserActive)

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

@AliKazi bạn không thể thực hiện điều này trong câu lệnh 1 dòng trong Java với các loại tùy chọn hỗ trợ. Bạn nên kiên trì 3 trạng thái. Tôi nghĩ rằng bạn quên về null.
Pavel Shorokhov

@ comm1x, IDE không thích giải pháp này. `Không thể truy cập" readBoolean "trước khi hàm tạo của lớp bậc trên được gọi.
Adam Hurwitz

@ comm1x Tôi đã giải quyết vấn đề. Để làm việc, các phương thức được thêm phải nằm trong đối tượng đồng hành
Adam Hurwitz

3

Bạn có thể đóng gói các giá trị boolean của mình vào một byte bằng cách sử dụng mặt nạ và dịch chuyển. Đó sẽ là cách hiệu quả nhất để làm điều đó và có lẽ là những gì họ sẽ mong đợi bạn làm.


+1. Đúng, lưu giá trị trong một byte sẽ hiệu quả hơn. Bạn có phiền tôi chỉnh sửa câu hỏi của tôi để thể hiện ý tưởng của bạn?
Octavian A. Damiean

Bạn có thể, nhưng những gì bạn đã viết không thực sự như tôi muốn nói. Nó sẽ hoạt động nhưng không hiệu quả nhất. Bạn có thể đóng gói 8 booleans vào một byte bằng mặt nạ và đại số boolean
fleetway76

Trong hầu hết các trường hợp, tôi đồng ý với bạn, tuy nhiên tôi có những trường hợp thỉnh thoảng xuất hiện khi tôi cần ba trạng thái mà Boolean sẽ làm việc. Chẳng hạn như một câu hỏi có / không có tùy chọn. Tôi cần null để biết liệu Boolean đã được chỉ định rõ ràng hay chưa.
Chad Gors Breath

Không có lý do gì để sử dụng byte trên int, vì writeByte()phương thức của Parcel gọi trực tiếpwriteInt()
Yaroslav Mytkalyk

3

Thật khó để xác định câu hỏi thực sự ở đây. Tôi đoán đó là cách đối phó với booleans khi thực hiện Parcelablegiao diện.

Một số thuộc tính của MyObject là boolean nhưng Parcel không có bất kỳ phương thức read / writeBoolean nào.

Bạn sẽ phải lưu trữ giá trị dưới dạng chuỗi hoặc dưới dạng byte. Nếu bạn chọn một chuỗi thì bạn sẽ phải sử dụng phương thức tĩnh của Stringlớp được gọi valueOf()để phân tích giá trị boolean. Nó không hiệu quả bằng việc lưu nó trong một byte khó khăn.

String.valueOf(theBoolean);

Nếu bạn đi một byte, bạn sẽ phải tự thực hiện logic chuyển đổi.

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

Khi sắp xếp Parcelđối tượng, bạn phải chăm sóc chuyển đổi sang loại ban đầu.


Hoàn toàn không có lý do sử dụng String. Không có lý do sử dụng byte trên int, vì writeByte()phương thức của Parcel gọi trực tiếp writeInt(). Logic chuyển đổi quá dài dòng. Chỉ cần làm writeInt(boolean ? 1 : 0)boolean = readInt() != 0
Yaroslav Mytkalyk

1

Câu hỏi này đã được trả lời hoàn hảo bởi những người khác, nếu bạn muốn tự mình làm nó.

Nếu bạn muốn gói gọn hoặc ẩn đi hầu hết các mã bưu kiện cấp thấp, bạn có thể cân nhắc sử dụng một số mã tôi đã viết cách đây một thời gian để đơn giản hóa việc xử lý các bưu kiện.

Viết vào một bưu kiện dễ dàng như:

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

trong đó màu sắc là một enum và ví dụ như là một boolean.

Đọc từ một bưu kiện cũng không khó hơn nhiều:

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

Chỉ cần nhìn vào "ParceldroidExample" tôi đã thêm vào dự án.

Cuối cùng, nó cũng giữ cho trình khởi tạo CREATOR ngắn:

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

Cảm ơn vì .class.getClassLoader().
CoolMind

0

Có nhiều ví dụ trong các nguồn Android (AOSP). Ví dụ, PackageInfolớp có một thành viên boolean requiredForAllUsersvà nó được tuần tự hóa như sau:

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

private PackageInfo(Parcel source) {
    ...
    requiredForAllUsers = source.readInt() != 0;
    ...
}
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.