Android: come mettere un Enum in un pacchetto?


332

Come si aggiunge un oggetto Enum a un pacchetto Android?


11
A mio avviso, i consigli dello staff di Google non vanno bene. Gli enum sono molto convenienti e vale la pena soffrire per il sovraccarico descritto.
ognian,

3
puoi rivisitare le risposte e accettare la seconda se pensi che potrebbe essere una scelta migliore.
philipp,

6
Sotto l'intestazione "Evitare enumerazioni" nel link sopra riportato ora dice questo: Miti delle prestazioni Le versioni precedenti di questo documento presentavano varie affermazioni fuorvianti. Ne affrontiamo alcuni qui.
StackOverflow

quella sezione non è nemmeno più presente.
Nathaniel D. Wagoner,

Risposte:


726

Gli enumeratori sono serializzabili, quindi non ci sono problemi.

Dato il seguente enum:

enum YourEnum {
  TYPE1,
  TYPE2
}

Bundle:

// put
bundle.putSerializable("key", YourEnum.TYPE1);

// get 
YourEnum yourenum = (YourEnum) bundle.get("key");

Intent:

// put
intent.putExtra("key", yourEnum);

// get
yourEnum = (YourEnum) intent.getSerializableExtra("key");

C'è qualcosa di sbagliato in questo metodo: salvataggio: outState.putSerializable("trollData", game.getFunkyTrolls());caricamento game.setFunkyTrolls((Game.FunkyTroll[]) savedInstanceState.getSerializable("trollData"));:?
Moberg,

21
Avrei votato a favore della tua risposta, ma la domanda riguardava l'aggiunta dell'Enum a un pacchetto e la tua risposta spiega come aggiungerlo a un Intento ... Concesso è quasi la stessa cosa, ma Alejandro sotto ha corretto la tua risposta.
Pooks,

2
quando lo si utilizza con Bundle, generaClassNotFoundException
Visualizza nome

2
questo può essere super lento e non si adatta alle matrici di cose che contengono enum, ecc See stackoverflow.com/a/5551155/175156
yincrash

1
@yincrash enum usa una serializzazione personalizzata che è abbastanza veloce. Prova: docs.oracle.com/javase/1.5.0/docs/guide/serialization/spec/…
Miha_x64

164

So che questa è una vecchia domanda, ma sono arrivato con lo stesso problema e vorrei condividere come l'ho risolto. La chiave è ciò che Miguel ha detto: gli Enum sono serializzabili.

Dato il seguente enum:

enum YourEnumType {
    ENUM_KEY_1, 
    ENUM_KEY_2
}

Mettere:

Bundle args = new Bundle();
args.putSerializable("arg", YourEnumType.ENUM_KEY_1);

3
Sulla base di questo: stackoverflow.com/questions/15521309/… , gli Enum personalizzati non sono serializzabili. Quindi i campi personalizzati in un Enum non verranno serializzati. come lo gestisci?
clu

Bella domanda @clu! Forse allora dovresti pensare di passarlo come una stringa come indicato in stackoverflow.com/questions/609860/…
Alejandro Colorado,

@clu Non prevedendo la serializzazione dei campi personalizzati. Funziona bene se è solo un enum normale come nel codice sopra.
Bluehallu,

@AlejandroColorado cosa aggiunge questo alla risposta di Miguel?
tir38,

1
La risposta di Miguel è stata modificata nel 2015. La risposta originale non diceva nulla sui fasci, mostrava solo un esempio di intento.
Alejandro Colorado,

41

Per completezza, questo è un esempio completo di come inserire e recuperare un enum da un pacchetto.

Dato il seguente enum:

enum EnumType{
    ENUM_VALUE_1,
    ENUM_VALUE_2
}

Puoi mettere l'enum in un bundle:

bundle.putSerializable("enum_key", EnumType.ENUM_VALUE_1);

E riprenditi l'enum:

EnumType enumType = (EnumType)bundle.getSerializable("enum_key");

32

Uso kotlin.

companion object {

        enum class Mode {
            MODE_REFERENCE,
            MODE_DOWNLOAD
        }
}

quindi metti in Intento:

intent.putExtra(KEY_MODE, Mode.MODE_DOWNLOAD.name)

quando fai rete per ottenere valore:

mode = Mode.valueOf(intent.getStringExtra(KEY_MODE))

6
Questa è una buona risposta, ma può essere integrata con un metodo di estensione, lo uso qui: gist.github.com/Grohden/eea5ff9d5e3ba955aa2f57ff0df2683f
Gabriel De Oliveira Rohden

.nameè un percorso molto importante
Phan Van Linh,

Questo sembra molto più semplice che trasformare Enum in un pacchetto, il che creerebbe ulteriore complessità se si lavora con la libreria di database Room di Android .
Adam Hurwitz,

@GabrielDeOliveiraRohden, non sono sicuro che il metodo di estensione sia necessario in quanto sembra evitare solo l'uso di .namein putString(). Con Kotlin è già ottimizzato se utilizzato .apply. Ad esempio :ContentFragment.newInstance(Bundle().apply { putString(FEED_TYPE_KEY, SAVED.name) })
Adam Hurwitz,

@AdamHurwitz, la funzione di estensione proposta non è l'intero punto delle funzioni di estensione di Kotlins? Ti costringe a non commettere errori, è perfetto! Link di bundle.putEnum(key, enum) | bundle.getEnum<>(key)
@GabrielDeOliveiraRohden

