의도를 통해 열거 또는 객체 전달 (최상의 솔루션)
시작했을 때 두 개의 다른 ArrayList에 액세스 해야하는 활동이 있습니다. 두 목록 모두 내가 만든 다른 객체입니다.
기본적으로 이러한 객체를 인 텐트에서 액티비티로 전달하는 방법이 필요합니다. addExtras ()를 사용할 수 있지만 Parceable 호환 클래스가 필요합니다. 클래스를 직렬화 가능하게 만들 수는 있지만 이해하면 프로그램 속도가 느려집니다.
내 옵션은 무엇입니까?
열거 형을 전달할 수 있습니까?
제쳐두고 : 인 텐트에서 매개 변수를 Activity Constructor에 전달하는 방법이 있습니까?
이것은 오래된 질문이지만 모두 Enum이 실제로 Serializable
있으므로 인 텐트에 완벽하게 추가 될 수 있다고 언급하지는 않습니다 . 이처럼 :
public enum AwesomeEnum {
SOMETHING, OTHER;
}
intent.putExtra("AwesomeEnum", AwesomeEnum.SOMETHING);
AwesomeEnum result = (AwesomeEnum) intent.getSerializableExtra("AwesomeEnum");
정적 또는 응용 프로그램 범위 변수를 사용하라는 제안은 실제로 나쁜 생각입니다. 이것은 실제로 활동을 상태 관리 시스템에 연결하며 유지 관리, 디버그 및 문제 바인딩이 어렵습니다.
대안 :
좋은 점으로 지적되었다 tedzyc 가 제공하는 솔루션이라는 사실에 대한 Oderik가 당신에게 오류를 제공합니다. 그러나 제공되는 대안은 사용하기에 다소 무너집니다 (제네릭을 사용하더라도).
열거 형을 의도에 추가하는 성능에 대해 정말로 걱정한다면 대신 다음 대안을 제안합니다.
옵션 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 : (일반적이고 재사용 가능하며 열거 형에서 분리됨)
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을 보유하고 있으므로 새로운 패러다임에 다른 옵션을 추가 할 것이라고 생각했습니다. 여기서는 확장 함수와 구체화 된 형식 (컴파일 할 때 형식을 유지)을 사용할 수 있습니다.
inline fun <reified T : Enum<T>> Intent.putExtra(victim: T): Intent =
putExtra(T::class.qualifiedName, victim.ordinal)
inline fun <reified T: Enum<T>> Intent.getEnumExtra(): T? =
getIntExtra(T::class.qualifiedName, -1)
.takeUnless { it == -1 }
?.let { T::class.java.enumConstants[it] }
이렇게하면 몇 가지 이점이 있습니다.
inline
함수 내부의 코드로 호출을 대체하는 덕분에 직렬화를 수행하기 위해 중개 오브젝트의 "오버 헤드"가 필요하지 않습니다 .- 이 기능은 SDK와 유사하므로 더 친숙합니다.
- IDE는 이러한 기능을 자동 완성하므로 유틸리티 클래스에 대한 사전 지식이 필요하지 않습니다.
용법:
// Sender usage
intent.putExtra(AwesomeEnum.SOMETHING)
// Receiver usage
val result = intent.getEnumExtra<AwesomeEnum>()
열거 형이 Parcelable을 구현하도록 만들 수 있습니다.
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];
}
};
}
그런 다음 Intent.putExtra (String, Parcelable)를 사용할 수 있습니다.
업데이트 : enum.values()
매 호출마다 새로운 배열 을 할당하는 wreckgar의 의견에 유의 하십시오.
업데이트 : Android Studio에는 ParcelableEnum
이 솔루션을 구현 하는 라이브 템플릿 이 있습니다. (Windows에서는 Ctrl+ 사용 J)
열거 형을 문자열로 전달할 수 있습니다.
public enum CountType {
ONE,
TWO,
THREE
}
private CountType count;
count = ONE;
String countString = count.name();
CountType countToo = CountType.valueOf(countString);
주어진 문자열이 지원되면 아무런 문제없이 열거 형 값을 전달할 수 있어야합니다.
열거 형을 의도적으로 전달하기 위해 열거 형을 정수로 변환 할 수 있습니다.
전의:
public enum Num{A ,B}
전송 (열에서 정수로) :
Num send = Num.A;
intent.putExtra("TEST", send.ordinal());
수신 (정수에서 열거로) :
Num rev;
int temp = intent.getIntExtra("TEST", -1);
if(temp >= 0 && temp < Num.values().length)
rev = Num.values()[temp];
친애하는. :)
실제로 필요한 경우 다음과 같이 name()
and를 사용하여 열거 형을 문자열로 직렬화 할 수 valueOf(String)
있습니다.
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;
}
}
}
열거 형에 변경 가능한 상태 (실제로해서는 안되는)가있는 경우 분명히 작동하지 않습니다.
It may be possible to make your Enum implement Serializable then you can pass it via the Intent, as there is a method for passing it as a serializable. The advice to use int instead of enum is bogus. Enums are used to make your code easier to read and easier to maintain. It would a large step backwards into the dark ages to not be able to use Enums.
about Oderik's post:
You can make your enum implement Parcelable which is quite easy for enums:
public enum MyEnum implements Parcelable { ... } You can than use Intent.putExtra(String, Parcelable).
If you define a MyEnum variable myEnum, then do intent.putExtra("Parcelable1", myEnum), you will get a "The method putExtra(String, Parcelable) is ambiguous for the type Intent" error message. because there is also a Intent.putExtra(String, Parcelable) method, and original 'Enum' type itself implements the Serializable interface, so compiler does not know choose which method(intent.putExtra(String, Parcelable/or Serializable)).
Suggest that remove the Parcelable interface from MyEnum, and move the core code into wrap class' Parcelable implementation, like this(Father2 is a Parcelable and contain an enum field):
public class Father2 implements Parcelable {
AnotherEnum mAnotherEnum;
int mField;
public Father2(AnotherEnum myEnum, int field) {
mAnotherEnum = myEnum;
mField = field;
}
private Father2(Parcel in) {
mField = in.readInt();
mAnotherEnum = AnotherEnum.values()[in.readInt()];
}
public static final Parcelable.Creator<Father2> CREATOR = new Parcelable.Creator<Father2>() {
public Father2 createFromParcel(Parcel in) {
return new Father2(in);
}
@Override
public Father2[] newArray(int size) {
return new Father2[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mField);
dest.writeInt(mAnotherEnum.ordinal());
}
}
then we can do:
AnotherEnum anotherEnum = AnotherEnum.Z;
intent.putExtra("Serializable2", AnotherEnum.X);
intent.putExtra("Parcelable2", new Father2(AnotherEnum.X, 7));
you can use enum constructor for enum to have primitive data type..
public enum DaysOfWeek {
MONDAY(1),
TUESDAY(2),
WEDNESDAY(3),
THURSDAY(4),
FRIDAY(5),
SATURDAY(6),
SUNDAY(7);
private int value;
private DaysOfWeek(int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static final SparseArray<DaysOfWeek> map = new SparseArray<DaysOfWeek>();
static
{
for (DaysOfWeek daysOfWeek : DaysOfWeek.values())
map.put(daysOfWeek.value, daysOfWeek);
}
public static DaysOfWeek from(int value) {
return map.get(value);
}
}
you can use to pass int as extras then pull it from enum using its value.
I like simple.
- The Fred activity has two modes --
HAPPY
andSAD
. - Create a static
IntentFactory
that creates yourIntent
for you. Pass it theMode
you want. - The
IntentFactory
uses the name of theMode
class as the name of the extra. - The
IntentFactory
converts theMode
to aString
usingname()
- Upon entry into
onCreate
use this info to convert back to aMode
. You could use
ordinal()
andMode.values()
as well. I like strings because I can see them in the debugger.public class Fred extends Activity { public static enum Mode { HAPPY, SAD, ; } public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.betting); Intent intent = getIntent(); Mode mode = Mode.valueOf(getIntent().getStringExtra(Mode.class.getName())); Toast.makeText(this, "mode="+mode.toString(), Toast.LENGTH_LONG).show(); } public static Intent IntentFactory(Context context, Mode mode){ Intent intent = new Intent(); intent.setClass(context,Fred.class); intent.putExtra(Mode.class.getName(),mode.name()); return intent; } }
I think your best bet is going to be to convert those lists into something parcelable such as a string (or map?) to get it to the Activity. Then the Activity will have to convert it back to an array.
Implementing custom parcelables is a pain in the neck IMHO so I would avoid it if possible.
Consider Following enum ::
public static enum MyEnum {
ValueA,
ValueB
}
For Passing ::
Intent mainIntent = new Intent(this,MyActivity.class);
mainIntent.putExtra("ENUM_CONST", MyEnum.ValueA);
this.startActivity(mainIntent);
To retrieve back from the intent/bundle/arguments ::
MyEnum myEnum = (MyEnum) intent.getSerializableExtra("ENUM_CONST");
Don't use enums. Reason #78 to not use enums. :) Use integers, which can easily be remoted through Bundle and Parcelable.
'Programing' 카테고리의 다른 글
Java에서 부울 변수를 전환하는 가장 확실한 방법은 무엇입니까? (0) | 2020.05.08 |
---|---|
이미지 데드 센터를 부트 스트랩과 정렬하는 방법 (0) | 2020.05.08 |
Node.js에서 Mongoose로 페이지 매김하는 방법? (0) | 2020.05.08 |
bash 쉘에서 하나의 문자열을 하나 이상의 공백으로 구분하여 여러 문자열로 나누는 방법은 무엇입니까? (0) | 2020.05.08 |
ASP.NET 웹 양식에 Runat =“Server”속성이 필요한 이유는 무엇입니까? (0) | 2020.05.08 |