在静态方法中调用 new Runnable() 是不是可以避免内存泄漏?
Posted
技术标签:
【中文标题】在静态方法中调用 new Runnable() 是不是可以避免内存泄漏?【英文标题】:Is Calling new Runnable() inside Static method safe from Memory Leak?在静态方法中调用 new Runnable() 是否可以避免内存泄漏? 【发布时间】:2017-07-28 05:42:24 【问题描述】:在我的 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 的最后一步,让按钮可见,然后继续制作出色的应用程序。 【参考方案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);
在此解决方案中,Runnable
和 WeakReference
将在消息期间保留在内存中,但开销明显小于完整的 Activity。
【讨论】:
以上是关于在静态方法中调用 new Runnable() 是不是可以避免内存泄漏?的主要内容,如果未能解决你的问题,请参考以下文章