AutoBackUp with EncryptedSharedPreferences failing to restore - android

I am using EncryptedSharedPreferences to store user information locally (see this if you are not familiar). I have implemented AutoBackUp with BackUp rules. I backed up the preferences, cleared data on my app, and attempted to restore the data (following the steps outlined for backup and restore).
Looking at Device File Explorer in Android Studio, I can confirm that my Preferences file is being restored (it is properly named and there is encrypted data in it). However, my app functions as if the preferences file does not exist.
What am I missing?
Preferences code:
class PreferenceManager(context: Context) {
companion object {
private const val KEY_STORE_ALIAS = "APP_KEY_STORE"
private const val privatePreferences = "APP_PREFERENCES"
}
// See https://developer.android.com/topic/security/data#kotlin for more info
private val sharedPreferences = EncryptedSharedPreferences.create(
privatePreferences,
KEY_STORE_ALIAS,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
init {
//val all = sharedPreferences.all
//for (item in all) {
//Log.e("PREFERENCES", "${item.key} - ${item.value}")
//}
}
#SuppressLint("ApplySharedPref")
fun clear() {
// Normally you want apply, but we need the changes to be done immediately
sharedPreferences.edit().clear().commit()
}
fun readBoolean(key: String, defaultValue: Boolean): Boolean {
return sharedPreferences.getBoolean(key, defaultValue)
}
fun readDouble(key: String): Double {
return sharedPreferences.getFloat(key, 0f).toDouble()
}
fun readString(key: String): String {
return sharedPreferences.getString(key, "")!!
}
fun removePreference(key: String) {
sharedPreferences.edit().remove(key).apply()
}
fun writeBoolean(key: String, value: Boolean) {
sharedPreferences.edit().putBoolean(key, value).apply()
}
fun writeDouble(key: String, value: Double) {
sharedPreferences.edit().putFloat(key, value.toFloat()).apply()
}
fun writeString(key: String, value: String) {
sharedPreferences.edit().putString(key, value).apply()
}
}
I am not implementing a BackupAgent currently.

From my understanding Jetpack Security relies on keys that are generated on the device hardware, and so it is that you cannot rely on that the original key is still there after a backup restore (think about changed devices).
Encryption is only as secure as the security of the key, and as long as it cannot leave the Keystore or the device, backup and restore cannot work automatically (without user interaction).
My approach (1) would be that you ask the user for a password, encrypt your regular shared preferences based on that password (maybe with another encryption library: for example https://github.com/iamMehedi/Secured-Preference-Store), and save the password with encryptedsharedpreferences from Jetpack. After restore of the backup ask the user for the password, save it again with Jetpack and decrypt the regular SharedPreferences.
That way even when the hardware keystore changes, you can restore the backup. The disadvantage is, that the user needs to remember a password.
I follow this approach with my app, just not with sharedpreferences (they are not sensible in my use case), but with the app database.
Another approach (2) would be to check for encrypted backups (available from Pie on), if you are only concerned about backups in the cloud. With that approach you don't encrypt the sharedpreferences locally, but the backups are encrypted by default. If you need local encryption, this approach is not for you, but the advantage is, that the user must only type in his/her lockscreen password on restore of the backups and after that everything gets restored without further user interaction.
A combination is also thinkable and is preferrable, if you can live without local encryption: Approach 1 for pre-9 and Approach 2 for post-9.

As #Floj12 mentioned EncryptedSharedPreferences use Keystore and you cannot back up the Keystore, so when your encrypted data will be restored you won't be able to decrypt it.
This is very sad that Google force two things that don't work together. Keystore on Android doesn't have a backup option like Keychain on iOS.
Here I will give you more option how can you backup the data:
Store user data one backend
Use a user-stored token to decrypt the backup
Have a static password for all apps
Export backup manually by the user in settings
I wrote about it more here:
https://medium.com/#thecodeside/android-auto-backup-keystore-encryption-broken-heart-love-story-8277c8b10505

Related

How to delete the preference file created by Jetpack DataStore

I have a multi-user application and use DataStore to create a preference file for each user. I want to be able to delete the file that is created by DataStore once the user unregisters. I found this question but it only clears the preferences within the file. Since the application might have multiple users it would be better to delete the whole file. How can this be done?
Since DataStore doesn't seem to provide a way to delete the files, I decided to delete it myself.
companion object {
private const val DATASTORE_PATH = "datastore/"
private const val PREFERENCE_EXTENSION = ".preferences_pb"
}
fun deletePreferenceFile(userId: String) {
val file = File(context.filesDir, "$DATASTORE_PATH$userId$PREFERENCE_EXTENSION")
file.delete()
}

Androidx Preferences Library vs DataStore preferences

I had previously replaced SharedPreferences in my app with the new DataStore, as recommended by Google in the docs, to reap some of the obvious benefits. Then it came time to add a settings screen, and I found the Preferences Library. The confusion came when I saw the library uses SharedPreferences by default with no option to switch to DataStore. You can use setPreferenceDataStore to provide a custom storage implementation, but DataStore does not implement the PreferenceDataStore interface, leaving it up to the developer. And yes this naming is also extremely confusing. I became more confused when I found no articles or questions talking about using DataStore with the Preferences Library, so I feel like I'm missing something. Are people using both of these storage solutions side by side? Or one or the other? If I were to implement PreferenceDataStore in DataStore, are there any gotchas/pitfalls I should be looking out for?
For anyone reading the question and thinking about the setPreferenceDataStore-solution. Implementing your own PreferencesDataStore with the DataStore instead of SharedPreferences is straight forward at a glance.
class SettingsDataStore(private val dataStore: DataStore<Preferences>): PreferenceDataStore() {
override fun putString(key: String, value: String?) {
CoroutineScope(Dispatchers.IO).launch {
dataStore.edit { it[stringPreferencesKey(key)] = value!! }
}
}
override fun getString(key: String, defValue: String?): String {
return runBlocking { dataStore.data.map { it[stringPreferencesKey(key)] ?: defValue!! }.first() }
}
...
}
And then setting the datastore in your fragment
#AndroidEntryPoint
class AppSettingsFragment : PreferenceFragmentCompat() {
#Inject
lateinit var dataStore: DataStore<Preferences>
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = SettingsDataStore(dataStore)
setPreferencesFromResource(R.xml.app_preferences, rootKey)
}
}
But there are a few issues with this solution. According to the documentation runBlocking with first() to synchronously read values is the preferred way, but should be used with caution.
Make sure to setpreferenceDataStore before calling setPreferencesFromResource to avoid loading issues where the default implementation (sharedPreferences) will be used for initial loading.
A couple weeks ago on my initial try to implement the PreferenceDataStore, I had troubles with type long keys. My settings screen was correctly showing and saving numeric values for an EditTextPreference but the flows did not emit any values for these keys. There might be an issue with EditTextPreference saving numbers as strings because setting an inputType in the xml seems to have no effect (at least not on the input keyboard). While saving numbers as strings might work, this also requires reading numbers as strings. Therefore you lose the type-safety for primitive types.
Maybe with one or two updates on the settings and datastore libs there might be an official working solution for this case.
I have run into the same issue using DataStore. Not only does DataStore not implement PreferenceDataStore, but I believe it is impossible to write an adapter to bridge the two, because the DataStore uses Kotlin Flows and is asynchronous, whereas PreferenceDataStore assumes that both get and put operations to be synchronous.
My solution to this is to write the preference screen manually using a recycler view. Fortunately, ConcatAdapter made it much easier, as I can basically create one adapter for each preference item, and then combine them into one adapter using ConcatAdapter.
What I ended up with is a PreferenceItemAdapter that has mutable title, summary, visible, and enabled properties that mimics the behavior of the preference library, and also a Jetpack Compose inspired API that looks like this:
preferenceGroup {
preference {
title("Name")
summary(datastore.data.map { it.name })
onClick {
showDialog {
val text = editText(datastore.data.first().name)
negativeButton()
positiveButton()
.onEach { dataStore.edit { settings -> settings.name = text.first } }.launchIn(lifecycleScope)
}
}
}
preference {
title("Date")
summary(datastore.data.map { it.parsedDate?.format(dateFormatter) ?: "Not configured" })
onClick {
showDatePickerDialog(datastore.data.first().parsedDate ?: LocalDate.now()) { newDate ->
lifecycleScope.launch { dataStore.edit { settings -> settings.date = newDate } }
}
}
}
}
There is more manual code in this approach, but I find it easier than trying to bend the preference library to my will, and gives me the flexibility I needed for my project (which also stores some of the preferences in Firebase).
I'll add my own strategy I went with for working around the incompatibility in case it's useful to some:
I stuck with the preference library and added android:persistent="false" to all my editable preferences so they wouldn't use SharedPreferences at all. Then I was free to just save and load the preference values reactively. Storing them through click/change listeners → view model → repository, and reflecting them back with observers.
Definitely messier than a good custom solution, but it worked well for my small app.

Fire a one-off function when the Android application is installed

I want to generate a unique ID for my application instance once it is installed. Then I want this to ID to be stored in SharedPreferences so it can be referred to in future.
So the function will look like:
val uniqueID = UUID.randomUUID().toString()
then I would save it to SharedPreferences.
How do I fire this function only once the application is installed (never to be fired again)?
NOTE: My app is being written in Kotlin
Simply check if your shared preference id key returns you any data. If not, it has never been run. Otherwise, it has!
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
if(sharedPreferences.getString("ID", null) == null) {
sharedPreferences.edit().putString("ID", UUID.randomUUID().toString()).apply()
}

Storing received notifications in my android app? [duplicate]

I recently coded an Android app. It's just a simple app that allows you to keep score of a basketball game with a few simple counter intervals. I'm getting demand to add a save feature, so you can save your scores and then load them back up. Currently, when you stop the app, your data is lost. So what I was wondering is what I would have to add to have the app save a label (score) and then load it back up. Thanks guys sorry I don't know much about this stuff.
You have two options, and I'll leave selection up to you.
Shared Preferences
This is a framework unique to Android that allows you to store primitive values (such as int, boolean, and String, although strictly speaking String isn't a primitive) in a key-value framework. This means that you give a value a name, say, "homeScore" and store the value to this key.
SharedPreferences settings = getApplicationContext().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("homeScore", YOUR_HOME_SCORE);
// Apply the edits!
editor.apply();
// Get from the SharedPreferences
SharedPreferences settings = getApplicationContext().getSharedPreferences(PREFS_NAME, 0);
int homeScore = settings.getInt("homeScore", 0);
Internal Storage
This, in my opinion, is what you might be looking for. You can store anything you want to a file, so this gives you more flexibility. However, the process can be trickier because everything will be stored as bytes, and that means you have to be careful to keep your read and write processes working together.
int homeScore;
byte[] homeScoreBytes;
homeScoreBytes[0] = (byte) homeScore;
homeScoreBytes[1] = (byte) (homeScore >> 8); //you can probably skip these two
homeScoreBytes[2] = (byte) (homeScore >> 16); //lines, because I've never seen a
//basketball score above 128, it's
//such a rare occurance.
FileOutputStream outputStream = getApplicationContext().openFileOutput(FILENAME, Context.MODE_PRIVATE);
outputStream.write(homeScoreBytes);
outputStream.close();
Now, you can also look into External Storage, but I don't recommend that in this particular case, because the external storage might not be there later. (Note that if you pick this, it requires a permission)
OP is asking for a "save" function, which is more than just preserving data across executions of the program (which you must do for the app to be worth anything.)
I recommend saving the data in a file on the sdcard which allows you to not only recall it later, but allows the user to mount the device as an external drive on their own computer and grab the data for use in other places.
So you really need a multi-point system:
1) Implement onSaveInstanceState(). In this method, you're passed a Bundle, which is basically like a dictionary. Store as much information in the bundle as would be needed to restart the app exactly where it left off. In your onCreate() method, check for the passed-in bundle to be non-null, and if so, restore the state from the bundle.
2) Implement onPause(). In this method, create a SharedPreferences editor and use it to save whatever state you need to start the app up next time. This mainly consists of the users' preferences (hence the name), but anything else relavent to the app's start-up state should go here as well. I would not store scores here, just the stuff you need to restart the app. Then, in onCreate(), whenever there's no bundle object, use the SharedPreferences interface to recall those settings.
3a) As for things like scores, you could follow Mathias's advice above and store the scores in the directory returned in getFilesDir(), using openFileOutput(), etc. I think this directory is private to the app and lives in main storage, meaning that other apps and the user would not be able to access the data. If that's ok with you, then this is probably the way to go.
3b) If you do want other apps or the user to have direct access to the data, or if the data is going to be very large, then the sdcard is the way to go. Pick a directory name like com/user1446371/basketballapp/ to avoid collisions with other applications (unless you're sure that your app name is reasonably unique) and create that directory on the sdcard. As Mathias pointed out, you should first confirm that the sdcard is mounted.
File sdcard = Environment.getExternalStorageDirectory();
if( sdcard == null || !sdcard.isDirectory()) {
fail("sdcard not available");
}
File datadir = new File(sdcard, "com/user1446371/basketballapp/");
if( !datadir.exists() && !datadir.mkdirs() ) {
fail("unable to create data directory");
}
if( !datadir.isDirectory() ) {
fail("exists, but is not a directory");
}
// Now use regular java I/O to read and write files to data directory
I recommend simple CSV files for your data, so that other applications can read them easily.
Obviously, you'll have to write activities that allow "save" and "open" dialogs. I generally just make calls to the openintents file manager and let it do the work. This requires that your users install the openintents file manager to make use of these features, however.
In onCreate:
SharedPreferences sharedPref = getSharedPreferences("mySettings", MODE_PRIVATE);
String mySetting = sharedPref.getString("mySetting", null);
In onDestroy or equivalent:
SharedPreferences sharedPref = getSharedPreferences("mySettings", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("mySetting", "Hello Android");
editor.commit();
Use SharedPreferences, http://developer.android.com/reference/android/content/SharedPreferences.html
Here's a sample:
http://developer.android.com/guide/topics/data/data-storage.html#pref
If the data structure is more complex or the data is large, use an Sqlite database; but for small amount of data and with a very simple data structure, I'd say, SharedPrefs will do and a DB might be overhead.
There is a lot of options to store your data and Android offers you to chose anyone
Your data storage options are the following:
Shared Preferences
Store private primitive data in key-value pairs.
Internal Storage
Store private data on the device memory.
External Storage
Store public data on the shared external storage.
SQLite Databases
Store structured data in a private database.
Network Connection
Store data on the web with your own network server
Check here for examples and tuto
2021 Answer
Old question but in 2021 you can use several things to save data.
1. Using local database - Room Library
Room is a library that let you store data in the internal SqlLite database that come with your Android device, it's a local database. It's easy and really powerful.
https://developer.android.com/training/data-storage/room
2. Using a remote database - Firebase / Your own database implementation
You can use Firebase services or your own database implementation on your server to remote store your data, that way you could access the data throw multiple devices.
https://firebase.google.com/docs/firestore
3. Storing a local file
You can store all information in a local file saved in the device's external storage, using maybe a .txt file with a \n as data separator. That option looks really "caveman" in 2021.
https://stackoverflow.com/a/14377185/14327871
4. Using SharedPreferences
As many people pointed you can also use the sharedPreferences to store little information as pair of key - value, it's useful for example when saving user preferences across a session.
https://developer.android.com/training/data-storage/shared-preferences?hl=en
For the OP case I would suggest using the 1st or 2nd option.
Shared preferences:
android shared preferences example for high scores?
Does your application has an access to the "external Storage Media". If it does then you can simply write the value (store it with timestamp) in a file and save it. The timestamp will help you in showing progress if thats what you are looking for. {not a smart solution.}
You can store your scores and load them back easily! by using this method
Use this library Paper Db
Add this library on your app:
implementation 'io.github.pilgr:paperdb:2.7.1'
and then initialize it once in the activity onCreate() you are storing:
Paper.init(context)
create a key to store your scores
int myScore=10;
Paper.book().write("scores", myScore);
and get the value of the score :
int mySavedScores=Paper.book().read("scores");
that's It!!! now you can save and access the value even application is closed
and refer the documentation for more methods and information,
it's a Good habit to read the documentation.
Please don't forget one thing - Internal Storage data are deleted when you uninstall the app. In some cases it can be "unexpected feature". Then it's good to use external storage.
Google docs about storage - Please look in particular at getExternalStoragePublicDirectory
Quick answer:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Boolean Music;
public static final String PREFS_NAME = "MyPrefsFile";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//restore preferences
SharedPreferences settings = this.getSharedPreferences(PREFS_NAME, 0);
Music = settings.getBoolean("key", true);
}
#Override
public void onClick() {
//save music setup to system
SharedPreferences settings = this.getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("key", Music);
editor.apply();
}
}
In my opinion db4o is the easiest way to go.
Here you can find a tutorial:
http://community.versant.com/documentation/reference/db4o-7.12/java/tutorial/
And here you can download the library:
http://www.db4o.com/community/download.aspx?file=db4o-8.0-java.zip
(Just put the db4o-8.0...-all-java5.jar in the lib directory into your project's libs folder.
If there is no libs folder in you project create it)
As db4o is a object oriented database system you can directly save you objects into the database and later get them back.
use this methods to use sharedPreferences very easily.
private val sharedPreferences = context.getSharedPreferences("myPreferences", Context.MODE_PRIVATE)
fun put(key: String, value: String) = sharedPreferences.edit().putString(key, value).apply()
fun put(key: String, value: Int) = sharedPreferences.edit().putInt(key, value).apply()
fun put(key: String, value: Float) = sharedPreferences.edit().putFloat(key, value).apply()
fun put(key: String, value: Boolean) = sharedPreferences.edit().putBoolean(key, value).apply()
fun put(key: String, value: Long) = sharedPreferences.edit().putLong(key, value).apply()
fun getString(key: String, defaultValue: String? = null): String? = sharedPreferences.getString(key, defaultValue)
fun getInt(key: String, defaultValue: Int = -1): Int = sharedPreferences.getInt(key, defaultValue)
fun getFloat(key: String, defaultValue: Float = -1F): Float = sharedPreferences.getFloat(key, defaultValue)
fun getBoolean(key: String, defaultValue: Boolean = false): Boolean = sharedPreferences.getBoolean(key, defaultValue)
fun getLong(key: String, defaultValue: Long = -1L): Long = sharedPreferences.getLong(key, defaultValue)
fun clearAll() = sharedPreferences.edit().clear().apply()
put them in a class and get context in its constructor.

