New type of inner class that shares constructor params?

I have some android code like this:

abstract class Preferences {
    val prefs: SharedPreferences
    internal val ctx: Context

    constructor(context: Context) {
        ctx = context
        prefs = PreferenceManager.getDefaultSharedPreferences(context)
    }

    inner abstract class Preference<T>(val key: String, val default: T) : ReadWriteProperty<Any?, T> {
        constructor(resId: Int, default: T) : this(ctx.getString(resId), default)
    }

    // Omitted: the non-abstract subclasses of Preference
    // They're not really relevant here
}

In Android, leaking contexts is a common source of memory leaks, so I’d like to throw away that reference if possible. The only place I ever use the context outside of the Preferences constructor is for getString in the secondary constructor of Preference. it would technically be possible to get all the strings at the beginning and then throw out the context, as long Preferences are only instantiated as part of the Prefererences constructor.

I could do that manually in my subclass by adding an extra param to the Preference constructor, eg:

abstract class Preferences {
    val prefs: SharedPreferences

    constructor(context: Context) {
        prefs = PreferenceManager.getDefaultSharedPreferences(context)
    }

    inner abstract class Preference<T>(val key: String, val default: T) : ReadWriteProperty<Any?, T> {
        constructor(resId: Int, default: T, context: Context) : this(context.getString(resId), default)
    }
}

class Config(context: Context) : Preferences(context) {
    val myPref: Boolean by BooleanPreference(R.string.key, false, context)
}

However, I’d like to package this in a library, and the Config subclass is something they’d create; I’d like to save the the trouble of passing the context around everywhere, if possible.

Does this seem reasonable? Is there a way I don’t know about to do it right now?

Why not store an application context instead (ctx = context.applicationContext). That has no leak issues. If you don’t want your strings to be resolved immediately you will have to keep a context around. It looks that you want to wrap preferences in a nicer way. If you don’t keep your Preferences object around (just store it in your activity/fragment) it should be fine even without using the application context.

1 Like