handlerがactivityのメンバー変数によるメモリ漏洩
10663 ワード
handlerがactivityのメンバー変数によるメモリ漏洩
分類:android関連
2013-07-09 18:55
622人が読む
コメント(0)
コレクション
通報する
まず簡単なコードのセットを見てみましょう1
2
3
4
5
6
7
8
9
public class SampleActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
}
}
Activity
にこのように書くと、Android Lint
はwarning:In Android, Handler classes should be static or leaks might occur.
を提示します.意味: Android ,Handler 。
どうしてそうなの?Handler
について
1
2
3
4
5
6
7
8
9
public class SampleActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
}
}
Looper
オブジェクトが同時に作成されます.Looper
は、Message
オブジェクトの処理に続く簡単なメッセージキューを実現する.プログラムフレームワークのすべての主要なイベント(例えば、画面上のクリック時間、Activity
ライフサイクルの方法など)は、Message
オブジェクトに含まれ、Looper
のメッセージキューに追加され、1つの処理が行われる.プライマリ・スレッドのLooper
は、アプリケーション全体のライフサイクル内に存在します.Handler
オブジェクトが作成されると、Looper
のmessage queueに関連付けられます.Message
がメッセージキューに追加するとMessage
は現在のHandler
参照を保持し、Looper
が現在のメッセージに処理するとHandler#handleMessage(Message)
が呼び出される.java
では、no-static
の内部クラスは、現在のクラスの参照を暗黙的に保持します.static
のクラスはありません.メモリの漏洩はどこで起きたのでしょうか.次のコードを見てみましょう
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class SampleActivity extends Activity {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 10
mHandler.postDelayed(new Runnable() {
@Override
public void run() { }
}, 600000);
// Activity
finish();
}
}
Activity
が終了すると、Message queueがこのMessage
を処理する前に、それは生存し続ける.このMessage
はHandler
の参照を持っているが、Handler
はActivity
(SampleActivity)の参照を持っている.このActivity
のすべてのリソースは、このメッセージ処理の前に回収されず、メモリ漏洩が発生している.解決策は、次のコードを見てください.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class SampleActivity extends Activity {
/**
* ,
*/
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
private final MyHandler mHandler = new MyHandler(this);
/**
* ,
*/
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 10
mHandler.postDelayed(sRunnable, 600000);
//
finish();
}
}
OK、終了
NOTE:弱い引用の
Activity
が回収されるのではないかと心配する人が多いですが、これは全く心配しないでください.私たちがこのインタフェースにいるとき、このActivity
は回収されませんから.もし私たちのこのActivityが回収されたら、私たちのこのインタフェースはどのように存在しますか.NOTE 2:皆さん、私は
AsyncTask
を参照して、ドキュメントと自分の理解を見て、私が説明できないところがあります.NOTE 3:具体的にどのように漏洩を防止するか私もはっきり言えませんが、
Handler
の下にソースコードがあります.1
2
3
4
5
6
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}