How to save data in an android app

I recently coded an Android app. It's just a simple app that allows you to keep score of a basketball game with a few simple counter intervals. I'm getting demand to add a save feature, so you can save your scores and then load them back up. Currently, when you stop the app, your data is lost. So what I was wondering is what I would have to add to have the app save a label (score) and then load it back up. Thanks guys sorry I don't know much about this stuff.
You have two options, and I'll leave selection up to you.
Shared Preferences
This is a framework unique to Android that allows you to store primitive values (such as int, boolean, and String, although strictly speaking String isn't a primitive) in a key-value framework. This means that you give a value a name, say, "homeScore" and store the value to this key.
SharedPreferences settings = getApplicationContext().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("homeScore", YOUR_HOME_SCORE);
// Apply the edits!
editor.apply();
// Get from the SharedPreferences
SharedPreferences settings = getApplicationContext().getSharedPreferences(PREFS_NAME, 0);
int homeScore = settings.getInt("homeScore", 0);
Internal Storage
This, in my opinion, is what you might be looking for. You can store anything you want to a file, so this gives you more flexibility. However, the process can be trickier because everything will be stored as bytes, and that means you have to be careful to keep your read and write processes working together.
int homeScore;
byte[] homeScoreBytes;
homeScoreBytes[0] = (byte) homeScore;
homeScoreBytes[1] = (byte) (homeScore >> 8); //you can probably skip these two
homeScoreBytes[2] = (byte) (homeScore >> 16); //lines, because I've never seen a
//basketball score above 128, it's
//such a rare occurance.
FileOutputStream outputStream = getApplicationContext().openFileOutput(FILENAME, Context.MODE_PRIVATE);
outputStream.write(homeScoreBytes);
outputStream.close();
Now, you can also look into External Storage, but I don't recommend that in this particular case, because the external storage might not be there later. (Note that if you pick this, it requires a permission)
OP is asking for a "save" function, which is more than just preserving data across executions of the program (which you must do for the app to be worth anything.)
I recommend saving the data in a file on the sdcard which allows you to not only recall it later, but allows the user to mount the device as an external drive on their own computer and grab the data for use in other places.
So you really need a multi-point system:
1) Implement onSaveInstanceState(). In this method, you're passed a Bundle, which is basically like a dictionary. Store as much information in the bundle as would be needed to restart the app exactly where it left off. In your onCreate() method, check for the passed-in bundle to be non-null, and if so, restore the state from the bundle.
2) Implement onPause(). In this method, create a SharedPreferences editor and use it to save whatever state you need to start the app up next time. This mainly consists of the users' preferences (hence the name), but anything else relavent to the app's start-up state should go here as well. I would not store scores here, just the stuff you need to restart the app. Then, in onCreate(), whenever there's no bundle object, use the SharedPreferences interface to recall those settings.
3a) As for things like scores, you could follow Mathias's advice above and store the scores in the directory returned in getFilesDir(), using openFileOutput(), etc. I think this directory is private to the app and lives in main storage, meaning that other apps and the user would not be able to access the data. If that's ok with you, then this is probably the way to go.
3b) If you do want other apps or the user to have direct access to the data, or if the data is going to be very large, then the sdcard is the way to go. Pick a directory name like com/user1446371/basketballapp/ to avoid collisions with other applications (unless you're sure that your app name is reasonably unique) and create that directory on the sdcard. As Mathias pointed out, you should first confirm that the sdcard is mounted.
File sdcard = Environment.getExternalStorageDirectory();
if( sdcard == null || !sdcard.isDirectory()) {
fail("sdcard not available");
}
File datadir = new File(sdcard, "com/user1446371/basketballapp/");
if( !datadir.exists() && !datadir.mkdirs() ) {
fail("unable to create data directory");
}
if( !datadir.isDirectory() ) {
fail("exists, but is not a directory");
}
// Now use regular java I/O to read and write files to data directory
I recommend simple CSV files for your data, so that other applications can read them easily.
Obviously, you'll have to write activities that allow "save" and "open" dialogs. I generally just make calls to the openintents file manager and let it do the work. This requires that your users install the openintents file manager to make use of these features, however.
In onCreate:
SharedPreferences sharedPref = getSharedPreferences("mySettings", MODE_PRIVATE);
String mySetting = sharedPref.getString("mySetting", null);
In onDestroy or equivalent:
SharedPreferences sharedPref = getSharedPreferences("mySettings", MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("mySetting", "Hello Android");
editor.commit();
Use SharedPreferences, http://developer.android.com/reference/android/content/SharedPreferences.html
Here's a sample:
http://developer.android.com/guide/topics/data/data-storage.html#pref
If the data structure is more complex or the data is large, use an Sqlite database; but for small amount of data and with a very simple data structure, I'd say, SharedPrefs will do and a DB might be overhead.
There is a lot of options to store your data and Android offers you to chose anyone
Your data storage options are the following:
Shared Preferences
Store private primitive data in key-value pairs.
Internal Storage
Store private data on the device memory.
External Storage
Store public data on the shared external storage.
SQLite Databases
Store structured data in a private database.
Network Connection
Store data on the web with your own network server
Check here for examples and tuto
2021 Answer
Old question but in 2021 you can use several things to save data.
1. Using local database - Room Library
Room is a library that let you store data in the internal SqlLite database that come with your Android device, it's a local database. It's easy and really powerful.
https://developer.android.com/training/data-storage/room
2. Using a remote database - Firebase / Your own database implementation
You can use Firebase services or your own database implementation on your server to remote store your data, that way you could access the data throw multiple devices.
https://firebase.google.com/docs/firestore
3. Storing a local file
You can store all information in a local file saved in the device's external storage, using maybe a .txt file with a \n as data separator. That option looks really "caveman" in 2021.
https://stackoverflow.com/a/14377185/14327871
4. Using SharedPreferences
As many people pointed you can also use the sharedPreferences to store little information as pair of key - value, it's useful for example when saving user preferences across a session.
https://developer.android.com/training/data-storage/shared-preferences?hl=en
For the OP case I would suggest using the 1st or 2nd option.
Shared preferences:
android shared preferences example for high scores?
Does your application has an access to the "external Storage Media". If it does then you can simply write the value (store it with timestamp) in a file and save it. The timestamp will help you in showing progress if thats what you are looking for. {not a smart solution.}
You can store your scores and load them back easily! by using this method
Use this library Paper Db
Add this library on your app:
implementation 'io.github.pilgr:paperdb:2.7.1'
and then initialize it once in the activity onCreate() you are storing:
Paper.init(context)
create a key to store your scores
int myScore=10;
Paper.book().write("scores", myScore);
and get the value of the score :
int mySavedScores=Paper.book().read("scores");
that's It!!! now you can save and access the value even application is closed
and refer the documentation for more methods and information,
it's a Good habit to read the documentation.
Please don't forget one thing - Internal Storage data are deleted when you uninstall the app. In some cases it can be "unexpected feature". Then it's good to use external storage.
Google docs about storage - Please look in particular at getExternalStoragePublicDirectory
Quick answer:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Boolean Music;
public static final String PREFS_NAME = "MyPrefsFile";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//restore preferences
SharedPreferences settings = this.getSharedPreferences(PREFS_NAME, 0);
Music = settings.getBoolean("key", true);
}
#Override
public void onClick() {
//save music setup to system
SharedPreferences settings = this.getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putBoolean("key", Music);
editor.apply();
}
}
In my opinion db4o is the easiest way to go.
Here you can find a tutorial:
http://community.versant.com/documentation/reference/db4o-7.12/java/tutorial/
And here you can download the library:
http://www.db4o.com/community/download.aspx?file=db4o-8.0-java.zip
(Just put the db4o-8.0...-all-java5.jar in the lib directory into your project's libs folder.
If there is no libs folder in you project create it)
As db4o is a object oriented database system you can directly save you objects into the database and later get them back.
use this methods to use sharedPreferences very easily.
private val sharedPreferences = context.getSharedPreferences("myPreferences", Context.MODE_PRIVATE)
fun put(key: String, value: String) = sharedPreferences.edit().putString(key, value).apply()
fun put(key: String, value: Int) = sharedPreferences.edit().putInt(key, value).apply()
fun put(key: String, value: Float) = sharedPreferences.edit().putFloat(key, value).apply()
fun put(key: String, value: Boolean) = sharedPreferences.edit().putBoolean(key, value).apply()
fun put(key: String, value: Long) = sharedPreferences.edit().putLong(key, value).apply()
fun getString(key: String, defaultValue: String? = null): String? = sharedPreferences.getString(key, defaultValue)
fun getInt(key: String, defaultValue: Int = -1): Int = sharedPreferences.getInt(key, defaultValue)
fun getFloat(key: String, defaultValue: Float = -1F): Float = sharedPreferences.getFloat(key, defaultValue)
fun getBoolean(key: String, defaultValue: Boolean = false): Boolean = sharedPreferences.getBoolean(key, defaultValue)
fun getLong(key: String, defaultValue: Long = -1L): Long = sharedPreferences.getLong(key, defaultValue)
fun clearAll() = sharedPreferences.edit().clear().apply()
put them in a class and get context in its constructor.

Categories

Resources