# Lesson 10. Local and External Storage
In this lesson you'll learn about Android's local and external storage.
| Micro Sprint | 8 |
| :---------------- | :-------------------------------------- |
| Activity Type | Lesson |
| Expected Duration | 30 minutes |
| Topic | Fragments |
| Objective | Learn about local and external storage. |
---
## 1. Introduction
> As seen on [Android Documentation](https://developer.android.com/guide/topics/data/data-storage.html)
Android provides developers several options for them to save data. Depending on your needs, your preferences and how much space you're going to use you might choose one or another. The different data storage options available are:
- Internal file Storage
- External file Storage
- Shared Preferences
- Databases
## 2. Internal Storage
Files saved in the internal storage are private to your app. Unless you grant another app with root priviledges, no one can read or modify what you store here. One big difference between internal and external storage, is that the information saved on the internal storage will not persist after the user uninstalls the app.
To write some text to a file:
``` javascript
val filename = "moviles"
val fileContents = "Hello Students!"
context.openFileOutput(filename, Context.MODE_PRIVATE).use {
it.write(fileContents.toByteArray())
}
```
As you can see, openFileOutput requires a flag as a parameter, in this case we used MODE_PRIVATE because we don't want any other app to be able to read it. Since API 24, this is deprecated but still required ([read more](https://developer.android.com/training/secure-file-sharing/index.html)).
To read a file from the internal storage, simply use the *openFileInput()* method.
## 2. External Storage
Saving files in the external storage is great if you want to be able to share them with other apps and allow the user to access them from another device, althought there are two types of files in this case.
1. Public files: they are available for the user to read them and for other apps to access them. When the user uninstalls the app, this files remain available in the device.
2. Private files: these are files that belong to your app and don't provide any value to other apps if they get access to them. When the user uninstalls the app, these files get wiped as well.
In order to save a filee to the external storage, you need to define read/write permissions in your manifest file:
```xml
...
...
...
```
After you have this permissions, you need to verify that the external storage is available.
``` javascript
/* Checks if external storage is available for read and write */
fun isExternalStorageWritable(): Boolean = Environment.getExternalStorageState() == Environment.MEDIA_MOUNTED
/* Checks if external storage is available to at least read */
fun isExternalStorageReadable(): Boolean = Environment.getExternalStorageState() in
setOf(Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED_READ_ONLY)
```
Now, if you want to save public files:
```javascript
// Get the directory for the user's public pictures directory.
val file = File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName)
if (!file?.mkdirs()) {
Log.e(LOG_TAG, "Directory not created")
}
return file
}
```
And if you want to save a private file:
```javascript
fun getPrivateAlbumStorageDir(context: Context, albumName: String): File? {
// Get the directory for the app's private pictures directory.
val file = File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName)
if (!file?.mkdirs()) {
Log.e(LOG_TAG, "Directory not created")
}
return file
}
```
As you can see, the only difference comes in the methods *getExternalPublicDirectory()* and *getExternalFilesDir()*, with the last needing the app's context.
Deleting a file from external storage is quite easy:
```java
myFile.delete();
//OR
myContext.deleteFile(fileName);
```
## 3. Shared Preferences
Shared Preferences are really useful when you don't need to save a lot of information but just basic key-values of primitive data types: booleans, floats, ints, longs, and strings.
To use the shared-preferences you can do it in two different ways. The first is by calling *getSharedPreferences()* from the context of the app. This means that you're going to get the shared preferences of all the app. If you just want to have a shared preferences file for a single activity, use *getPreferences()*.
getSharedPreferences()
```java
val sharedPref = activity?.getSharedPreferences(
getString(R.string.preference_file_key), Context.MODE_PRIVATE)
```
getPreferences()
```java
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE)
```
To write to the shared preferences:
```java
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE) ?: return
with (sharedPref.edit()) {
putInt(getString(R.string.saved_high_score_key), newHighScore)
commit()
}
```
To read the shared preferences:
```java
val sharedPref = activity?.getPreferences(Context.MODE_PRIVATE) ?: return
val defaultValue = resources.getInteger(R.integer.saved_high_score_default_key)
val highScore = sharedPref.getInt(getString(R.string.saved_high_score_key), defaultValue)
```
We personally recommend you to build a helper class that manages the Shared Preferences for your whole app.
## 4. Databases
Databases in Android come with SQLite supported. Any database you create with this is completely private, however the API is really low-level, and we recommend you tu use Room persistence library to handle them.
> To read more about the Room persistence library, visit [Room persistence library documentation](https://developer.android.com/training/data-storage/room/index.html).
---
| Version | Author | Date |
| :------ | :-------------------- | :------------- |
| 1.0 | Juan Santiago Acevedo | March 27, 2018 |