最近我一直在研究java / android中的内存泄漏,几乎无处不在,它说我应该使用带有弱引用的静态内部类而不是匿名类 .
所以,在我的Android应用程序中,我开始这样做,但很快就厌倦了它因为它不确定它是否是防止内存泄漏方面的静态内部类的有效替代品 . 正如我之前所说,我还没有看到其他任何地方建议的解决方案(都说使用静态内部类)所以这就是为什么我不确定我的替代方案是否有效 .
生病使用我的应用程序中的简单示例:
我有一个名为WebClient的类来处理异步Web请求,它接受一个名为iCallback的接口,它将响应从服务器返回给调用者,在我的活动中,一旦我得到这个回调,我需要关闭一个对话框,并可能执行一些活动相关的东西(比如触发onBackPressed()和setResult()) .
所以这是我创建的静态内部类:
private static class CallBack implements WebClient.ICallback
{
private WeakReference<ProgressDialog> mProgDiag;
private WeakReference<BaseActivity> mActivity;
public CallBack(BaseActivity activity, ProgressDialog progDiag)
{
this.mProgDiag = new WeakReference<>(progDiag);
this.mActivity = new WeakReference<>(activity);
}
@Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
final BaseActivity parentActivity = mActivity.get();
ProgressDialog dialog = mProgDiag.get();
if(dialog != null)
{
dialog.dismiss();
}
if (responseAsString == null)
{
if(parentActivity != null)
{
Utils.makeServerErrorDialog(parentActivity,
new iDialogButtonClickedListener()
{
@Override
public void onDialogButtonClicked()
{
parentActivity.onBackPressed();
}
});
}
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
if(parentActivity != null)
{
Intent result = new Intent();
result.putExtra(...);
parentActivity.setResult(Activity.RESULT_OK, result);
}
}
else
{
Utils.reportErrorToServer(...);
if(parentActivity != null)
{
parentActivity.setResult(Activity.RESULT_CANCELED);
}
}
if(parentActivity != null)
{
parentActivity.onBackPressed();
}
}
}
所以对于我需要在这个静态内部类中的每个变量,我必须创建一个新的弱引用,然后检索对象本身,然后每次我想要访问它我需要检查它是否为null ...这似乎很多代码给我 .
这是我建议的替代方案:
public abstract class BaseActivity extends AppCompatActivity
implements WebClient.ICallback
{
private static final String TAG = "BaseActivity";
WebClient.ICallback mCallBack;
ProgressDialog mProgDiag;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
mCallBack = this;
//some code to invoke a server request on button click
//and passing mCallBack to the request
}
@Override
public void onCallback(String data)
{
String responseAsString = Utils.extractStringFromResponse(...);
mProgDiag.dismiss();
if (responseAsString == null)
{
Utils.makeServerErrorDialog(this,
new iDialogButtonClickedListener()
{
@Override
public void onDialogButtonClicked()
{
onBackPressed();
}
});
return;
}
//everything is ok
if (responseAsString.equals("1"))
{
Intent result = new Intent();
result.putExtra(...);
setResult(Activity.RESULT_OK, result);
}
else
{
Utils.reportErrorToServer(...);
setResult(Activity.RESULT_CANCELED);
}
onBackPressed();
}
@Override
protected void onPause()
{
mCallBack = null;
super.onPause();
}
@Override
protected void onResume()
{
super.onResume();
mCallBack = this;
}
}
对我来说,这似乎更清晰:没有为我需要访问的每个变量创建和检索弱引用的实例,我可以直接调用活动方法(例如onBackPressed()),并且不会在任何地方检查null .
在调用callBack方法之前,我现在必须检查null的唯一地方是WebClient类 .
所以我的问题是,这种方法在防止内存泄漏方面是否达到了相同的效果?它是静态内部类的“有 Value ”替代品吗?
1 回答
不幸的是,你的方法不起作用 . 通过在您的活动中实现 WebClient.ICallback 而不是内部类,您无法摆脱泄漏 . 发生泄漏不是因为对活动和对话的引用隐含在匿名类,lambda或非静态内部类实例中;当WebClient在活动消失时保留此引用时会发生这种情况(它不会被破坏,因为它有强烈的引用) .
在活动暂停时设置为null的特殊 mCallBack 不会获得任何结果 . 同样,您只需将活动实例传递给WebClient即可 . 现在有一个强烈的参考,你的活动是由某人(WebClient的异步处理程序)管理的,谁不在你的控制之下 . 如果你运气不好,异步处理程序会卡在某处,永远不会释放这个引用 .
请阅读详细explanation .
请注意 WebView 本身可以cause a memory leak,如果不采取特殊措施!