【问题标题】:When does passing an activity to another class cause memory leaks?何时将活动传递给另一个类会导致内存泄漏?
【发布时间】:2020-03-27 00:32:01
【问题描述】:

在我的 Android Studio 项目中,我有一个活动 (MainActivity) 和一个对象 (PurchasesHandler)。在活动的onCreate 方法中,PurchaseHandler 被实例化如下:

PurchasesHandler purchasesHandler = new PurchasesHandler(MainActivity.this, ...)

通过阅读大量有关内存泄漏的文章,我知道在传递活动时应该非常小心,因为这会导致内存泄漏。不过我猜通过activity不一定会导致内存泄漏吧?

所以让我们更进一步,看看PurchasesHandler。该处理程序包含一个简单的 AlertDialog 构建器,如下所示:

private void showBillingResponseDialog(String title, String message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                })
                .show();
    }

如您所见,我在此方法中引用了活动,但我想这也不会导致内存泄漏,对吧?如果是这样,有人可以解释为什么吗?我觉得它是这样的很直观,但我无法解释为什么会这样。

那么让我们再看一个来自PurchasesHandler的代码sn-p:

public void sampleMethod() {
        BillingClient billingClient = BillingClient.newBuilder(context)
                .enablePendingPurchases()
                .setListener(this) // Passes the onPurchasesUpdated listener of this class
                .build();

在这段代码 sn-p 中,我设置了一个引用 PurchasesHandler 本身的侦听器(因为 .setListener(this))。我现在的猜测是,存在内存泄漏,因为侦听器持有对PurchasesHandler 的引用,而PurchasesHandler 持有对活动的引用。这意味着不能从堆中释放/删除活动,对吗?

如果我的假设是正确的,有没有什么好的方法可以消除内存泄漏?我知道我应该注销监听器,但是对于BillingClient,不存在注销选项。只有一个endConnection() 方法,但是这种方法有时不能正常工作。

【问题讨论】:

    标签: java android android-studio memory-leaks


    【解决方案1】:

    假设您在 SomeActivity 中实现了 PurchaseHandler,然后在活动的 onStop 或 OnDestroy 中分配 PurchaseHandlerObject = null

    其他方法是使用 Wea​​kReference https://medium.com/google-developer-experts/finally-understanding-how-references-work-in-android-and-java-26a0d9c92f83

    【讨论】:

    • 如果我将 PurchasesHandlerObject 设置为 null,我仍然可以在分析器中看到新实例。
    • 您能分享一下您是如何实现的代码吗?您是否在 onStop 或 onDestroy 中将实例标记为空?
    • 在我设置的活动的 onPause purchasesHandler = null;
    • 坦率地说很酷我没有在 Profiler 中检查这个东西,因为你在 onPause 中将实例标记为 null 只需在 onStop 中验证 if (purchaseHandler == null) --> 如果它为 null 那么如果您仍然看到它不为空,则不应该有任何内存泄漏,那么我需要检查代码:P
    • 它实际上为空,但分析器向我显示了我创建的每个 purchaseHandler 的其他实例。因此,如果我在 onResume 中创建一个 PurchasesHandler 并在 onPause 中将其设置为 null,那么就会添加一个实例。但是,如果我首先确定 PurchasesHandler 中的 BillingClient 断开连接或为空,那么无论我多久恢复一次活动,我都只有一个 PurchasesHandler 实例。当 PurchasesHandler 无效时,似乎 BillingClient 的后台进程没有被取消。
    【解决方案2】:

    如果任何保持对活动的引用的代码可能会导致内存泄漏,那么您是正确的。这就是为什么建议在活动停止时释放引用。如果您的库不提供删除侦听器功能,则将侦听器对象设置为 null 将释放活动的所有引用。还要注意警报对话框

    【讨论】:

      猜你喜欢
      • 2019-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-06
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多