[java] Android에서 열거 형 사용을 엄격히 피해야합니까?

Bundle다음과 같은 인터페이스에서 키와 같은 관련 상수 세트를 함께 정의했습니다 .

public interface From{
    String LOGIN_SCREEN = "LoginSCreen";
    String NOTIFICATION = "Notification";
    String WIDGET = "widget";
}

이것은 관련 상수를 함께 그룹화하고 정적 가져 오기 (구현이 아님)를 만들어 사용하는 더 좋은 방법을 제공합니다. 내가 알고있는 Android프레임 워크도 같은 동일한 방법으로 상수를 사용합니다 Toast.LENTH_LONG, View.GONE.

그러나 나는 종종 Java Enums상수를 나타내는 훨씬 더 좋고 강력한 방법을 제공 한다고 느낍니다 .

그러나 사용의 성취도 문제가 enums에가 Android?

약간의 조사로 나는 혼란에 빠졌습니다. 이 질문에서
? 안드로이드의 성능 정보에서 제거 “당신 만의 int 필요 않도록 열거 형” 는 것이 분명 Google제거했습니다 “피 열거 형을” 성능 팁에서, 그러나 그것의에서 공식 훈련 문서는 메모리 오버 헤드에주의 가 명확하게 말한다 절 : “열거 형을 종종 정적 상수보다 두 배 이상의 메모리가 필요합니다. Android에서 열거 형을 사용하는 것은 엄격히 피해야합니다. “ 여전히 유효합니까? (예 : Java1.6 이후 버전)

내가 관찰 한 가지 더 문제가 전송하는 것입니다 enums통해 intents사용하여 Bundle직렬화에 의해 내가 그들을 보내야합니다 (예 :putSerializable() , 기본 putString()메소드에 비해 비용이 많이 드는 작업이라고 생각하지만 enums무료로 제공하지만).

누군가 같은 것을 표현하는 가장 좋은 방법이 무엇인지 명확히 해줄 수 있습니까 Android? 에 사용 enums을 엄격히 피해야 Android합니까?



답변

enum기능이 필요할 때 사용하십시오 . 엄격하게 피하지 마십시오 .

Java enum은 더 강력하지만 기능이 필요하지 않은 경우 상수를 사용하면 공간을 덜 차지하고 원시 자체가 될 수 있습니다.

열거 형을 사용하는 경우 :

  • 당신이 받아 들일 수 – 유형 검사 (내가 부르는 아래 참조 목록에 값을, 그들은 연속없는 연속 여기)
  • 메서드 오버로딩-모든 열거 형 상수에는 자체 메서드 구현이 있습니다.

    public enum UnitConverter{
        METERS{
            @Override
            public double toMiles(final double meters){
                return meters * 0.00062137D;
            }
    
            @Override
            public double toMeters(final double meters){
                return meters;
            }
        },
        MILES{
            @Override
            public double toMiles(final double miles){
                return miles;
            }
    
            @Override
            public double toMeters(final double miles){
                return miles / 0.00062137D;
            }
        };
    
        public abstract double toMiles(double unit);
        public abstract double toMeters(double unit);
    }
  • 더 많은 데이터-하나의 상수에 하나의 변수에 넣을 수없는 하나 이상의 정보가 포함되어 있습니다.

  • 복잡한 데이터-데이터를 조작하는 데 필요한 방법

하면 되지 열거를 사용하는 방법 :

  • 한 유형의 모든 값을 허용 할 수 있으며 상수에는 가장 많이 사용되는 값만 포함됩니다.
  • 연속 데이터를받을 수 있습니다.

    public class Month{
        public static final int JANUARY = 1;
        public static final int FEBRUARY = 2;
        public static final int MARCH = 3;
        ...
    
        public static String getName(final int month){
            if(month <= 0 || month > 12){
                throw new IllegalArgumentException("Invalid month number: " + month);
            }
    
            ...
        }
    }
  • 이름 (예를 들어)
  • 실제로 열거 형이 필요하지 않은 다른 모든 것

열거 형은 더 많은 공간을 차지합니다.

  • 열거 형 상수에 대한 단일 참조는 4 바이트를 차지 합니다.
  • 모든 열거 형 상수는 8 바이트에 정렬 된 필드 크기 + 개체의 오버 헤드의 합계 인 공간을 차지 합니다.
  • 열거 형 클래스 자체가 일부 공간을 차지합니다.

상수는 더 적은 공간을 차지합니다.

  • 상수에는 참조가 없으므로 순수한 데이터입니다 (참조 인 경우에도 열거 형 인스턴스는 다른 참조에 대한 참조가 됨).
  • 기존 클래스에 상수를 추가 할 수 있습니다. 다른 클래스를 추가 할 필요가 없습니다.
  • 상수는 인라인 될 수 있습니다. 확장 된 컴파일 타임 기능을 제공합니다 (예 : null 검사, 데드 코드 찾기 등).


답변

열거 형에 단순히 값이있는 경우 다음과 같이 IntDef / StringDef를 사용해야합니다.

