Subbu Lakshmanan

Singletons per Activity context

Singletons design pattern

Singletons

Singleton Design Pattern is by far the most common design pattern and the first one that come across to anyone when think about Design Patterns. It's so commonly used that there are people who can write the pattern in their sleep.

Android Studio Default Template

class Test {
    private static final Test ourInstance = new Test();

    static Test getInstance() {
        return ourInstance;
    }

    private Test() {
    }
}

The below is the template that we generally use in our team.

Our Template


class Test {
    private static final Test ourInstance;

    static Test getInstance() {
        if(ourInstance == null){
            ourInstance = new Test();
        }
        return ourInstance;
    }

    private Test() {
    }
}

I faced a situation where I was required to create a Singleton per activity, or a Singleton class that holds an instance of Activity context. Usually when you try to declare objects like 'Activity' or 'Context' as a static field in any Java class, Android Studio warns about memory leak via static objects.

Do not place Android context classes in static fields; this is a memory leak.

To avoid that memory leakage,

  1. Do not store context (That's obvious! isn't it).

  2. Use WeakReference to store the context.

private final WeakReference<Activity> mActivityContextRef;

public static void newInstance(Activity activity) {
    if (ourInstance == null) {
        ourInstance = new Test(activity);
    }
}

private Test(Activity activity) {
    mActivityContextRef = new WeakReference<>(activity);
}

Some of the best articles on Weak References:

  1. Romain Guy's Article
  2. Articles from Google Developers Experts-1
  3. Articles from Google Developers Experts-2

Back to the earlier scenario that I described, I had to create an Singletons per Activity. Combining with our singleton template with the concept of WeakReference, I came up with this.

public static void newInstance(Activity activity) {
        if (ourInstance == null) {
            ourInstance = new Test(activity);
        } else {
            if (activity.equals(ourInstance.mActivityContextRef.get())) {
                LogUtils.debug(TAG, "newInstance: Same Activity; No need to create new instance");
            } else {
                LogUtils.debug(TAG, "newInstance: New Activity; Create new instance");
                ourInstance = null;
                ourInstance = new Test(activity);
            }
        }
    }

    private Test(Activity activity) {
        mActivityContextRef = new WeakReference<>(activity);
    }

This solution helped us to solve the issue we were facing.

I don't argue that this is perfect solution and in fact a Word of Caution When I was talking to one of my senior colleagues regarding the above Singleton per Activity, he questioned me that Why would anyone require an Activity context in a Singleton POJO class. That got me thinking and I realized that the class in question was handling too many responsiblities and refactored using MVP design pattern. I will write that in another post.

This post is also available on DEV.

All rights reserved