使用没有任何静态引用的上下文

时间:2016-12-31 21:57:40

标签: android design-patterns memory-leaks singleton

我正在尝试从Singleton类访问应用程序资源(字符串资源是特定的)。作为Singleton,这个类不能保存对Context对象的任何引用(以防止内存泄漏)。当我在网上寻找其他实现时,我遇到了这两个实现:

  1. 在Application类中创建一个静态上下文,并在整个应用程序中使用它。
  2. 将上下文作为参数传递给需要它的方法。
  3. 我不想使用第一个,因为它也使用对Context对象的静态引用。我知道在Android的Application类中静态地使用它是可以的,但它仍然看起来像是黑客。

    第二个实现是没用的,因为我没有任何上下文实例,我可以传递给单例的someOtherMethod。

    所以当我初始化单例实例时,我想出了以下实现,其中我使用我的Singleton抽象来覆盖其上下文需要方法(对于前面的代码中的例如getString(int resId))。

    我很想知道这是否会导致任何内存泄漏?

    我在哪里与这种方法混淆:

    - >重写getString中对上下文的引用是最终的。我不确定这是否会导致内存泄漏。

        public abstract class SingletonClass{
    
        .
        .
        .
    
        private static SingletonClass sInstance;
    
        private SingletonClass(Context paramContext) {
            // constructor code
        }
    
        public static SingletonClass getInstance(final Context context) {
            if (sInstance == null) {
                sInstance = new SingletonClass(context){
                    @Override
                    public String getString(int resId) {
                        return context.getString(resId);
                    }
                };
            }
            return sInstance;
        }
    
        public abstract String getString(int resId);
    
        .
        .
        .
    
        private void someOtherMethod(){
            //uses above getString()
        }
    
        }
    

2 个答案:

答案 0 :(得分:0)

您的方法确实存在内存泄漏。传递给getInstance的第一个上下文永远不会被垃圾收集,因为您的匿名类包含对它的引用。 (并且有一个匿名类的静态引用)。例如,如果你打电话给getInstance(Activity),该活动将保留在内存中,直到该进程被终止!

幸运的是,有一个非常简单的解决办法来摆脱内存泄漏。您可以安全地保留应用程序上下文(context.getApplicationContext),这基本上是应用程序生命周期的单例上下文。

public static SingletonClass getInstance(Context c) {
    if (sInstance == null) {
        sInstance = new SingletonClass(c.getApplicationContext());
    }
    return sInstance;
}

答案 1 :(得分:0)

您可以依赖于活动生命周期,并要求活动在onResume方法中传递对单个对象的引用,并在onPause中清除它。

protected void onResume() {
  super.onResume();
  Singleton.getInstance().onResume(this);
}

protected void onPause() {
  super.onResume();
  Singleton.getInstance().onPause();
}

此外,您可以刷新Context的实例并将其保存在WeakReference中:

class Singleton {
  private WeakReference<Context> mContext;

  private boolean hasContext() {
    return mContext != null && mContext.get() != null;
  }

  public static Singleton getInstance(Context c) {
     //do your singleton lazy
     if (!sInstance.hasInstance()) {
       sInstance.mContext = new WeakReference<>(c);
     }
     return sInstance;
  }
}

第二种情况可以引用完成活动,所以我不建议。