Android 在静态方法中调用new Runnable()是否可以防止内存泄漏?

Android 在静态方法中调用new Runnable()是否可以防止内存泄漏?,android,multithreading,memory-leaks,Android,Multithreading,Memory Leaks,在我的“活动”中,我希望在加载“活动”后1秒出现一个浮动操作按钮 为此,我创建了一个新的静态方法,如下所示 public class utility { public static void delayedShowFab(final FloatingActionButton fab) { new Handler().postDelayed(new Runnable(){ @Override public void run(

在我的“活动”中,我希望在加载“活动”后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秒后自动销毁吗?

是和否。在正常操作中,引用将被清除,内存将被释放。从技术上讲,如果活动在1秒之前被终止,则存在内存泄漏。
FloatingActionButton
仍然保存对其父
上下文的引用。因此,
活动
将保留在内存中,直到处理程序处理消息为止,在这种情况下,fab将显示,但由于该活动已不在视图中,因此不会出现任何可见的情况

这不会对性能产生太大的影响,因为它只有一秒钟。这一秒钟的开销很小,但没有什么意义。真正的问题是,如果你把时间延长一分钟

public class utility {

public static void delayedShowFab(final FloatingActionButton fab)
    {
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                fab.show();
            }
        }, 1000 * 60);
    }
}
现在,假设用户刚刚决定在那一分钟内将手机旋转一百次(可能他正在慢跑,屏幕打开了,谁知道呢?)

每次屏幕旋转时,都会使用新的晶圆厂创建一个新的活动。您立即发布到主线程以等待另一分钟。在运行此消息之前,创建的每个活动都将存在。这意味着该活动中包含的所有资源也将在此期间存在

要解决这个问题,有几个选择

选项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);
           }
        }
    }
}
然后,在活动的
ondestory
方法中,只需对返回的对象调用
cancel

选项2:使用弱引用

用于保留对对象的引用,而不将其包含在引用计数中。这样,当对该对象的所有引用都消失时,它将消失

因此,在本例中,您将持有对FloatingActionButon的弱引用 并且只有当它仍然存在时才调用
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);
    }
}
公共类实用程序{
公共静态无效延迟显示fab(最终浮动操作按钮fab)
{
最终WeakReference ref=新WeakReference(fab);
new Handler().postDelayed(new Runnable()){
@凌驾
公开募捐{
FloatingActionButton fab=ref.get();
//你总是要检查,因为它可能会消失。
如果(fab!=null){
fab.show();
}
}
}, 1000 * 60);
}
}

在此解决方案中,
Runnable
WeakReference
将在消息持续期间保留在内存中,但开销明显小于完整活动

是和否。在正常操作中,将清除引用并释放内存。从技术上讲,如果活动在1秒之前被终止,则存在内存泄漏。
FloatingActionButton
仍然保存对其父
上下文的引用。因此,
活动
将保留在内存中,直到处理程序处理消息为止,在这种情况下,fab将显示,但由于该活动已不在视图中,因此不会出现任何可见的情况

这不会对性能产生太大的影响,因为它只有一秒钟。这一秒钟的开销很小,但没有什么意义。真正的问题是,如果你把时间延长一分钟

public class utility {

public static void delayedShowFab(final FloatingActionButton fab)
    {
        new Handler().postDelayed(new Runnable(){
            @Override
            public void run() {
                fab.show();
            }
        }, 1000 * 60);
    }
}
现在,假设用户刚刚决定在那一分钟内将手机旋转一百次(可能他正在慢跑,屏幕打开了,谁知道呢?)

每次屏幕旋转时,都会使用新的晶圆厂创建一个新的活动。您立即发布到主线程以等待另一分钟。在运行此消息之前,创建的每个活动都将存在。这意味着该活动中包含的所有资源也将在此期间存在

要解决这个问题,有几个选择

选项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);
           }
        }
    }
}
然后,在活动的
ondestory
方法中,只需对返回的对象调用
cancel

选项2:使用弱引用

用于保留对对象的引用,而不将其包含在引用计数中。这样,当对该对象的所有引用都消失时,它将消失

因此,在本例中,您将持有对FloatingActionButon的弱引用 并且只有当它仍然存在时才调用
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);
    }
}
公共类实用程序{
公共静态无效延迟显示fab(最终浮动操作按钮fab)
{
最终WeakReference ref=新WeakReference(fab);
new Handler().postDelayed(new Runnable()){
@凌驾
公开募捐{
FloatingActionButton fab=ref.get();
//你总是要检查,因为它可能会消失。
如果(fab!=null){
fab.show();
}
}
}, 1000 * 60);
}
}

在此解决方案中,
Runnable
WeakReference
将在消息持续期间保留在内存中,但开销明显小于完整活动

我已经放弃了这样的设计——它们似乎从来都不适合我。未知崩溃由于其他进程占用CPU,一秒变成五秒。今天,我要做的只是构建UI的最后一步,使按钮可见,并继续制作一个伟大的应用程序。我已经放弃了设计