Question: Using context without any static reference

Question

Using context without any static reference

Answers 2
Added at 2016-12-31 22:12
Tags
Question

I am trying to access application resources, (string resources to be specific) from a Singleton class. Being Singleton, this class cannot hold any reference to Context objects (to prevent memory leak). While I was looking for other implementations on the net, I came across this two implementation:

  1. Create a static context in Application class and use it across the app.
  2. Pass context as a parameter to the method that requires it.

I don't want to use the fist one as it also uses a static reference to Context object. I understand that it's ok to have it statically in the Application class of android, but still it looks like a hack.

The second implementation is useless since i don't have any instance of context which I can pass to the someOtherMethod of the singleton.

So I came up with following implementation where I make my Singleton abstract to override its context requiring methods (for ex. getString(int resId) in the code below) when I initialize the singleton instance.

I am curious to know if this can lead to any memory leaks now?

Where am I confused with this approach:

--> The reference to context in the Overridden getString is final. I am not sure if that can cause a memory leak or not.

    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()
    }

    }
Answers to

Using context without any static reference

nr: #1 dodano: 2017-01-01 02:01

Your approach does have a memory leak. The first context passed into getInstance will never be garbage collected, since your anonymous class holds a reference to it. (and there is a static reference to the anonymous class). e.g., if you call getInstance(Activity), that activity will remain in memory until the process is killed!

Fortunately there is a pretty easy fix to get rid of the memory leak. You can safely hold onto the application context (context.getApplicationContext), which is basically a singleton context for lifetime of the app.

public static SingletonClass getInstance(Context c) {
    if (sInstance == null) {
        sInstance = new SingletonClass(c.getApplicationContext());
    }
    return sInstance;
}
nr: #2 dodano: 2017-01-01 18:01

You can depend on activity lifecycle, and require activities to pass reference to your singleton object in onResume method, and clean it in onPause.

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

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

Also, you can refresh the instance of Context and hold it in 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;
  }
}

Second case could hold a reference to finishing activity, so i don't suggest it.

Source Show
◀ Wstecz