Activity has leaked window … that was originally added

Activity has leaked window … that was originally added,好像这个问题很普遍,一般不会导致程序运行终止,但是后台报一堆错总是不爽的,网上搜了一下,很多是在横竖屏切换时报出来的,这种情况下比较好解决,在Mainifest.xml中的对应<Activity>节点加上android:configChanges="orientation|keyboardHidden|navigation"就可以解决。

但我碰到的不是这种情形,还是《ListView滚动时右侧快速滑块的启用方法》中描述的那样,我要在ListView滚动时出现通讯录类似的出现字母提示,跟踪错误,问题出在了这个动态产生的提示框(TextView)上,创建这个TextView的代码是这样的:

//滚动时弹出的提示框
txtOverlay = (TextView) LayoutInflater.from(this).inflate(R.layout.pop_overlay, null);
// 默认设置为不可见。  
txtOverlay.setVisibility(View.INVISIBLE);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT,
		LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION,
		WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
		PixelFormat.TRANSLUCENT);
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(txtOverlay, lp);

当我退出应用就会在后台报出Activity has leaked window … that was originally added的异常。Google了很久,最终在stackoverflow.com上找到了答案,出现这种问题真正原因是:View拥有它所在的Context的引用(通过构造函数的参数获得),当退出Activity没有关闭动态创建的View(如Dialog),它会一直拥有Context的引用,从而不能被GC回收,从而导致内存泄露。知道原因就好办了,我们在Activity中的OnDestroy()方法中释放资源就OK了,以下是我这种情况下的解决办法,其它控件也类似。

/**
 * 动态创建的View要在onDestroy()方法中删除掉,
 * 避免后台报错:
 * Activity  has leaked window android.widget.TextView that was originally added here
 */
@Override
protected void onDestroy() {
	windowManager.removeView(txtOverlay);
	super.onDestroy();
}

再附上老外的原话,感觉英文描述得更确切:

Views have a reference to their parent Context (taken from constructor argument). If you leave an Activity without destroying Dialogs and other dynamically created Views, they still hold this reference to your Activity (if you created with this as Context: like new ProgressDialog(this)), so it cannot be collected by the GC, causing a memory leak.


你可能感兴趣的:(ListView,service,application,dialog,reference,Constructor)