【发布时间】:2017-05-04 09:36:17
【问题描述】:
最近我一直在研究 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();
}
}
}
所以对于我在这个静态内部类中需要的每个变量,我必须创建一个新的弱引用,然后检索对象本身,然后每次我想访问它时我都需要检查它是否为空......看起来对我来说就像很多代码。
这是我建议的替代方案:
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。
我现在唯一需要检查 null 的地方是在调用 callBack 方法之前的 WebClient 类中。
所以我的问题是,这种方法在防止内存泄漏方面是否达到了相同的结果?它是静态内部类的“有价值”替代品吗?
【问题讨论】:
-
好问题,我也想知道我是否真的需要每个变量的 WeakReference 并每次都检查 null
-
好吧,您的解决方案中仍然需要一些
null检查。但我认为您的主要问题是您在需要时检查这些值。只需检查一次(在您的示例中为parentActivity)。 -
Java 中没有“静态内部类”这样的东西,因为“内部类”的 Java 定义是一个非静态的嵌套类。
-
匿名类绝对没有错。它们非常有用。使用弱引用使每个嵌套类都成为静态是一种奇怪的迷信。这种一揽子规则没有工程基础。正如您所发现的那样,它会导致过度设计的废话并远离问题域。放弃别人给你的坏建议(“几乎无处不在”?我认为不是!)并回到明智的编程实践。
-
在这种情况下
sensible programming practices是什么?
标签: java android memory-leaks inner-classes