Search code examples
kotlinandroid-sharedpreferences

Constructor visibility restricted to file


I want to create an easier way to handle SharedPreferences. The way I want to call it is like this

get preference:

val email = SharedPrefs.userdata.email
val wifiOnly = SharedPrefs.connections.wifiOnly

set preference:

SharedPrefs.userdata.email = "someone@example.com"
SharedPrefs.connections.wifiOnly = true

I'm able to do so like this:

App.instance returns a Context object in the following snippet

object SharedPrefs {

    val userdata by lazy { UserPreferences() }
    val connections by lazy { ConnectionPreferences() }

    class UserPreferences {

        private val prefs: SharedPreferences = App.instance.getSharedPreferences("userdata", Context.MODE_PRIVATE)

        var email: String
            get() = prefs.getString("email", null)
            set(value) = prefs.edit().putString("email", value).apply()
    }

    class ConnectionPreferences {

        private val prefs: SharedPreferences = App.instance.getSharedPreferences("connections", Context.MODE_PRIVATE)

        var wifyOnly: Boolean
            get() = prefs.getBoolean("wifiOnly", false)
            set(value) = prefs.edit().putBoolean("wifyOnly", value).apply()
    }

}

The problem is that this can still be called: SharedPrefs.UserPreferences() Can I make this constructor private to this file or object only?


Solution

  • You can separate the interface and the implementation class, and make the latter private to the object:

    object SharedPrefs {
        val userdata: UserPreferences by lazy { UserPreferencesImpl() }
    
        interface UserPreferences {
            var email: String
        }
    
        private class UserPreferencesImpl : UserPreferences {
            private val prefs: SharedPreferences = 
                App.instance.getSharedPreferences("userdata", Context.MODE_PRIVATE)
    
            override var email: String
                get() = prefs.getString("email", null)
                set(value) = prefs.edit().putString("email", value).apply()
        }
    
    
        // ...
    }
    

    Alternatively, if you are developing a library or you have a modular architecture, you can make use of the internal visibility modifier to restrict the visibility to the module:

    class UserPreferences internal constructor() { /* ... */ }