Android 使用上下文而不使用任何静态引用

Android 使用上下文而不使用任何静态引用,android,design-patterns,memory-leaks,singleton,Android,Design Patterns,Memory Leaks,Singleton,我试图从单例类访问应用程序资源(具体来说是字符串资源)。由于是单例的,这个类不能保存对上下文对象的任何引用(以防止内存泄漏)。当我在网上寻找其他实现时,我遇到了以下两种实现: 在应用程序类中创建静态上下文,并在整个应用程序中使用它 将上下文作为参数传递给需要它的方法 我不想使用First,因为它还使用对上下文对象的静态引用。我知道在android的应用程序类中静态地使用它是可以的,但它看起来仍然像一个黑客 第二个实现是无用的,因为我没有任何上下文实例可以传递给singleton的SomeOthe

我试图从单例类访问应用程序资源(具体来说是字符串资源)。由于是单例的,这个类不能保存对上下文对象的任何引用(以防止内存泄漏)。当我在网上寻找其他实现时,我遇到了以下两种实现:

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

    第二个实现是无用的,因为我没有任何上下文实例可以传递给singleton的SomeOther方法

    因此,我提出了以下实现,在初始化Singleton实例时,我将我的Singleton抽象化为覆盖其上下文要求的方法(例如下面代码中的
    getString(intresid)

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

    我对这种方法有何误解:

    -->重写的
    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()
        }
    
        }
    

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

    幸运的是,有一个非常简单的修复方法可以消除内存泄漏。您可以安全地保留应用程序上下文(
    context.getApplicationContext
    ),它基本上是应用程序生命周期中的单例上下文

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

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

    protected void onResume() {
      super.onResume();
      Singleton.getInstance().onResume(this);
    }
    
    protected void onPause() {
      super.onResume();
      Singleton.getInstance().onPause();
    }
    
    此外,您还可以刷新
    上下文的实例
    ,并将其保存在
    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;
      }
    }
    
    类单例{
    私有WeakReference mContext;
    私有布尔hasContext(){
    返回mContext!=null&&mContext.get()!=null;
    }
    公共静态单例getInstance(上下文c){
    //你的单身汉懒惰吗
    如果(!sInstance.hasInstance()){
    sInstance.mContext=新的WeakReference(c);
    }
    回归承诺;
    }
    }
    

    第二种情况可能会引用finishing activity,因此我不建议这样做。

    您可以分享一下如何使用这些字符串,更具体地说,为什么在使用它们时没有
    上下文
    ?在大多数情况下,Activity/Service/BroadcastReceiver/SQLiteOpenHelper/等都会提供上下文,这使得您的单身汉变得有些不必要。我正在开发一款android游戏,并在其中使用Google Play游戏服务。我认为singleton是因为我需要在整个应用程序中保持一个GoogleAppClient。singleton的
    功能是做一些异步的事情。如果
    上下文
    突然变为
    null
    ,它会抛出一个错误,不是吗?@AnkitMundada如果您的上下文变为null,那么您就与上下文无关了。如果资源的上下文为null,您可以只返回null。我的意思是,在您的第一个方法中,当我在
    onResume()
    中清理上下文时,但如果它仍然由
    单例的异步调用使用,它不会引发异常吗?如果异步进程仍在使用上下文,为什么要说“您不再与上下文有任何关系?”那么请使用锁定以避免异常。处理异步代码是您的责任,这不是常见的情况。