返回

匿名内部类内存泄漏问题的排查及解决方案

Android

内存泄漏的原因

在 Java 中,匿名内部类默认会持有外部类的引用。如果外部类是一个 Activity 或者 Fragment,就有可能导致内存泄漏。这是因为 Activity 和 Fragment 在销毁时,并不会自动释放其持有的匿名内部类。

在 Kotlin 中,匿名内部类默认不会持有外部类的引用。这有助于防止内存泄漏,但并不是绝对的。如果匿名内部类引用了外部类的成员变量,就有可能导致内存泄漏。

解决办法

Java

  • 使用静态内部类。
  • 使用局部内部类。
  • 使用 Lambda 表达式。

Kotlin

  • 使用 Lambda 表达式。
  • 使用匿名内部类的 @JvmField 注解。

总结

匿名内部类在 Java 和 Kotlin 中的使用很普遍,但它们也有可能导致内存泄漏。通过使用静态内部类、局部内部类、Lambda 表达式或者 @JvmField 注解,可以避免匿名内部类导致的内存泄漏。

示例

Java

// 静态内部类
public static class StaticInnerClass {
    private Context context;

    public StaticInnerClass(Context context) {
        this.context = context;
    }

    public void doSomething() {
        // 使用 context
    }
}

// 局部内部类
public void doSomething() {
    class LocalInnerClass {
        private Context context;

        public LocalInnerClass(Context context) {
            this.context = context;
        }

        public void doSomething() {
            // 使用 context
        }
    }

    LocalInnerClass innerClass = new LocalInnerClass(this);
    innerClass.doSomething();
}

// Lambda 表达式
public void doSomething() {
    Runnable runnable = () -> {
        // 使用 context
    };
    runnable.run();
}

Kotlin

// 匿名内部类
fun doSomething(context: Context) {
    object : View.OnClickListener {
        override fun onClick(v: View) {
            // 使用 context
        }
    }
}

// Lambda 表达式
fun doSomething(context: Context) {
    val runnable = {
        // 使用 context
    }
    runnable()
}

// 匿名内部类的 `@JvmField` 注解
class MyClass {
    @JvmField
    private val listener = object : View.OnClickListener {
        override fun onClick(v: View) {
            // 使用 context
        }
    }
}

进一步阅读