具有上下文的无内存泄漏单例

Memory-leak free Singleton with context

我正在尝试实现以下单例模式:SingletonClass.getInstance(context).callMethod()

虽然有各种教程解释如何在 Kotlin 中制作单例,但其中 none 解决了在静态字段中保存 context 会导致内存泄漏的事实 Android.

如何在不造成内存泄漏的情况下创建上述模式?

更新:

这是我对 CommonsWare 解决方案 #2 的实现。我用的是公币

单例class:

class  NetworkUtils(val context: Context) {

}

申请Class:

class MyApplication : Application() {

    val appModule = module {
        single { NetworkUtils(androidContext()) }
    }

    override fun onCreate() {
        super.onCreate()
        startKoin(this, listOf(appModule))
    }
}

Activity class:

class MainActivity : AppCompatActivity() {

    val networkUtils : NetworkUtils by inject()

}

选项 #1:让 getInstance(Context) 在提供的 Context 上调用 applicationContext 并保留它。 Application 单例是在您的进程存在时创建的,并且在进程的生命周期内存在。它是预泄漏的;你不能再泄露了。

选项 #2:摆脱 getInstance() 并设置某种形式的依赖注入(Dagger 2、Koin 等)。这些 DI 框架有一些方法可以让它们向它们创建并注入下游的单例提供 Application 单例。

如果您必须创建涉及上下文的单例 class,您可以这样做。这会有所帮助。在这种情况下,当您调用 getInstance(context) 时,您的上下文将在每个 activity 中重置。

public class MyClass {

    private Context context;

    public static getInstance(Context context){
         if(instance ==null)
             instance = new MyClass();
         instance.setContext(context);
         return instance;
    }

   public void setContext(Context context){
      this.context = context;
  }
}

当您第一次调用 getInstance() 时,您传递给此函数的 Context 将永远保存。因此,进一步 getInstance() 调用中的上下文与此无关。我从不保存这个 Context.

这就是我正在做的事情:

在 Kotlin 中创建一个 object 并在应用程序启动后立即使用上下文初始化该对象。我没有存储上下文,而是执行该上下文所需的任何操作。

object PreferenceHelper {

    private var prefs: SharedPreferences? = null

    fun initWith(context: Context){
        if(prefs == null) this.prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE)
    }

    fun someAction(){ .... }
}

Application 里面 class:

class MyApp: Application(){
   override fun onCreate(){
      PreferenceHelper.initWith(this)
   }
 }

以及以后在应用中的任何位置:

 PreferenceHelper.someAction()

如果您不需要在每次使用 Singleton class 执行某些操作时都需要引用 Context,则可以这样做。

我不会将上下文存储在 SingletonClass 中,我只是通过依赖注入将上下文传递给 class 的每个方法。 类似于:

SingletonClass.callMethod(context)

像这样在伴随对象中定义 "static" 方法:

 companion object {
        fun callMethod(context: Context) {
            // do Something
        }
    }

然后从您的 activity 调用它:

SingletonClass.callMethod(this)

希望对您有所帮助:)