Android: Comment mettre un Enum dans un Bundle?


332

Comment ajouter un objet Enum à un bundle Android?


11
À mon avis, les conseils du personnel de Google sont mauvais. Les énumérations sont très pratiques et la souffrance des frais généraux décrits en vaut la peine.
ognian

3
pouvez-vous revoir les réponses et accepter la 2e si vous pensez que cela pourrait être un meilleur choix.
philipp

6
Sous l'intitulé «Éviter les énumérations» dans le lien ci-dessus, il est maintenant dit ceci: Mythes sur les performances Les versions précédentes de ce document faisaient diverses allégations trompeuses. Nous en abordons certains ici.
StackOverflowed

cette section n'est même plus présente.
Nathaniel D. Waggoner

Réponses:


726

Les énumérations sont sérialisables, il n'y a donc aucun problème.

Étant donné l'énumération suivante:

enum YourEnum {
  TYPE1,
  TYPE2
}

Paquet:

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

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

Intention:

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

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

Y a-t-il un problème avec cette méthode: sauvegarde: outState.putSerializable("trollData", game.getFunkyTrolls());chargement game.setFunkyTrolls((Game.FunkyTroll[]) savedInstanceState.getSerializable("trollData"));:?
Moberg

21
J'aurais voté pour votre réponse, mais la question concernait l'ajout de l'énumération à un ensemble et votre réponse explique comment l'ajouter à une intention ... Certes, c'est presque la même chose, mais Alejandro ci-dessous a corrigé votre réponse.
Pooks

2
lors de son utilisation avec Bundle, il lanceClassNotFoundException
Nom d'affichage

2
cela peut être super lent et ne s'adapte pas aux tableaux de choses qui contiennent de l'énumération, etc. Voir stackoverflow.com/a/5551155/175156
yincrash

1
@yincrash enum utilise une sérialisation personnalisée qui est assez rapide. Preuve: docs.oracle.com/javase/1.5.0/docs/guide/serialization/spec/…
Miha_x64

164

Je sais que c'est une vieille question, mais je suis venu avec le même problème et je voudrais partager comment je l'ai résolu. La clé est ce que Miguel a dit: les énumérations sont sérialisables.

Étant donné l'énumération suivante:

enum YourEnumType {
    ENUM_KEY_1, 
    ENUM_KEY_2
}

Mettre:

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

3
Sur la base de ceci: stackoverflow.com/questions/15521309/… , les énumérations personnalisées ne sont pas sérialisables. Les champs personnalisés d'un Enum ne seront donc pas sérialisés. Comment gérez-vous cela?
clu

Jolie question @clu! Peut-être que vous devriez alors penser en le passant comme une chaîne comme indiqué dans stackoverflow.com/questions/609860/…
Alejandro Colorado

@clu En ne s'attendant pas à ce que les champs personnalisés soient sérialisés. Cela fonctionne bien si c'est juste une énumération normale comme dans le code ci-dessus.
bluehallu

@AlejandroColorado qu'est-ce que cela ajoute à la réponse de miguel?
tir38

1
La réponse de Miguel a été révisée en 2015. La réponse originale ne disait rien sur les paquets, elle ne montrait qu'un exemple d'intention.
Alejandro Colorado

41

Par souci d'exhaustivité, ceci est un exemple complet de la façon de mettre en place et de récupérer une énumération à partir d'un bundle.

Étant donné l'énumération suivante:

enum EnumType{
    ENUM_VALUE_1,
    ENUM_VALUE_2
}

Vous pouvez mettre l'énumération dans un bundle:

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

Et récupérez l'énumération:

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

32

J'utilise du kotlin.

companion object {

        enum class Mode {
            MODE_REFERENCE,
            MODE_DOWNLOAD
        }
}

puis mettre en intention:

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

lorsque vous net pour obtenir de la valeur:

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

6
C'est une bonne réponse, mais elle peut être complétée par une méthode d'extension, j'utilise celle-ci ici: gist.github.com/Grohden/eea5ff9d5e3ba955aa2f57ff0df2683f
Gabriel De Oliveira Rohden

.nameest un chemin très important
Phan Van Linh

Cela semble beaucoup plus simple que de transformer l' Enum en une parcellaire, ce qui créerait une complexité supplémentaire si vous travaillez avec la bibliothèque de base de données Room d'Android .
Adam Hurwitz

@GabrielDeOliveiraRohden, je ne suis pas sûr que la méthode d'extension soit nécessaire car elle semble éviter uniquement l'utilisation de .namein putString(). Avec Kotlin, c'est déjà simplifié si vous l'utilisez .apply. Par exemple :ContentFragment.newInstance(Bundle().apply { putString(FEED_TYPE_KEY, SAVED.name) })
Adam Hurwitz

@AdamHurwitz, la fonction d'extension proposée n'est-elle pas l'intégralité des fonctions d'extension de Kotlins? Cela vous oblige à ne pas faire d'erreurs, c'est parfait! Lien de bundle.putEnum(key, enum) | bundle.getEnum<>(key)
@GabrielDeOliveiraRohden

17

Il peut être préférable de le passer en tant que chaîne à partir de myEnumValue.name () et de le restaurer à partir de YourEnums.valueOf (s), sinon la commande de l'énumération doit être préservée!

Explication plus longue: conversion de l'énumération ordinale en type énumération


1
L'ordre n'a pas d'importance si la sérialisation-> désérialisation se produit immédiatement au moment de l'exécution, comme lors d'un appel d'une activité à une autre. Cela pourrait être un problème dans tous les processus tels que l'envoi d'intentions d'une application à une ancienne version de l'application.
miguel

6

Une autre option:

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
Vous pouvez utiliser putSerializable(key, value)/ (Type) getSerializable(key)ou putString(key, value.name())/ Type.valueOf(getString(key)), la mise en œuvre de Parcelable est ici redondante et absurde.
Miha_x64

1
L'utilisation Parcelableest une bonne solution pour stocker des tableaux de valeurs Enum.
RhodanV5500


2

Pour l' intention, vous pouvez utiliser cette méthode:

Intention: 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

Une chose à savoir - si vous utilisez bundle.putSerializablepour Bundleajouter un à une notification, vous pouvez rencontrer le problème suivant:

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

...

Pour contourner ce problème, vous pouvez procéder comme suit:

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

Qui peut ensuite être utilisé comme ceci:

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

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

0

Une manière simple, attribuer une valeur entière à enum

Voir l'exemple suivant:

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

}

Côté expéditeur:

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

Côté récepteur:

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

Je pense que convertir l'énumération en int (pour l'énumération normale), puis définir le bundle a été la manière la plus simple. comme ce code d'intention:

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

puis pour vérifier l'état:

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

mais ne fonctionne pas pour tous les types d'énumération!


0

J'ai créé une extension 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) )
}

Créez un bundle et ajoutez:

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

et obtenir:

intent?.getEnumExtra< ENUM_CLAS >( "KEY" )?.let{}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.