https://developer.android.com/studio/write/annotations.html#enum-annotations

예 : 대신 :

enum NavigationMode {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS} 

너는 사용한다:

@IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
@Retention(RetentionPolicy.SOURCE)
public @interface NavigationMode {}

public static final int NAVIGATION_MODE_STANDARD = 0;
public static final int NAVIGATION_MODE_LIST = 1;
public static final int NAVIGATION_MODE_TABS = 2;

매개 변수 / 반환 된 값으로있는 함수에서 다음을 사용하십시오.

@NavigationMode
public abstract int getNavigationMode();

public abstract void setNavigationMode(@NavigationMode int mode);

열거 형이 복잡한 경우 열거 형을 사용하십시오. 그렇게 나쁘진 않아.

열거 형과 상수 값을 비교하려면 여기를 읽어야합니다.

http://hsc.com/Blog/Best-Practices-For-Memory-Optimization-on-Android-1

그들의 예는 2 개의 값이있는 열거 형입니다. 상수 정수를 사용할 때 128 바이트에 비해 dex 파일에서 1112 바이트를 사용합니다. 열거 형이 실제 클래스이므로 C / C ++에서 작동하는 방식과는 대조적으로 의미가 있습니다.


답변

이전 답변 외에도 Proguard를 사용하는 경우 (확실히 크기를 줄이고 코드를 난독 화하기 위해 수행해야 함) 가능한 모든 곳 Enums으로 자동 변환됩니다 @IntDef.

https://www.guardsquare.com/en/proguard/manual/optimizations

클래스 / 언 박싱 / 열거 형

가능한 경우 열거 형 유형을 정수 상수로 단순화합니다.

따라서 일부 불연속 값이 있고 일부 메서드가 동일한 유형의 다른 값이 아닌이 값만 사용할 수 있도록 허용해야하는 경우 EnumProguard가이 수동 코드 최적화 작업을 수행 할 것이기 때문에를 사용 합니다.

그리고 여기에 Jake Wharton의 열거 형 사용에 대한 좋은 게시물이 있습니다.

라이브러리 개발자로서 저는 소비하는 앱의 크기, 메모리 및 성능에 가능한 한 영향을 미치지 않기 위해 수행해야하는 이러한 작은 최적화를 인식합니다. 그러나 […] 공용 API에 열거 형 대 정수 값을 적절한 곳에 두는 것이 완벽하다는 사실을 인식하는 것이 중요합니다. 정보에 입각 한 결정을 내리는 차이를 아는 것이 중요합니다.


답변

Android에서 열거 형 사용을 엄격히 피해야합니까?

아니요. ” 엄격하게 “는 너무 나빠서 전혀 사용해서는 안된다는 의미입니다. 열거 형 (ui 스레드에서 연속)을 사용하는 많은 (수천 또는 수백만) 작업과 같은 극단적 인 상황에서 성능 문제가 발생할 수 있습니다 . 훨씬 더 일반적인 것은 백그라운드 스레드에서 엄격하게 발생 해야하는 네트워크 I / O 작업입니다 . 열거의 가장 일반적인 사용은 아마 유형 검사의 일종입니다 – 객체인지 확인 또는 그것을 너무 빨리 당신이 열거 형의 단일 비교 및 정수의 비교 사이의 차이를 발견 할 수 없습니다이다.

누군가가 Android에서 동일한 것을 나타내는 가장 좋은 방법을 명확히 할 수 있습니까?

이것에 대한 일반적인 경험 법칙은 없습니다. 자신에게 맞는 것을 사용하고 앱을 준비하는 데 도움이됩니다. 나중에 최적화-앱의 일부 측면을 느리게하는 병목 현상이 있음을 확인한 후.


답변

Android P에서 Google은 열거 형 사용에 제한 / 이의가 없습니다.

문서는 이전에주의하도록 권장되었던 곳에서 변경되었지만 지금은 언급하지 않습니다.
https://developer.android.com/reference/java/lang/Enum


답변

두 가지 사실.

1, Enum은 JAVA에서 가장 강력한 기능 중 하나입니다.

2, Android 휴대 전화에는 일반적으로 많은 메모리가 있습니다.

그래서 제 대답은 아니오입니다. Android에서 Enum을 사용하겠습니다.


답변

추가하고 싶습니다. 키 또는 값이 주석 인터페이스 중 하나 인 List <> 또는 Map <>을 선언 할 때 @Annotations를 사용할 수 없습니다. “여기에는 주석을 사용할 수 없습니다.”라는 오류가 표시됩니다.

enum Values { One, Two, Three }
Map<String, Values> myMap;    // This works

// ... but ...
public static final int ONE = 1;
public static final int TWO = 2;
public static final int THREE = 3;

@Retention(RetentionPolicy.SOURCE)
@IntDef({ONE, TWO, THREE})
public @interface Values {}

Map<String, @Values Integer> myMap;    // *** ERROR ***

따라서 목록 / 맵으로 압축해야 할 때 enum을 사용하십시오. 추가 할 수 있지만 @annotated int / string 그룹은 할 수 없습니다.