【问题标题】:Android: How to put an Enum in a Bundle?Android:如何将枚举放入捆绑包中?
【发布时间】:2011-03-18 14:33:30
【问题描述】:

如何将 Enum 对象添加到 Android Bundle?

【问题讨论】:

  • 在我看来,Google 员工的建议很糟糕。枚举非常方便,并且值得承受所描述的开销。
  • 如果您认为第二个可能是更好的选择,您能否重新审视答案并接受第二个答案。
  • 在上面链接中的“避免枚举”标题下,它现在说:性能神话本文档的先前版本提出了各种误导性声明。我们在这里解决其中的一些问题。
  • 该部分甚至不再存在。

标签: android enums android-bundle


【解决方案1】:

在 Kotlin 中:

enum class MyEnum {
  NAME, SURNAME, GENDER
}

把这个枚举放在一个Bundle中:

Bundle().apply {
  putInt(MY_ENUM_KEY, MyEnum.ordinal)
}

从 Bundle 中获取枚举:

val ordinal = getInt(MY_ENUM_KEY, 0)
MyEnum.values()[ordinal]

完整示例:

class MyFragment : Fragment() {

    enum class MyEnum {
        NAME, SURNAME, GENDER
    }

    companion object {
        private const val MY_ENUM_KEY = "my_enum_key"

        fun newInstance(myEnum: MyEnum) = MyFragment().apply {
            arguments = Bundle().apply {
                putInt(MY_ENUM_KEY, myEnum.ordinal)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        with(requireArguments()) {
            val ordinal = getInt(MY_ENUM_KEY, 0)
            val myEnum = MyEnum.values()[ordinal]
        }
    }
}

在 Java 中:

public final class MyFragment extends Fragment {
    private static final String MY_ENUM_KEY = "my_enum";

    public enum MyEnum {
        NAME,
        SURNAME,
        GENDER
    }

    public final MyFragment newInstance(MyEnum myEnum) {
        Bundle bundle = new Bundle();
        bundle.putInt(MY_ENUM_KEY, myEnum.ordinal());
        MyFragment fragment = new MyFragment();
        fragment.setArguments(bundle);
        return fragment;
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Bundle arguments = this.requireArguments();
        int ordinal = arguments.getInt(MY_ENUM_KEY, 0);
        MyEnum myEnum = MyEnum.values()[ordinal];
    }
}

【讨论】:

    【解决方案2】:

    我创建了一个 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) )
    }
    
    

    创建一个包并添加:

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

    得到:

    intent?.getEnumExtra< ENUM_CLAS >( "KEY" )?.let{}
    
    

    【讨论】:

    • 片段怎么样?你在那里没有意图。你是怎么得到它的?
    • 在片段中你可以使用arguments。例如:arguments?.getString("YOUR_KEY")
    【解决方案3】:

    枚举是可序列化的,所以没有问题。

    给定以下枚举:

    enum YourEnum {
      TYPE1,
      TYPE2
    }
    

    捆绑:

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

    意图:

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

    【讨论】:

    • 这个方法有问题吗:保存:outState.putSerializable("trollData", game.getFunkyTrolls());加载:game.setFunkyTrolls((Game.FunkyTroll[]) savedInstanceState.getSerializable("trollData"));
    • 我会投票给你的答案,但问题是关于将 Enum 添加到 Bundle 中,而你的回复解释了如何将它添加到 Intent 中......当然这几乎是一样的,但是 Alejandro下面修正了你的答案。
    • 与Bundle一起使用时,会抛出ClassNotFoundException
    • 这可能非常慢,并且无法扩展到包含枚举等的数组。请参阅stackoverflow.com/a/5551155/175156
    • @yincrash 枚举使用非常快的自定义序列化。证明:docs.oracle.com/javase/1.5.0/docs/guide/serialization/spec/…
    【解决方案4】:

    对于Intent,您可以这样使用:

    意图:科特林

    第一个活动:

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

    第二个活动:

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

    【讨论】:

      【解决方案5】:

      我使用 kotlin。

      companion object {
      
              enum class Mode {
                  MODE_REFERENCE,
                  MODE_DOWNLOAD
              }
      }
      

      然后放入Intent:

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

      当你通过净值获得价值时:

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

      【讨论】:

      • 这是一个很好的答案,但它可以用扩展方法来补充,我在这里使用这个:gist.github.com/Grohden/eea5ff9d5e3ba955aa2f57ff0df2683f
      • .name 是非常重要的路径
      • 这似乎比将 Enum 变成一个 parcelable 简单得多,如果使用 Android 的 Room 数据库库,这将增加更多的复杂性。
      • @GabrielDeOliveiraRohden,我不确定是否需要扩展方法,因为它似乎只能避免在putString() 中使用.name。使用 Kotlin,如果使用 .apply,它已经被简化了。 例如ContentFragment.newInstance(Bundle().apply { putString(FEED_TYPE_KEY, SAVED.name) })
      • @AdamHurwitz,提议的扩展函数不就是 Kotlins 扩展函数的重点吗?它强制你不要犯错误,它是完美的! @GabrielDeOliveiraRohden 的链接bundle.putEnum(key, enum) | bundle.getEnum&lt;&gt;(key)
      【解决方案6】:

      另一种选择:

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

      【讨论】:

      • 你可以使用putSerializable(key, value)/(Type) getSerializable(key)putString(key, value.name())/Type.valueOf(getString(key)),这里的Parcelable实现是多余且无意义的。
      • 使用Parcelable 是存储枚举值数组的好方法。
      【解决方案7】:

      有一点需要注意——如果您使用bundle.putSerializableBundle 添加到通知中,您可能会遇到以下问题:

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

      要解决此问题,您可以执行以下操作:

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

      然后可以这样使用:

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

      【讨论】:

        【解决方案8】:

        我认为将 enum 转换为 int(对于普通枚举)然后在 bundle 上设置是最简单的方法。喜欢这个意图代码:

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

        然后检查状态:

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

        但不适用于所有枚举类型!

        【讨论】:

          【解决方案9】:

          一个简单的方法,给枚举赋整数值

          请看下面的例子:

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

          发送方:

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

          接收方:

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

          【讨论】:

            【解决方案10】:

            使用 bundle.putSerializable(String key, Serializable s) 和 bundle.getSerializable(String key):

            enum Mode = {
              BASIC, ADVANCED
            }
            
            Mode m = Mode.BASIC;
            
            bundle.putSerializable("mode", m);
            
            ...
            
            Mode m;
            m = bundle.getSerializable("mode");
            

            文档:http://developer.android.com/reference/android/os/Bundle.html

            【讨论】:

              【解决方案11】:

              为了完整起见,这是一个完整的示例,说明如何从包中放入和取回枚举。

              给定以下枚举:

              enum EnumType{
                  ENUM_VALUE_1,
                  ENUM_VALUE_2
              }
              

              您可以将枚举放入一个包中:

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

              然后取回枚举:

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

              【讨论】:

                【解决方案12】:

                我知道这是一个老问题,但我遇到了同样的问题,我想分享一下我是如何解决的。关键是 Miguel 所说的:枚举是可序列化的。

                给定以下枚举:

                enum YourEnumType {
                    ENUM_KEY_1, 
                    ENUM_KEY_2
                }
                

                放:

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

                【讨论】:

                • 基于此:stackoverflow.com/questions/15521309/…,自定义枚举不可序列化。所以枚举中的自定义字段不会被序列化。你是怎么处理的?
                • 好问题@clu!也许那时您应该考虑将其作为字符串传递,如stackoverflow.com/questions/609860/… 中所述
                • @clu 不希望自定义字段被序列化。如果它只是上面代码中的普通枚举,它就可以正常工作。
                • @AlejandroColorado 这对 miguel 的回答有什么影响?
                • Miguel 的答案是在 2015 年编辑的。最初的答案没有提到捆绑包,它只显示了一个意图示例。
                【解决方案13】:

                最好将它作为字符串从 myEnumValue.name() 传递并从 YourEnums.valueOf(s) 中恢复,否则必须保留枚举的顺序!

                更多解释:Convert from enum ordinal to enum type

                【讨论】:

                • 如果序列化->反序列化在运行时立即发生,例如从一个活动调用到另一个活动时,排序无关紧要。这可能是跨进程的问题,例如将 Intent 从一个应用发送到旧版本的应用。
                猜你喜欢
                • 1970-01-01
                • 2012-12-03
                • 2010-11-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-28
                • 1970-01-01
                相关资源
                最近更新 更多