可能替代静态内部类以防止android/java中的内存泄漏?

or_*_*vir 6 java android memory-leaks inner-classes

最近我一直在研究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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

所以对于我需要在这个静态内部类中的每个变量,我必须创建一个新的弱引用,然后检索对象本身,然后每次我想要访问它我需要检查它是否为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

对我来说这看起来更清晰:没有为我需要访问的每个变量创建和检索弱引用的实例,我可以直接调用活动方法(例如onBackPressed()),并且不会在任何地方检查null.
在调用callBack方法之前,我现在必须检查null的唯一地方是WebClient类.

所以我的问题是,这种方法在防止内存泄漏方面是否达到了相同的效果?它是静态内部类的"有价值"替代品吗?

Ale*_*ohn 3

不幸的是,你的方法不起作用。通过在您的活动中实现WebClient.ICallback而不是内部类,您并不能消除泄漏。发生泄漏并不是因为对活动和对话框的引用隐式存在于匿名类、lambda 或非静态内部类实例中;而是因为对活动和对话框的引用隐含在匿名类、lambda 或非静态内部类实例中。当 WebClient 在活动消失时保留此引用(它不会被销毁,因为有对它的强引用)时,就会发生这种情况。

当活动暂停时,您设置为 null 的特殊mCallBack不会获得任何结果。同样,您可以简单地将活动实例传递给 WebClient。现在有对您的活动的强引用,该活动由不受您控制的某人(WebClient 的异步处理程序)管理。如果不幸的话,异步处理程序将卡在某个地方并且永远不会释放此引用。

请阅读此详细说明

请注意,如果不采取特殊措施,WebView本身可能会导致内存泄漏!