2
new Handler().postDelayed(new Runnable(){

@Override
public void run() {
     // do stuff
}}, 100);

これをアクティビティ (onCreate または onResume など) から呼び出すと、メモリ リークが発生する可能性がありますか? new Runnable()は実際には静的インスタンスであるべきだと読みましたが、本当ですか?

4

2 に答える 2

6

はい。このコードにより、メモリ リークが発生する可能性があります。

に基づくこの匿名クラスRunnableがキューにある限り (この例では 100 ミリ秒)、外部Activityクラスへの参照を保持します。

もちろん、このようなメモリ リーク自体は問題ではありませんが、内部runで実行されるコードによっては、たとえば が強制終了された後にダイアログを表示しようとすると、アプリケーションがクラッシュするなど、より大きな問題が発生する可能性がありますActivity。このような状況では、適切な情報例外が表示されます。

IllegalArgumentException: onSaveInstanceState の後にこのアクションを実行できません

また

BadTokenException: ウィンドウを追加できません - ... アクティビティは実行中ですか?

于 2013-07-21T23:57:32.920 に答える
3

はい、これは漏れです。ハンドラーの動作方法により、ハンドラーが非常に長期間存続し、参照するリソースがガベージ コレクションされるのを防ぐことができます。ここに良い説明があります:http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

ランナブルがオブジェクトの存続期間を超える可能性がある場合は、代わりにこちらの回答のアプローチを試してください: https://stackoverflow.com/a/27825703/579234

あなたがしていることは、非静的ハンドラー クラスに関する既存の Lint 警告をトリガーする通常のケースの上に別のレベルのオブジェクトを追加することで、Lint 警告がトリガーされます: Android lint のチェック:

ハンドラーリーク
-----------
概要: Handler クラスが への参照を保持しないようにします。
外側のクラス

優先度: 4 / 10
重大度: 警告
カテゴリ: パフォーマンス

Android では、Handler クラスを静的にする必要があります。そうしないと、リークが発生する可能性があります。メッセージ
アプリケーション スレッドの MessageQueue にエンキューされたものも、そのターゲットを保持します
ハンドラ。ハンドラーが内部クラスの場合、その外部クラスはそのまま保持されます。
良い。外部クラスのリークを避けるために、Handler を static ネストされたものとして宣言します。
外部クラスへの WeakReference を持つクラス。

匿名クラスの使用は、http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.9.5に記載されているものと同じです:

匿名クラスは常に内部クラスです (§8.1.3)。決して静的ではありません (§8.1.1、§8.5.1)。

したがって、明示的に説明すると、ランナブルは「this」への参照を保持し、ハンドラーはランナブルへの参照を保持するため、ハンドラーが停止するまで「this」はガベージコレクションされません。

于 2015-01-07T17:38:59.387 に答える