Step #7: Retrieving Our Preference
All through this work, we have been passing around a URL as a parameter. We are getting the URL from the user in our PrefsFragment
, but we need a way to get that value (or a default value) into our main code. And, since this involves disk I/O, we should set up another repository with a suspend
function that can handle loading that data for us.
Right-click over the com.commonsware.todo.repo
package in the java/
directory and choose “New” > “Kotlin File/Class” from the context menu. For the name, fill in PrefsRepository
, and choose “Class” for the kind. Press Enter or Return to create the class. Then, replace the class contents with:
package com.commonsware.todo.repo
import android.content.Context
import androidx.preference.PreferenceManager
import com.commonsware.todo.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class PrefsRepository(context: Context) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
private val webServiceUrlKey = context.getString(R.string.web_service_url_key)
private val defaultWebServiceUrl =
context.getString(R.string.web_service_url_default)
suspend fun loadWebServiceUrl(): String = withContext(Dispatchers.IO) {
prefs.getString(webServiceUrlKey, defaultWebServiceUrl) ?: defaultWebServiceUrl
}
}
Given a Context
constructor parameter, we set up three properties:
-
prefs
, which is theSharedPreferences
object that is used by ourPreferenceScreen
-
webServiceUrlKey
, which is the name of the preference that we want -
defaultWebServiceUrl
, which is the default URL to use, if the user did not override it in thePrefsFragment
SharedPreferences
gives us read/write access to the preferences. Those preferences are stored on disk in an XML file. The first time we try reading (or writing) a preference, the SharedPreferences
will load that XML file into memory. Therefore, the loadWebServiceUrl()
function is a suspend
function, so we ensure that loading and parsing that XML happens on a background thread.
To read a preference, you call a typed getter method, such as getString()
, on the SharedPreferences
object. This takes two parameters:
- The key under which the preference is stored, which should match the key that you specified in your
PreferenceScreen
; and - The default value to return if the user has not supplied a preference value yet via
PrefsFragment
getString()
is marked as potentially returning null
. That is because you could pass null
as the default value, in which case getString()
will return null
if there is no value for the preference defined yet. getString()
should not return null
if you provide a non-null
default value… but the Kotlin compiler has no way of knowing this. Since we need some URL to try, loadWebServiceUrl()
is set up to return String
, not String?
. So we cannot just return the String?
that we get back from getString()
. We could use the Kotlin !!
operator to force the type to be non-nullable. Here, we use the Elvis operator to say “OK, if getString()
returns null
unexpectedly, use our default value”.
Then, go into ToDoApp
and add another line to our module
closure:
single { PrefsRepository(androidContext()) }
This will make a PrefsRepository
available to other components via Koin.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.