Message
はい、このサンプルがキューに保持されている場合、リークが発生します。ただし、通常はかなり短い時間に制限されるため、それほど深刻なリークではありません。
しかし、リークを防ぐかなり簡単な方法があります。
次の 2 つのクラスをプロジェクトに追加します。
/** Callback that decouples the wrapped Callback via WeakReference */
public class SafeCallback implements Handler.Callback {
private final WeakReference<Handler.Callback> mCallback;
public SafeCallback(Handler.Callback callback) {
mCallback = new WeakReference<Handler.Callback>(callback);
}
@Override
public boolean handleMessage(Message msg) {
Handler.Callback callback = mCallback.get();
if (callback != null)
return callback.handleMessage(msg);
// else warn, return true, ..?
return false;
}
}
/** replacement for anonymous inner Handler implementations */
public abstract class SafeHandler implements Handler.Callback {
@Override
public abstract boolean handleMessage(Message msg);
public final Handler get() {
return new Handler(new SafeCallback(this));
}
public final Handler get(Looper looper) {
return new Handler(looper, new SafeCallback(this));
}
}
Handler
これで/はほとんど以前と同じように使用できますCallback
が、リークはなくなりました。
だからどちらかのように
public class TestActivity extends Activity {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new SafeHandler() { // << instead of new Handler() {
@Override
public boolean handleMessage(Message msg) {
// handle message
return false;
}
}.get(); // << Notice this added .get()
}
}
または好き
public class TestActivity2 extends Activity implements Handler.Callback {
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mHandler = new Handler(new SafeCallback(this)); // << wrapped in SafeCallback
}
@Override
public boolean handleMessage(Message msg) {
// handle message
return false;
}
}
のリークの問題Handler
は、各Message
/ Runnable
(実際には a でラップされているMessage
) がターゲットであることを認識していることです。つまり、Handler
orへのハード参照がありCallback
ます。また、そのターゲットが非静的内部クラスである場合、外部クラスへの暗黙的なハード参照があり、通常はActivity
.
つまり、 がMessages
キューに入れられている限りHandler
、全体Activity
をガベージ コレクションすることはできません。
この問題を解決するには、 からMessage
へのハード参照のチェーンをActivity
切断する必要があります。SafeCallback
クラスは、あなたWeakReference
のActivity
.
つまり、 はMessage
ハード参照になりましSafeCallback
たが、そこにバインドされている部分はガベージ コレクションできるようになりました。それが起こった場合、結果Handler.Callback callback = mCallback.get();
は単純に破棄されます。とにかく、これ以上有用なターゲットはありません。それ自体はまだリークしていますが、それはほとんど空のクラスであるため、問題は発生しません。null
Message
SafeCallback