There are single datas that need to be saved by key name. This is why preferences are so useful.
However preferences can be distinguished in two parts. Those that are real settings that the user interacts with in the PreferenceActivity and those that are merely used to save temporary or permanent data that do not correspond explicitly to a check-box or something similar.
As far as the former goes, seems that cYrixmorten's answer is the best available but you have to be aware of some maintenance.
The latter could be saved in database in a specific table with two columns, one for key and one for value.
The following code implements such an idea and is created to give a similar experience of ease of use like native android preferences.
This Scala code is not considered the most elegant solution. Use it with care.
package myAndroidSqlite
import android.content.{ContentValues, Context}
import models.DatabaseHandler
/**
* Created with IntelliJ IDEA.
* Developer: pligor
*/
abstract class MyDbPreferencesCase[INNER_TYPE, OUTER_TYPE] {
//abstract
def preferenceKey: String
def defaultValue: INNER_TYPE
def getValue(implicit context: Context): OUTER_TYPE
def setValue(newValue: OUTER_TYPE)(implicit context: Context): Boolean
//concrete
def isDefault(implicit context: Context, innerTypeManifest: Manifest[INNER_TYPE]) = {
getInnerValue.asInstanceOf[INNER_TYPE] == defaultValue
}
def isEmpty(implicit context: Context, innerTypeManifest: Manifest[INNER_TYPE]) = isDefault
private lazy val finalPreferenceKey: String = preferenceKey
def clear(implicit context: Context, innerTypeManifest: Manifest[INNER_TYPE]): Unit = {
setInnerValue(defaultValue)
}
/**
* same as clear
*/
def reset(implicit context: Context, innerTypeManifest: Manifest[INNER_TYPE]): Unit = {
clear
}
private val booleanManifest = manifest[Boolean]
private val floatManifest = manifest[Float]
private val intManifest = manifest[Int]
private val longManifest = manifest[Long]
private val stringManifest = manifest[String]
protected def getInnerValue(implicit context: Context,
innerTypeManifest: Manifest[INNER_TYPE]): Any = {
createTableIfNotExists;
val dbValue = getDBvalue
writeNullValueIfNotExists;
innerTypeManifest match {
case `booleanManifest` => dbValue.map(_.toBoolean).getOrElse(defaultValue.asInstanceOf[Boolean])
case `floatManifest` => dbValue.map(_.toFloat).getOrElse(defaultValue.asInstanceOf[Float])
case `intManifest` => dbValue.map(_.toInt).getOrElse(defaultValue.asInstanceOf[Int])
case `longManifest` => dbValue.map(_.toLong).getOrElse(defaultValue.asInstanceOf[Long])
case `stringManifest` => dbValue.getOrElse(defaultValue.asInstanceOf[String])
}
}
protected def setInnerValue(newValue: INNER_TYPE)
(implicit context: Context,
innerTypeManifest: Manifest[INNER_TYPE]): Boolean = {
createTableIfNotExists;
val stringedValue = innerTypeManifest match {
case `booleanManifest` => newValue.asInstanceOf[Boolean].toString
case `floatManifest` => newValue.asInstanceOf[Float].toString
case `intManifest` => newValue.asInstanceOf[Int].toString
case `longManifest` => newValue.asInstanceOf[Long].toString
case `stringManifest` => newValue.asInstanceOf[String]
}
val dbIdOption = getDBid
val contentValues = new ContentValues()
contentValues.put(valueColumnName, stringedValue)
if (dbIdOption.isDefined) {
DatabaseHandler.getInstance.updateById(
tableName = dbSharedPreferencesTableName,
modelId = dbIdOption.get,
contentValues = contentValues,
columnName = autoIncColumnName
)
} else {
contentValues.put(keyColumnName, finalPreferenceKey)
MySQLiteOpenHelper.validateInsertion(
DatabaseHandler.getInstance.insert(dbSharedPreferencesTableName, contentValues)
)
}
}
private val dbSharedPreferencesTableName = "android_shared_preferences"
private val autoIncColumnName = "id"
private val keyColumnName = "key"
private val valueColumnName = "value"
private def createTableIfNotExists(implicit context: Context): Unit = {
DatabaseHandler.getInstance.workWithWritableDatabase {
db =>
db.execSQL(
s"""CREATE TABLE IF NOT EXISTS $dbSharedPreferencesTableName (
|$autoIncColumnName INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|$keyColumnName TEXT NOT NULL,
|$valueColumnName TEXT NULL,
|UNIQUE ($keyColumnName)
|)""".stripMargin
)
}
}
private def getDBvalue(implicit context: Context) = {
DatabaseHandler.getInstance.getSingleScalar[String](
query = s"""SELECT "$valueColumnName" FROM $dbSharedPreferencesTableName WHERE "$keyColumnName" = ?""",
Array[String](finalPreferenceKey)
)
}
private def getDBid(implicit context: Context): Option[Long] = {
DatabaseHandler.getInstance.getSingleScalar[Long](
query = s"""SELECT $autoIncColumnName FROM $dbSharedPreferencesTableName WHERE "$keyColumnName" = ?""",
Array[String](finalPreferenceKey)
)
}
private def rowExists(implicit context: Context): Boolean = {
DatabaseHandler.getInstance.exists(
tableName = dbSharedPreferencesTableName,
value = finalPreferenceKey,
columnName = keyColumnName
)
}
private def writeNullValueIfNotExists(implicit context: Context): Unit = {
if (rowExists) {
//no need to do anything
} else {
val contentValues = new ContentValues()
contentValues.put(keyColumnName, finalPreferenceKey)
contentValues.putNull(valueColumnName)
DatabaseHandler.getInstance.insert(dbSharedPreferencesTableName, contentValues)
}
}
}
/*
TESTING ABOVE CLASS
////////////////////////////////////////////////////////////////////////////////////
{
val booleanBeforeWrite = BooleanPreference.getValue
log log s"booleanBeforeWrite: $booleanBeforeWrite"
val booleanWriteSuccess = BooleanPreference.setValue(newValue = true)
log log s"booleanWriteSuccess: $booleanWriteSuccess"
val booleanAfterWrite = BooleanPreference.getValue
log log s"booleanAfterWrite: $booleanAfterWrite"
}
{
val intImmediateWrite = IntPreference.setValue(100)
log log s"intImmediateWrite: $intImmediateWrite"
val intWrittenValue = IntPreference.getValue
log log s"intWrittenValue: $intWrittenValue"
}
{
val longImmediateWrite = LongPreference.setValue(200L)
log log s"longImmediateWrite: $longImmediateWrite"
LongPreference.clear
val longAfterClear = LongPreference.getValue
log log s"longAfterClear: $longAfterClear"
}
{
val floatBeforeWrite = FloatPreference.getValue
log log s"floatBeforeWrite: $floatBeforeWrite"
val floatWritten = FloatPreference.setValue(0.553F)
log log s"floatWritten: $floatWritten"
FloatPreference.reset
val floatAfterReset = FloatPreference.getValue
log log s"floatAfterReset: $floatAfterReset"
}
{
val stringImmediateWrite = StringPreference.setValue("go go")
log log s"stringImmediateWrite: $stringImmediateWrite"
val stringAfterWrite = StringPreference.getValue
log log s"stringAfterWrite: $stringAfterWrite"
}
////////////////////////////////////////////////////////////////////////////////////
case object BooleanPreference extends MyDbPreferencesCase[Boolean, Boolean] {
val preferenceKey: String = "BooleanPreference"
val defaultValue: Boolean = false
def getValue(implicit context: Context): Boolean = {
getInnerValue.asInstanceOf[Boolean]
}
def setValue(newValue: Boolean)(implicit context: Context): Boolean = {
setInnerValue(newValue)
}
}
case object IntPreference extends MyDbPreferencesCase[Int, Int] {
val preferenceKey: String = "IntPreference"
val defaultValue: Int = -1
def getValue(implicit context: Context): Int = {
getInnerValue.asInstanceOf[Int]
}
def setValue(newValue: Int)(implicit context: Context): Boolean = {
setInnerValue(newValue)
}
}
case object FloatPreference extends MyDbPreferencesCase[Float, Float] {
val preferenceKey: String = "FloatPreference"
val defaultValue: Float = 0.1F
def getValue(implicit context: Context): Float = {
getInnerValue.asInstanceOf[Float]
}
def setValue(newValue: Float)(implicit context: Context): Boolean = {
setInnerValue(newValue)
}
}
case object LongPreference extends MyDbPreferencesCase[Long, Long] {
val preferenceKey: String = "LongPreference"
val defaultValue: Long = +1
def getValue(implicit context: Context): Long = {
getInnerValue.asInstanceOf[Long]
}
def setValue(newValue: Long)(implicit context: Context): Boolean = {
setInnerValue(newValue)
}
}
case object StringPreference extends MyDbPreferencesCase[String, String] {
val preferenceKey: String = "StringPreference"
val defaultValue: String = "tipota"
def getValue(implicit context: Context): String = {
getInnerValue.asInstanceOf[String]
}
def setValue(newValue: String)(implicit context: Context): Boolean = {
setInnerValue(newValue)
}
}
*/
Above source code takes for granted that you have already implemented a DatabaseHandler with the necessary methods