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) がターゲットであることを認識していることです。つまり、Handlerorへのハード参照がありCallbackます。また、そのターゲットが非静的内部クラスである場合、外部クラスへの暗黙的なハード参照があり、通常はActivity.
つまり、 がMessagesキューに入れられている限りHandler、全体Activityをガベージ コレクションすることはできません。
この問題を解決するには、 からMessageへのハード参照のチェーンをActivity切断する必要があります。SafeCallbackクラスは、あなたWeakReferenceのActivity.
つまり、 はMessageハード参照になりましSafeCallbackたが、そこにバインドされている部分はガベージ コレクションできるようになりました。それが起こった場合、結果Handler.Callback callback = mCallback.get();は単純に破棄されます。とにかく、これ以上有用なターゲットはありません。それ自体はまだリークしていますが、それはほとんど空のクラスであるため、問題は発生しません。nullMessageSafeCallback