在我的一类中,我有以下代码:
mHandler = createHandler();
private Handler createHandler() {
return new Handler() {
public void handleMessage (Message msg) {
update();
if (!paused) {
sendEmptyMessageDelayed(0, 300);
}
}
};
}
Run Code Online (Sandbox Code Playgroud)
文件说:
http://developer.android.com/reference/android/os/Handler.html
每个Handler实例都与一个线程和该线程的消息队列相关联
因此,如果我理解正确,只要应用程序线程正在运行,Handler就不会被垃圾收集,这是正确的吗?
在我的具体示例中,由于Handler是一个匿名内部类,因此它具有对封闭Object的隐式引用以及由其指向的对象的整个层次结构.这看起来像是一个内存泄漏的配方.
顺便说一句,我可以让处理程序停止发送消息(这就是为什么我有if (!paused))但这不会使它成为GCed,对吧?
那么有没有办法从消息队列中删除Handler并使其成为GCed?
Joe*_*eer 14
对Handler源的检查揭示了更多细节.
以下是Romain Guy添加的Handler()构造函数中的一些调试代码:
if (FIND_POTENTIAL_LEAKS) {
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());
}
}
Run Code Online (Sandbox Code Playgroud)
警告很明确:不要将Handler子类声明为内部类.
Handler的looper是从静态ThreadLocal实例获得的:
mLooper = Looper.myLooper();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static final Looper myLooper() {
return (Looper)sThreadLocal.get();
}
Run Code Online (Sandbox Code Playgroud)
泄漏剖析:
主应用程序线程保留Looper及其MessageQueue,队列中的Messages保留到其目标Handler的链接,Handler - 除非它是一个带有WeakReference的静态嵌套类 - 将保留您的Activity及其观点.
您可以通过清理消息来尝试插入此泄漏:
handler.removeMessages(what);
Run Code Online (Sandbox Code Playgroud)
但这说起来容易做起来难.
在我的具体示例中,由于 Handler 是一个匿名内部类,因此它具有对封闭对象及其所指向的整个对象层次结构的隐式引用。
static通过使用嵌套类而不是匿名内部类,您可以将潜在泄漏的影响减少到几乎没有。