17

Potrebbe essere meglio passarlo come stringa da myEnumValue.name () e ripristinarlo da YourEnums.valueOf (s), altrimenti è necessario preservare l'ordinamento dell'enum!

Spiegazione più lunga: Converti da enum ordinal a enum type


1
L'ordinamento non importa se la serializzazione-> deserializzazione avviene immediatamente in fase di esecuzione, ad esempio quando si chiama da un'attività a un'altra. Potrebbe essere un problema attraverso processi come l'invio di Intenti da un'app a una versione precedente dell'app.
miguel,

6

Un'altra opzione:

public enum DataType implements Parcleable {
    SIMPLE, COMPLEX;

    public static final Parcelable.Creator<DataType> CREATOR = new Creator<DataType>() {

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

        @Override
        public DataType createFromParcel(Parcel source) {
            return DataType.values()[source.readInt()];
        }
    };

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

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

1
Puoi usare putSerializable(key, value)/ (Type) getSerializable(key)o putString(key, value.name())/ Type.valueOf(getString(key)), l'implementazione parcelabile qui è ridondante e senza senso.
Miha_x64,

1
L'utilizzo Parcelableè una buona soluzione per archiviare le matrici di valori Enum.
RhodanV5500,


2

Per Intent puoi usare in questo modo:

Intento: kotlin

FirstActivity:

val intent = Intent(context, SecondActivity::class.java)
intent.putExtra("type", typeEnum.A)
startActivity(intent)

SecondActivity:

override fun onCreate(savedInstanceState: Bundle?) {
     super.onCreate(savedInstanceState) 
     //...
     val type = (intent.extras?.get("type") as? typeEnum.Type?)
}

1

Una cosa da tenere presente: se si utilizza bundle.putSerializableper Bundleessere aggiunto a una notifica, è possibile che si verifichi il seguente problema:

*** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
    java.lang.RuntimeException: Parcelable encountered ClassNotFoundException reading a Serializable object.

...

Per aggirare questo, è possibile effettuare le seguenti operazioni:

public enum MyEnum {
    TYPE_0(0),
    TYPE_1(1),
    TYPE_2(2);

    private final int code;

    private MyEnum(int code) {
        this.code = navigationOptionLabelResId;
    }

    public int getCode() {
        return code;
    }

    public static MyEnum fromCode(int code) {
        switch(code) {
            case 0:
                return TYPE_0;
            case 1:
                return TYPE_1;
            case 2:
                return TYPE_2;
            default:
                throw new RuntimeException(
                    "Illegal TYPE_0: " + code);
        }
    }
}

Che può quindi essere utilizzato in questo modo:

// Put
Bundle bundle = new Bundle();
bundle.putInt("key", MyEnum.TYPE_0.getCode());

// Get 
MyEnum myEnum = MyEnum.fromCode(bundle.getInt("key"));

0

Un modo semplice, assegnare il valore intero a enum

Vedi il seguente esempio:

public enum MyEnum {

    TYPE_ONE(1), TYPE_TWO(2), TYPE_THREE(3);

    private int value;

    MyEnum(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

}

Lato mittente:

Intent nextIntent = new Intent(CurrentActivity.this, NextActivity.class);
nextIntent.putExtra("key_type", MyEnum.TYPE_ONE.getValue());
startActivity(nextIntent);

Lato ricevitore:

Bundle mExtras = getIntent().getExtras();
int mType = 0;
if (mExtras != null) {
    mType = mExtras.getInt("key_type", 0);
}

/* OR
    Intent mIntent = getIntent();
    int mType = mIntent.getIntExtra("key_type", 0);
*/

if(mType == MyEnum.TYPE_ONE.getValue())
    Toast.makeText(NextActivity.this, "TypeOne", Toast.LENGTH_SHORT).show();
else if(mType == MyEnum.TYPE_TWO.getValue())
    Toast.makeText(NextActivity.this, "TypeTwo", Toast.LENGTH_SHORT).show();
else if(mType == MyEnum.TYPE_THREE.getValue())
    Toast.makeText(NextActivity.this, "TypeThree", Toast.LENGTH_SHORT).show();
else
    Toast.makeText(NextActivity.this, "Wrong Key", Toast.LENGTH_SHORT).show();

0

Penso che convertire enum in int (per enum normale) e poi impostare su bundle sia stato il modo più semplice. come questo codice per intento:

myIntent.PutExtra("Side", (int)PageType.Fornt);

quindi per lo stato di controllo:

int type = Intent.GetIntExtra("Side",-1);
if(type == (int)PageType.Fornt)
{
    //To Do
}

ma non funziona per tutti i tipi di enum!


0

Ho creato un'estensione Koltin:

fun Bundle.putEnum(key: String, enum: Enum<*>) {
    this.putString( key , enum.name )
}

inline fun <reified T: Enum<T>> Intent.getEnumExtra(key:String) : T {
    return enumValueOf( getStringExtra(key) )
}

Crea un pacchetto e aggiungi:

Bundle().also {
   it.putEnum( "KEY" , ENUM_CLAS.ITEM )
}

e prendi:

intent?.getEnumExtra< ENUM_CLAS >( "KEY" )?.let{}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.