web-dev-qa-db-ja.com

Androidで列挙型の使用を厳密に避けるべきですか?

以下のようなインターフェースでBundleキーのような関連する定数のセットを一緒に定義していました。

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

これにより、関連する定数をグループ化し、静的なインポート(実装ではない)を使用するより良い方法が提供されます。 Androidフレームワークも、Toast.LENTH_LONGView.GONEなどのように定数を使用します。

ただし、Java Enumsは定数を表現するためのはるかに優れた強力な方法を提供すると感じます。

しかし、enumsAndroidを使用する際にパフォーマンスの問題はありますか?

少しの研究で、私は混乱してしまいました。この質問から 「Intが必要なEnumを避ける」はAndroidのパフォーマンスのヒントから削除されましたか?Googleが削除されたことは明らかです「Avoid enums」パフォーマンスのヒントからですが、公式のトレーニングドキュメントから メモリオーバーヘッドに注意してください セクションには次のように明記されています:静的定数として。 Androidでは列挙型の使用を厳密に避ける必要があります。 "これは引き続き有効ですか?(たとえば、Javaバージョン1.6以降)

私が観察したもう1つの問題は、enumsを使用してintentsを介してBundleを送信することです。それらをシリアル化して送信する必要があります(つまり、putSerializable()enumsは無料で提供していますが、プリミティブなputString()メソッドと比較して高価な操作だと思います)。

誰かがAndroidで同じものを表すための最良の方法であるものを明確にしていただけますか? enumsAndroidを使用することを厳密に避けるべきですか?

89
nvinayshetty

機能が必要な場合は、enumを使用します。 回避しないでくださいstrictly.

Java列挙型はより強力ですが、その機能が必要ない場合、定数を使用すると、占有するスペースが少なくなり、プリミティブになる可能性があります。

列挙型を使用する場合:

  • 型チェック-onlyリストされた値を受け入れることができ、それらは連続ではありません(以下を参照してくださいcontinuousここ)
  • メソッドのオーバーロード-すべての列挙定数にはメソッドの独自の実装があります

    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);
    }
    
  • より多くのデータ-1つの定数には、1つの変数に入れることができない複数の情報が含まれています

  • 複雑なデータ-データを操作するためのメソッドが常に必要です

列挙型を使用するnotの場合:

  • 1つのタイプのすべての値を受け入れることができ、定数には最もよく使用されるもののみが含まれます
  • 連続データを受け入れることができます

    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);
            }
    
            ...
        }
    }
    
  • 名前の場合(例のように)
  • 本当に列挙型を必要としない他のすべてのために

列挙型はより多くのスペースを占有します

  • enum定数への単一の参照は4バイトを占有します
  • すべての列挙型定数は、スペースを占有しますフィールドのサイズの合計 8バイトに整列+ オブジェクトのオーバーヘッド
  • enumクラス自体がスペースを占有します

定数が占めるスペースが少ない

  • 定数には参照がないため、純粋なデータです(参照であっても、enumインスタンスは別の参照への参照になります)
  • 既存のクラスに定数を追加できます-別のクラスを追加する必要はありません
  • 定数はインライン化できます。コンパイル時の拡張機能(nullチェック、デッドコードの検出など)を提供します。
105
Kamil Jarosz

列挙型に値がある場合は、次に示すようにIntDef/StringDefを使用する必要があります。

http://tools.Android.com/tech-docs/support-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++での動作とは対照的に、列挙型は実際のクラスであるため、意味があります。

56

以前の回答に加えて、Proguardを使用している場合(サイズを小さくしてコードを難読化するために間違いなく行う必要がある場合)、Enumsは自動的に@IntDefに変換されます可能だ:

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

class/unboxing/enum

可能な場合は常に、列挙型を整数定数に単純化します。

したがって、いくつかの離散値があり、一部の方法でこの値のみを使用し、同じタイプの他の値は使用できない場合は、Enumを使用します。Proguardがこの手動のコード最適化作業を行うためです。

そして こちら Jake Whartonの列挙型の使用に関する良い投稿です。

ライブラリ開発者として、消費するアプリのサイズ、メモリ、パフォーマンスにできるだけ影響を与えたくないため、これらの小さな最適化を行う必要があることを認識しています。しかし、[...]パブリックAPIに列挙型を配置することと、適切な場合には整数値を配置することは完全に適切であることを認識することが重要です。情報に基づいた意思決定を行うための違いを知ることが重要です

11
Gaket

Androidで列挙型の使用を厳密に避けるべきですか?

いいえ。 "Strictly"は、それらが非常に悪いことを意味し、まったく使用すべきではありません。 多くの多く(数千または数百万)の列挙(UIスレッドで連続)のような極端な状況では、パフォーマンスの問題が発生する可能性があります。より一般的なのは、バックグラウンドスレッドでstrictlyが発生するネットワークI/O操作です。列挙型の最も一般的な使用法は、おそらく何らかの種類のチェックです-オブジェクトがthisthatであるかどうかは非常に高速であるため、列挙の単一の比較と整数の比較。

誰かがAndroidで同じものを表現するための最良の方法であるものを明確にしていただけますか?

これに関する一般的な経験則はありません。自分に合ったものをすべて使用し、アプリの準備を支援します。後で最適化-気づいた後、アプリのいくつかの側面を遅くするボトルネックがあります。

11
stan0

Android Pを使用すると、enumを使用する際にgoogleに制限/異議はありません

ドキュメントは、以前は注意を払うことが推奨されていた場所を変更しましたが、現在は言及していません。 https://developer.Android.com/reference/Java/lang/Enum

8
Ali

2つの事実。

1、EnumはJavaの最も強力な機能の1つです。

2、Android電話には通常、大量のメモリがあります。

だから私の答えはNOです。 AndroidでEnumを使用します。

4
Kai Wang

キーまたは値のいずれかが注釈インターフェイスのいずれかである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グループは追加できません。

2
Grisgram