256 Stimmen

Übergabe von Enum oder Objekt durch einen Intent (die beste Lösung)

Ich habe eine Aktivität, die beim Start Zugriff auf zwei verschiedene ArrayLists benötigt. Beide Listen sind unterschiedliche Objekte, die ich selbst erstellt habe.

Grundsätzlich benötige ich eine Möglichkeit, diese Objekte von einem Intent an die Aktivität zu übergeben. Ich kann addExtras() verwenden, aber dies erfordert eine Parceable kompatible Klasse. Ich könnte meine Klassen zu serializable übergeben werden, aber wie ich verstehe, verlangsamt dies das Programm.

Welche Möglichkeiten habe ich?

Kann ich eine Enum übergeben?

Nebenbei bemerkt: Gibt es eine Möglichkeit, Parameter an einen Activity Constructor aus einem Intent zu übergeben?

648voto

pablisco Punkte 13542

Dies ist eine alte Frage, aber jeder vergisst zu erwähnen, dass Enums eigentlich Serializable und kann daher problemlos als Zusatz zu einem Vorhaben hinzugefügt werden. Zum Beispiel so:

public enum AwesomeEnum {
  SOMETHING, OTHER;
}

intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);

AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");

Der Vorschlag, statische oder anwendungsweite Variablen zu verwenden, ist eine wirklich schlechte Idee. Dadurch werden Ihre Aktivitäten an ein zustandsverwaltendes System gekoppelt, und es ist schwer zu warten, zu debuggen und zu problematisieren.


ALTERNATIVEN:

Ein guter Punkt wurde angemerkt von tedzyc über die Tatsache, dass die Lösung, die von Oderik gibt eine Fehlermeldung aus. Die angebotene Alternative ist jedoch etwas umständlich in der Anwendung (selbst bei Verwendung von Generika).

Wenn Sie sich wirklich Sorgen um die Leistung des Hinzufügens des Enums zu einem Intent machen, schlage ich stattdessen diese Alternativen vor:

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

OPTION 2: (generisch, wiederverwendbar und vom Enum entkoppelt)

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

OPTION 3 (mit Kotlin):

Es ist schon eine Weile her, aber da wir jetzt Kotlin haben, dachte ich, ich würde eine weitere Option für das neue Paradigma hinzufügen. Hier können wir Erweiterungsfunktionen und reifizierte Typen verwenden (die den Typ beim Kompilieren beibehalten).

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

Diese Vorgehensweise hat einige Vorteile.

  • Wir benötigen nicht den "Overhead" eines zwischengeschalteten Objekts, um die Serialisierung durchzuführen, da dies alles dank der inline der die Aufrufe durch den Code innerhalb der Funktion ersetzt.
  • Die Funktionen sind vertrauter, da sie den SDK-Funktionen ähnlich sind.
  • Die IDE füllt diese Funktionen automatisch aus, d. h. es sind keine Vorkenntnisse über die Utility-Klasse erforderlich.

Einer der Nachteile ist, dass, wenn wir die Reihenfolge der Emums ändern, jede alte Referenz nicht mehr funktioniert. Dies kann ein Problem mit Dingen wie Intents innerhalb von anhängigen Intents sein, da sie Updates überleben können. Für den Rest der Zeit sollte es jedoch in Ordnung sein.

Es ist wichtig zu beachten, dass andere Lösungen, wie die Verwendung des Namens anstelle der Position, ebenfalls fehlschlagen, wenn wir einen der Werte umbenennen. Allerdings erhalten wir in diesen Fällen eine Ausnahme anstelle des falschen Enum-Werts.

使用方法

// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()

114voto

Oderik Punkte 2216

Sie können Ihre enum implementieren Parcelable, die ganz einfach für enums ist:

public enum MyEnum implements Parcelable {
    VALUE;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(final Parcel dest, final int flags) {
        dest.writeInt(ordinal());
    }

    public static final Creator<MyEnum> CREATOR = new Creator<MyEnum>() {
        @Override
        public MyEnum createFromParcel(final Parcel source) {
            return MyEnum.values()[source.readInt()];
        }

        @Override
        public MyEnum[] newArray(final int size) {
            return new MyEnum[size];
        }
    };
}

Sie können dann Intent.putExtra(String, Parcelable) verwenden.

UPDATE: Bitte beachten Sie den Kommentar von wreckgar, dass enum.values() ordnet bei jedem Aufruf ein neues Array zu.

UPDATE: Android Studio bietet eine Live-Vorlage ParcelableEnum die diese Lösung umsetzt. (Unter Windows verwenden Sie Ctrl + J )

28voto

Sie können eine Aufzählung als String übergeben.

public enum CountType {
    ONE,
    TWO,
    THREE
}

private CountType count;
count = ONE;

String countString = count.name();

CountType countToo = CountType.valueOf(countString);

Da Zeichenketten unterstützt werden, sollten Sie in der Lage sein, den Wert des Enums ohne Probleme zu übergeben.

22voto

TURTLE Punkte 229

Um eine Aufzählung mit Absicht zu übergeben, können Sie die Aufzählung in eine Ganzzahl umwandeln.

Ex:

public enum Num{A ,B}

Sending(enum to integer):

Num send = Num.A;
intent.putExtra("TEST", send.ordinal());

Empfangen(integer to enum):

Num rev;
int temp = intent.getIntExtra("TEST", -1);
if(temp >= 0 && temp < Num.values().length)
    rev = Num.values()[temp];

Mit freundlichen Grüßen. :)

15voto

Jan Berkel Punkte 3323

Wenn Sie es wirklich brauchen, können Sie ein Enum als String serialisieren, indem Sie name() y valueOf(String) wie folgt:

 class Example implements Parcelable { 
   public enum Foo { BAR, BAZ }

   public Foo fooValue;

   public void writeToParcel(Parcel dest, int flags) {
      parcel.writeString(fooValue == null ? null : fooValue.name());
   }

   public static final Creator<Example> CREATOR = new Creator<Example>() {
     public Example createFromParcel(Parcel source) {        
       Example e = new Example();
       String s = source.readString(); 
       if (s != null) e.fooValue = Foo.valueOf(s);
       return e;
     }
   }
 }

Dies funktioniert natürlich nicht, wenn Ihre Enums veränderbaren Zustand haben (was sie nicht sollten, wirklich).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X