2012-04-11 12 views
7

内部クラスは、囲んでいるクラスへの参照を保持しているため、Androidでは推奨されません。しかし、Javaでは、外部クラスは、内部クラスがもはや参照されていないときにのみGCedされます。つまり、Androidでは、外部アクティビティクラスの内部クラスへの非静的参照がある場合、内部クラスは外部アクティビティクラスよりも長く存在することはできません。これは、参照が保持されていない場合にのみアクティビティを破棄できるためです(少なくともそれが私が推測しているものです)。だから、静的でない内部クラスを使用している問題は何ですか(Javaから推論した場合、外側のアクティビティよりも明らかに存在しないため)何か不足していますか?内部クラス:AndroidとJavaの比較

ありがとうございます!

+1

あなたは非静的内部クラスはアンドロイドで推奨されていない読みましたか? – Cristian

+0

これはアンドロイドの問題ではありません。交換可能で高速なコードの場合は、静的なコード以外は避けて、必要な情報をローカルフィールドとして保存してください。内部クラスの問題は、GC'edを取得するために親クラスへの参照を 'null'に設定できないことです。コンパイラは、内部クラスのアクセスがプライベートで親クラスのインスタンスごとに1つの内部クラスがある場合、アクセスメソッドを生成する必要があります。 – Stephan

+0

@Cristianはこのリンクの一番下までスクロールします。http://developer.android.com/resources/articles/avoiding-memory-leaks.html 内部クラスのライフサイクルを制御できない場合は避けてください。ありがとうございます。 – OckhamsRazor

答えて

8

は、あなたが簡単にあなたの活動のコンテキスト外、内非静的クラスを渡すことができます

class Leaker 
{ 
    public static Object leakedObj; 
} 

class MyActivity extends Activity 
{ 
    public class MyInnerClass { ... } 

    void onCreate(Bundle savedState) 
    { 
     Leaker.leakedObj = new MyInnerClass(); 
     //The activity now won't be GCed until Leaker.leakedObj is cleared.   
    } 
} 

この単純な例を考えてみましょう。アクティビティのライフサイクル外のオブジェクトに内部クラスを渡さない限り、大丈夫です。しかし、それは確かに内部クラスを介してあなたの活動をリークすることは可能です。

+0

あなたの答えは有望なようです。静的でない内部クラスは、外部アクティビティのみの参照を除き、内部クラスへの他の参照がない場合、アクティビティより長く存続することがありますか? – OckhamsRazor

+0

+1アクティビティの非静的内部クラスの主な問題点を指摘するための+1:必要なときにアクティビティをGCすることができません。そのため、他のどこかの生きている(アクティビティライフサイクル以外の)オブジェクトが内部クラスのインスタンスへの参照。この内部クラスは、合成参照によってActivityにハングアップします。 –

+0

@OckhamsRazorあなたの内部クラスへの唯一の参照がアクティビティからのものである場合(それらはすべて非静的です)、アクティビティは通常通り収集されます。 –

6

私はそれをよりよく説明できるため、言い換えを気にしません。親クラスはFooで、内部クラスはFoo$Innerです::と仮定すると、

問題は、VMがfooとFooの$インナー異なるクラスであるため、違法であることをFooの$インナーからはFooのプライベートメンバーへの直接アクセスを考慮していることです、 Java言語が内部クラスが外部クラスのプライベートメンバーにアクセスすることを許可しています。ギャップを埋めるために、コンパイラは、合成方法のカップルを生成する:それはmValueフィールドにアクセスしたり、外側のクラスのdoStuffメソッドを呼び出す必要があるときはいつでも

/*package*/ static int Foo.access$100(Foo foo) { 
    return foo.mValue; 
} 
/*package*/ static void Foo.access$200(Foo foo, int value) { 
    foo.doStuff(value); 
} 

内部クラスコードは、これらの静的メソッドを呼び出します。つまり、上記のコードは、アクセサメソッドを使用してメンバーフィールドにアクセスしている場合です。先ほどアクセサーが直接フィールドアクセスよりも遅い方法について説明しました。これは特定の言語イディオムの例であり、「目に見えない」パフォーマンスヒットをもたらします。

パフォーマンスのホットスポットでこのようなコードを使用している場合は、プライベートアクセスではなく、パッケージにアクセスするために内部クラスによってアクセスされるフィールドとメソッドを宣言することでオーバーヘッドを回避できます。残念なことに、これは、同じパッケージ内の他のクラスからフィールドに直接アクセスできるため、これをパブリックAPIで使用しないでください。

出典:https://developer.android.com/training/articles/perf-tips.html#PackageInner

+0

ありがとう、これはクールなものです。静的でない外部アクティビティの参照を除いて、内部クラスへの他の参照がない場合、非静的内部クラスはアクティビティよりも長く存続することができますか? – OckhamsRazor

+0

@OckhamsRazor「外部アクティビティの[非静的]参照を除いて、内部クラスの[インスタンスの]インスタンスへの他の参照がない場合、非静的内部クラスがアクティビティよりも長く存続できますか?答えはいいえだ。 –

+0

ああ、クール、感謝のマイク、あなたはそれをより良い表現。私が知りたいと思っていたものもそうです。乾杯! – OckhamsRazor