【问题标题】:Is Calling new Runnable() inside Static method safe from Memory Leak?在静态方法中调用 new Runnable() 是否可以避免内存泄漏?
【发布时间】:2023-04-04 13:26:01
【问题描述】:

在我的 Activity 中,我希望在 Activity 加载 1 秒后出现一个浮动操作按钮。

为此,我创建了一个像这样的新静态方法。

public class utility {

public static void delayedShowFab(final FloatingActionButton fab)
    {
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                fab.show();
            }
        }, 1000);
    }
}

我这样调用方法:

@Override    
protected void onCreate(Bundle savedInstanceState) {
    final FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
    utility.delayedShowFab(fab);
}

我的代码对内存泄漏安全吗?新的 Runnable 和新的 Handler 对象会在 1 秒后自动销毁吗?

【问题讨论】:

  • 我已经放弃了这样的设计,它们似乎对我来说永远无法正常工作。未知的崩溃一秒钟变成了五秒钟,因为其他一些进程正在占用 CPU。今天,我将完成构建 UI 的最后一步,让按钮可见,然后继续制作出色的应用程序。

标签: android multithreading memory-leaks


【解决方案1】:

是的,不是的。在正常操作中,引用将被清除,内存将被释放。从技术上讲,如果 Activity 在经过一秒钟之前被杀死,则会发生内存泄漏。 FloatingActionButton 仍然持有对其父 Context 的引用。因此,Activity 将保留在内存中,直到 Handler 处理消息,在这种情况下,fab 将显示,但由于 Activity 不再在视图中,因此什么都不会发生。

这不会对性能产生非常显着的影响,因为它只有一秒钟。那一秒钟只有一些小开销,但没什么大不了的。 真正的问题是,如果您将该时间延长 1 分钟。

public class utility {

public static void delayedShowFab(final FloatingActionButton fab)
    {
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                fab.show();
            }
        }, 1000 * 60);
    }
}

现在,假设用户刚刚决定在那一分钟内将手机旋转一百次(也许他正在慢跑并且屏幕处于开启状态。谁知道呢?)。

每次屏幕旋转时,都会创建一个带有新 FAB 的新 Activity。您立即发布到主线程以等待一分钟。在运行此消息之前,创建的每个 Activity 都将存在。这意味着该 Activity 中包含的所有资源也将在该持续时间内存在。

要解决这个问题,有几个选项。

选项 1:取消操作。

保持 API 完整。您可以返回取消操作的方法。类似这样:

public class utility {

public interface Cancelable {
    void cancel();
}

public static void delayedShowFab(final FloatingActionButton fab) {
        final Handler handler = new Handler();
        final Runnable runnable = new Runnable(){
            @Override
            public void run() {
                fab.show();
            }
        };

        handler.postDelayed(runnable, 1000);

        return new Cancelable() {
           public void cancel() {
              handler.removeCallbacks(runnable);
           }
        }
    }
}

然后,在 Activity 的 onDestroy 方法中,只需在返回的对象上调用 cancel

选项 2:使用弱引用

WeakReferences 用于保存对对象的引用,而不包括在引用计数中。这样,当对该对象的所有引用都消失时,它就会消失。

所以在本例中,您将持有对 FloatingActionButon 的 WeakReference 如果它仍然存在,则只调用show

public class utility {

public static void delayedShowFab(final FloatingActionButton fab)
    {
        final WeakReference<FloatingActionButton> ref = new WeakReference<>(fab);
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                FloatingActionButton fab = ref.get();
                // You always have to check because it may disappear.
                if(fab != null) { 
                  fab.show();
                }
            }
        }, 1000 * 60);
    }
}

在此解决方案中,RunnableWeakReference 将在消息期间保留在内存中,但开销明显小于完整的 Activity。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-16
    • 2011-01-15
    • 2015-09-01
    • 1970-01-01
    • 2011-02-28
    相关资源
    最近更新 更多