นี่เป็นคำถามเก่า แต่ทุกคนล้มเหลวที่จะพูดถึงว่า Enums เป็นจริงSerializable
และดังนั้นจึงสามารถเพิ่มเข้ากับเจตนาเป็นพิเศษได้อย่างสมบูรณ์แบบ แบบนี้:
public enum AwesomeEnum {
SOMETHING, OTHER;
}
intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);
AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");
คำแนะนำในการใช้ตัวแปรแบบสแตติกหรือแอปพลิเคชันกว้างเป็นความคิดที่ไม่ดีจริงๆ สิ่งนี้จะเชื่อมโยงกิจกรรมของคุณเข้ากับระบบการจัดการของรัฐและเป็นการยากที่จะบำรุงรักษาการดีบักและปัญหาที่ถูกผูกไว้
ทางเลือก:
จุดที่ดีคือการสังเกตโดยtedzycเกี่ยวกับความจริงที่ว่าวิธีการแก้ปัญหาโดยOderikให้ข้อผิดพลาด อย่างไรก็ตามทางเลือกที่นำเสนอนั้นค่อนข้างยุ่งยากในการใช้ (แม้จะใช้ยาชื่อสามัญ)
หากคุณกังวลเกี่ยวกับประสิทธิภาพของการเพิ่ม enum ในเจตจำนงฉันขอเสนอทางเลือกเหล่านี้แทน:
ตัวเลือกที่ 1:
public enum AwesomeEnum {
SOMETHING, OTHER;
private static final String name = AwesomeEnum.class.getName();
public void attachTo(Intent intent) {
intent.putExtra(name, ordinal());
}
public static AwesomeEnum detachFrom(Intent intent) {
if(!intent.hasExtra(name)) throw new IllegalStateException();
return values()[intent.getIntExtra(name, -1)];
}
}
การใช้งาน:
// Sender usage
AwesomeEnum.SOMETHING.attachTo(intent);
// Receiver usage
AwesomeEnum result = AwesomeEnum.detachFrom(intent);
ตัวเลือกที่ 2:
(ทั่วไปนำมาใช้ใหม่และแยกออกจาก enum)
public final class EnumUtil {
public static class Serializer<T extends Enum<T>> extends Deserializer<T> {
private T victim;
@SuppressWarnings("unchecked")
public Serializer(T victim) {
super((Class<T>) victim.getClass());
this.victim = victim;
}
public void to(Intent intent) {
intent.putExtra(name, victim.ordinal());
}
}
public static class Deserializer<T extends Enum<T>> {
protected Class<T> victimType;
protected String name;
public Deserializer(Class<T> victimType) {
this.victimType = victimType;
this.name = victimType.getName();
}
public T from(Intent intent) {
if (!intent.hasExtra(name)) throw new IllegalStateException();
return victimType.getEnumConstants()[intent.getIntExtra(name, -1)];
}
}
public static <T extends Enum<T>> Deserializer<T> deserialize(Class<T> victim) {
return new Deserializer<T>(victim);
}
public static <T extends Enum<T>> Serializer<T> serialize(T victim) {
return new Serializer<T>(victim);
}
}
การใช้งาน:
// Sender usage
EnumUtil.serialize(AwesomeEnum.Something).to(intent);
// Receiver usage
AwesomeEnum result =
EnumUtil.deserialize(AwesomeEnum.class).from(intent);
ตัวเลือก 3 (พร้อม Kotlin):
ไม่นานมานี้ แต่ตั้งแต่ตอนนี้เรามี Kotlin ฉันคิดว่าฉันจะเพิ่มตัวเลือกใหม่สำหรับกระบวนทัศน์ใหม่ ที่นี่เราสามารถใช้ประโยชน์จากฟังก์ชั่นส่วนขยายและประเภท reified (ซึ่งยังคงประเภทเมื่อรวบรวม)
inline fun <reified T : Enum<T>> Intent.putExtra(victim: T): Intent =
putExtra(T::class.java.name, victim.ordinal)
inline fun <reified T: Enum<T>> Intent.getEnumExtra(): T? =
getIntExtra(T::class.java.name, -1)
.takeUnless { it == -1 }
?.let { T::class.java.enumConstants[it] }
มีประโยชน์เล็กน้อยในการทำเช่นนี้
- เราไม่ต้องการ "ค่าใช้จ่าย" ของวัตถุตัวกลางในการทำซีเรียล
inline
ไลเซชั่นเพราะมันเสร็จเรียบร้อยแล้วขอบคุณที่จะแทนที่การโทรด้วยรหัสภายในฟังก์ชั่น
- ฟังก์ชั่นนี้มีความคุ้นเคยมากกว่าเนื่องจากคล้ายกับ SDK
- IDE จะเติมข้อความอัตโนมัติให้กับฟังก์ชั่นเหล่านี้ซึ่งหมายความว่าไม่จำเป็นต้องมีความรู้ก่อนหน้านี้เกี่ยวกับคลาสยูทิลิตี้
ข้อเสียอย่างหนึ่งคือถ้าเราเปลี่ยนลำดับของ Emums การอ้างอิงเก่า ๆ จะไม่ทำงาน นี่อาจเป็นปัญหากับสิ่งต่าง ๆ เช่น Intent ภายใน Intent ที่ค้างอยู่เนื่องจากอาจอยู่รอดจากการอัปเดต อย่างไรก็ตามสำหรับเวลาที่เหลือมันก็โอเค
สิ่งสำคัญคือต้องทราบว่าโซลูชันอื่น ๆ เช่นการใช้ชื่อแทนตำแหน่งจะล้มเหลวหากเราเปลี่ยนชื่อค่าใด ๆ แม้ว่าในกรณีเหล่านั้นเราจะได้รับข้อยกเว้นแทนค่า Enum ที่ไม่ถูกต้อง
การใช้งาน:
// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()