Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 1 | page.title=Storage Options |
Joe Fernandez | 33baa5a | 2013-11-14 11:41:19 -0800 | [diff] [blame] | 2 | page.tags=database,sharedpreferences,sdcard |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 3 | @jd:body |
| 4 | |
| 5 | |
| 6 | <div id="qv-wrapper"> |
| 7 | <div id="qv"> |
| 8 | |
| 9 | <h2>Storage quickview</h2> |
| 10 | <ul> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 11 | <li>Use Shared Preferences for primitive data</li> |
| 12 | <li>Use internal device storage for private data</li> |
| 13 | <li>Use external storage for large data sets that are not private</li> |
| 14 | <li>Use SQLite databases for structured storage</li> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 15 | </ul> |
| 16 | |
| 17 | <h2>In this document</h2> |
| 18 | <ol> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 19 | <li><a href="#pref">Using Shared Preferences</a></li> |
Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 20 | <li><a href="#filesInternal">Using the Internal Storage</a></li> |
| 21 | <li><a href="#filesExternal">Using the External Storage</a></li> |
| 22 | <li><a href="#db">Using Databases</a></li> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 23 | <li><a href="#netw">Using a Network Connection</a></li> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 24 | </ol> |
| 25 | |
| 26 | <h2>See also</h2> |
| 27 | <ol> |
| 28 | <li><a href="#pref">Content Providers and Content Resolvers</a></li> |
| 29 | </ol> |
| 30 | |
| 31 | </div> |
| 32 | </div> |
| 33 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 34 | <p>Android provides several options for you to save persistent application data. The solution you |
| 35 | choose depends on your specific needs, such as whether the data should be private to your |
| 36 | application or accessible to other applications (and the user) and how much space your data |
| 37 | requires. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 38 | </p> |
| 39 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 40 | <p>Your data storage options are the following:</p> |
| 41 | |
| 42 | <dl> |
| 43 | <dt><a href="#pref">Shared Preferences</a></dt> |
| 44 | <dd>Store private primitive data in key-value pairs.</dd> |
| 45 | <dt><a href="#filesInternal">Internal Storage</a></dt> |
| 46 | <dd>Store private data on the device memory.</dd> |
| 47 | <dt><a href="#filesExternal">External Storage</a></dt> |
| 48 | <dd>Store public data on the shared external storage.</dd> |
| 49 | <dt><a href="#db">SQLite Databases</a></dt> |
| 50 | <dd>Store structured data in a private database.</dd> |
| 51 | <dt><a href="#netw">Network Connection</a></dt> |
| 52 | <dd>Store data on the web with your own network server.</dd> |
| 53 | </dl> |
| 54 | |
| 55 | <p>Android provides a way for you to expose even your private data to other applications |
| 56 | — with a <a href="{@docRoot}guide/topics/providers/content-providers.html">content |
| 57 | provider</a>. A content provider is an optional component that exposes read/write access to |
| 58 | your application data, subject to whatever restrictions you want to impose. For more information |
| 59 | about using content providers, see the |
| 60 | <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a> |
| 61 | documentation. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 62 | </p> |
| 63 | |
| 64 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 65 | |
| 66 | |
| 67 | <h2 id="pref">Using Shared Preferences</h2> |
| 68 | |
| 69 | <p>The {@link android.content.SharedPreferences} class provides a general framework that allows you |
| 70 | to save and retrieve persistent key-value pairs of primitive data types. You can use {@link |
| 71 | android.content.SharedPreferences} to save any primitive data: booleans, floats, ints, longs, and |
| 72 | strings. This data will persist across user sessions (even if your application is killed).</p> |
| 73 | |
| 74 | <div class="sidebox-wrapper"> |
| 75 | <div class="sidebox"> |
| 76 | <h3>User Preferences</h3> |
| 77 | <p>Shared preferences are not strictly for saving "user preferences," such as what ringtone a |
| 78 | user has chosen. If you're interested in creating user preferences for your application, see {@link |
| 79 | android.preference.PreferenceActivity}, which provides an Activity framework for you to create |
| 80 | user preferences, which will be automatically persisted (using shared preferences).</p> |
| 81 | </div> |
| 82 | </div> |
| 83 | |
| 84 | <p>To get a {@link android.content.SharedPreferences} object for your application, use one of |
| 85 | two methods:</p> |
| 86 | <ul> |
| 87 | <li>{@link android.content.Context#getSharedPreferences(String,int) |
| 88 | getSharedPreferences()} - Use this if you need multiple preferences files identified by name, |
| 89 | which you specify with the first parameter.</li> |
| 90 | <li>{@link android.app.Activity#getPreferences(int) getPreferences()} - Use this if you need |
| 91 | only one preferences file for your Activity. Because this will be the only preferences file |
| 92 | for your Activity, you don't supply a name.</li> |
| 93 | </ul> |
| 94 | |
| 95 | <p>To write values:</p> |
| 96 | <ol> |
| 97 | <li>Call {@link android.content.SharedPreferences#edit()} to get a {@link |
| 98 | android.content.SharedPreferences.Editor}.</li> |
| 99 | <li>Add values with methods such as {@link |
| 100 | android.content.SharedPreferences.Editor#putBoolean(String,boolean) putBoolean()} and {@link |
| 101 | android.content.SharedPreferences.Editor#putString(String,String) putString()}.</li> |
| 102 | <li>Commit the new values with {@link android.content.SharedPreferences.Editor#commit()}</li> |
| 103 | </ol> |
| 104 | |
| 105 | <p>To read values, use {@link android.content.SharedPreferences} methods such as {@link |
| 106 | android.content.SharedPreferences#getBoolean(String,boolean) getBoolean()} and {@link |
| 107 | android.content.SharedPreferences#getString(String,String) getString()}.</p> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 108 | |
| 109 | <p> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 110 | Here is an example that saves a preference for silent keypress mode in a |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 111 | calculator: |
| 112 | </p> |
| 113 | |
| 114 | <pre> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 115 | public class Calc extends Activity { |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 116 | public static final String PREFS_NAME = "MyPrefsFile"; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 117 | |
| 118 | @Override |
Scott Main | c4367e5 | 2010-09-03 11:03:42 -0700 | [diff] [blame] | 119 | protected void onCreate(Bundle state){ |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 120 | super.onCreate(state); |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 121 | . . . |
| 122 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 123 | // Restore preferences |
| 124 | SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); |
| 125 | boolean silent = settings.getBoolean("silentMode", false); |
| 126 | setSilent(silent); |
| 127 | } |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 128 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 129 | @Override |
| 130 | protected void onStop(){ |
| 131 | super.onStop(); |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 132 | |
| 133 | // We need an Editor object to make preference changes. |
| 134 | // All objects are from android.context.Context |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 135 | SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0); |
| 136 | SharedPreferences.Editor editor = settings.edit(); |
| 137 | editor.putBoolean("silentMode", mSilentMode); |
| 138 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 139 | // Commit the edits! |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 140 | editor.commit(); |
| 141 | } |
| 142 | } |
| 143 | </pre> |
| 144 | |
| 145 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 146 | |
| 147 | |
| 148 | <a name="files"></a> |
Scott Main | 9280c34 | 2010-05-11 19:28:31 -0700 | [diff] [blame] | 149 | <h2 id="filesInternal">Using the Internal Storage</h2> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 150 | |
| 151 | <p>You can save files directly on the device's internal storage. By default, files saved |
| 152 | to the internal storage are private to your application and other applications cannot access |
| 153 | them (nor can the user). When the user uninstalls your application, these files are removed.</p> |
| 154 | |
| 155 | <p>To create and write a private file to the internal storage:</p> |
| 156 | |
| 157 | <ol> |
| 158 | <li>Call {@link android.content.Context#openFileOutput(String,int) openFileOutput()} with the |
| 159 | name of the file and the operating mode. This returns a {@link java.io.FileOutputStream}.</li> |
| 160 | <li>Write to the file with {@link java.io.FileOutputStream#write(byte[]) write()}.</li> |
| 161 | <li>Close the stream with {@link java.io.FileOutputStream#close()}.</li> |
| 162 | </ol> |
| 163 | |
| 164 | <p>For example:</p> |
| 165 | |
| 166 | <pre> |
| 167 | String FILENAME = "hello_file"; |
| 168 | String string = "hello world!"; |
| 169 | |
| 170 | FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE); |
| 171 | fos.write(string.getBytes()); |
| 172 | fos.close(); |
| 173 | </pre> |
| 174 | |
| 175 | <p>{@link android.content.Context#MODE_PRIVATE} will create the file (or replace a file of |
| 176 | the same name) and make it private to your application. Other modes available are: {@link |
| 177 | android.content.Context#MODE_APPEND}, {@link |
| 178 | android.content.Context#MODE_WORLD_READABLE}, and {@link |
| 179 | android.content.Context#MODE_WORLD_WRITEABLE}.</p> |
| 180 | |
| 181 | <p>To read a file from internal storage:</p> |
| 182 | |
| 183 | <ol> |
| 184 | <li>Call {@link android.content.Context#openFileInput openFileInput()} and pass it the |
| 185 | name of the file to read. This returns a {@link java.io.FileInputStream}.</li> |
| 186 | <li>Read bytes from the file with {@link java.io.FileInputStream#read(byte[],int,int) |
| 187 | read()}.</li> |
| 188 | <li>Then close the stream with {@link java.io.FileInputStream#close()}.</li> |
| 189 | </ol> |
| 190 | |
| 191 | <p class="note"><strong>Tip:</strong> If you want to save a static file in your application at |
| 192 | compile time, save the file in your project <code>res/raw/</code> directory. You can open it with |
| 193 | {@link android.content.res.Resources#openRawResource(int) openRawResource()}, passing the {@code |
| 194 | R.raw.<em><filename></em>} resource ID. This method returns an {@link java.io.InputStream} |
| 195 | that you can use to read the file (but you cannot write to the original file). |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 196 | </p> |
| 197 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 198 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 199 | <h3 id="InternalCache">Saving cache files</h3> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 200 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 201 | <p>If you'd like to cache some data, rather than store it persistently, you should use {@link |
| 202 | android.content.Context#getCacheDir()} to open a {@link |
| 203 | java.io.File} that represents the internal directory where your application should save |
| 204 | temporary cache files.</p> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 205 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 206 | <p>When the device is |
| 207 | low on internal storage space, Android may delete these cache files to recover space. However, you |
| 208 | should not rely on the system to clean up these files for you. You should always maintain the cache |
| 209 | files yourself and stay within a reasonable limit of space consumed, such as 1MB. When the user |
| 210 | uninstalls your application, these files are removed.</p> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 211 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 212 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 213 | <h3 id="InternalMethods">Other useful methods</h3> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 214 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 215 | <dl> |
| 216 | <dt>{@link android.content.Context#getFilesDir()}</dt> |
| 217 | <dd>Gets the absolute path to the filesystem directory where your internal files are saved.</dd> |
| 218 | <dt>{@link android.content.Context#getDir(String,int) getDir()}</dt> |
| 219 | <dd>Creates (or opens an existing) directory within your internal storage space.</dd> |
| 220 | <dt>{@link android.content.Context#deleteFile(String) deleteFile()}</dt> |
| 221 | <dd>Deletes a file saved on the internal storage.</dd> |
| 222 | <dt>{@link android.content.Context#fileList()}</dt> |
| 223 | <dd>Returns an array of files currently saved by your application.</dd> |
| 224 | </dl> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 225 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 226 | |
| 227 | |
| 228 | |
Scott Main | 9280c34 | 2010-05-11 19:28:31 -0700 | [diff] [blame] | 229 | <h2 id="filesExternal">Using the External Storage</h2> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 230 | |
| 231 | <p>Every Android-compatible device supports a shared "external storage" that you can use to |
| 232 | save files. This can be a removable storage media (such as an SD card) or an internal |
| 233 | (non-removable) storage. Files saved to the external storage are world-readable and can |
| 234 | be modified by the user when they enable USB mass storage to transfer files on a computer.</p> |
| 235 | |
Scott Main | 04c63a4 | 2012-09-07 15:26:39 -0700 | [diff] [blame] | 236 | <p class="caution"><strong>Caution:</strong> External storage can become unavailable if the user mounts the |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 237 | external storage on a computer or removes the media, and there's no security enforced upon files you |
| 238 | save to the external storage. All applications can read and write files placed on the external |
| 239 | storage and the user can remove them.</p> |
| 240 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 241 | <h3 id="ExternalPermissions">Getting access to external storage</h3> |
| 242 | |
| 243 | <p>In order to read or write files on the external storage, your app must acquire the |
| 244 | {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} |
| 245 | or {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} system |
| 246 | permissions. For example:</p> |
| 247 | <pre> |
| 248 | <manifest ...> |
| 249 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
| 250 | ... |
| 251 | </manifest> |
| 252 | </pre> |
| 253 | |
| 254 | <p>If you need to both read and write files, then you need to request only the |
| 255 | {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, because it |
| 256 | implicitly requires read access as well.</p> |
| 257 | |
| 258 | <p class="note"><strong>Note:</strong> Beginning with Android 4.4, these permissions are not |
| 259 | required if you're reading or writing only files that are private to your app. For more |
| 260 | information, see the section below about |
| 261 | <a href="#AccessingExtFiles">saving files that are app-private</a>.</p> |
| 262 | |
| 263 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 264 | |
Scott Main | a90eb8f | 2011-04-05 14:05:03 -0700 | [diff] [blame] | 265 | <h3 id="MediaAvail">Checking media availability</h3> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 266 | |
| 267 | <p>Before you do any work with the external storage, you should always call {@link |
| 268 | android.os.Environment#getExternalStorageState()} to check whether the media is available. The |
| 269 | media might be mounted to a computer, missing, read-only, or in some other state. For example, |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 270 | here are a couple methods you can use to check the availability:</p> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 271 | |
| 272 | <pre> |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 273 | /* Checks if external storage is available for read and write */ |
| 274 | public boolean isExternalStorageWritable() { |
| 275 | String state = Environment.getExternalStorageState(); |
| 276 | if (Environment.MEDIA_MOUNTED.equals(state)) { |
| 277 | return true; |
| 278 | } |
| 279 | return false; |
| 280 | } |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 281 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 282 | /* Checks if external storage is available to at least read */ |
| 283 | public boolean isExternalStorageReadable() { |
| 284 | String state = Environment.getExternalStorageState(); |
| 285 | if (Environment.MEDIA_MOUNTED.equals(state) || |
| 286 | Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { |
| 287 | return true; |
| 288 | } |
| 289 | return false; |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 290 | } |
| 291 | </pre> |
| 292 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 293 | <p>The {@link android.os.Environment#getExternalStorageState()} method returns other states that you |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 294 | might want to check, such as whether the media is being shared (connected to a computer), is missing |
| 295 | entirely, has been removed badly, etc. You can use these to notify the user with more information |
| 296 | when your application needs to access the media.</p> |
| 297 | |
| 298 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 299 | <h3 id="SavingSharedFiles">Saving files that can be shared with other apps</h3> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 300 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 301 | <div class="sidebox-wrapper" > |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 302 | <div class="sidebox"> |
| 303 | |
| 304 | <h4>Hiding your files from the Media Scanner</h4> |
| 305 | |
| 306 | <p>Include an empty file named {@code .nomedia} in your external files directory (note the dot |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 307 | prefix in the filename). This prevents media scanner from reading your media |
| 308 | files and providing them to other apps through the {@link android.provider.MediaStore} |
| 309 | content provider. However, if your files are truly private to your app, you should |
| 310 | <a href="#AccessingExtFiles">save them in an app-private directory</a>.</p> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 311 | |
| 312 | </div> |
| 313 | </div> |
| 314 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 315 | <p>Generally, new files that the user may acquire through your app should be saved to a "public" |
| 316 | location on the device where other apps can access them and the user can easily copy them from the |
| 317 | device. When doing so, you should use to one of the shared public directories, such as {@code |
| 318 | Music/}, {@code Pictures/}, and {@code Ringtones/}.</p> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 319 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 320 | <p>To get a {@link java.io.File} representing the appropriate public directory, call {@link |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 321 | android.os.Environment#getExternalStoragePublicDirectory(String) |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 322 | getExternalStoragePublicDirectory()}, passing it the type of directory you want, such as |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 323 | {@link android.os.Environment#DIRECTORY_MUSIC}, {@link android.os.Environment#DIRECTORY_PICTURES}, |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 324 | {@link android.os.Environment#DIRECTORY_RINGTONES}, or others. By saving your files to the |
| 325 | corresponding media-type directory, |
| 326 | the system's media scanner can properly categorize your files in the system (for |
| 327 | instance, ringtones appear in system settings as ringtones, not as music).</p> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 328 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 329 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 330 | <p>For example, here's a method that creates a directory for a new photo album in |
| 331 | the public pictures directory:</p> |
| 332 | |
| 333 | <pre> |
| 334 | public File getAlbumStorageDir(String albumName) { |
| 335 | // Get the directory for the user's public pictures directory. |
| 336 | File file = new File(Environment.getExternalStoragePublicDirectory( |
| 337 | Environment.DIRECTORY_PICTURES), albumName); |
| 338 | if (!file.mkdirs()) { |
| 339 | Log.e(LOG_TAG, "Directory not created"); |
| 340 | } |
| 341 | return file; |
| 342 | } |
| 343 | </pre> |
| 344 | |
| 345 | |
| 346 | |
| 347 | <h3 id="AccessingExtFiles">Saving files that are app-private</h3> |
| 348 | |
| 349 | <p>If you are handling files that are not intended for other apps to use |
| 350 | (such as graphic textures or sound effects used by only your app), you should use |
| 351 | a private storage directory on the external storage by calling {@link |
| 352 | android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}. |
| 353 | This method also takes a <code>type</code> argument to specify the type of subdirectory |
| 354 | (such as {@link android.os.Environment#DIRECTORY_MOVIES}). If you don't need a specific |
| 355 | media directory, pass <code>null</code> to receive |
| 356 | the root directory of your app's private directory.</p> |
| 357 | |
| 358 | <p>Beginning with Android 4.4, reading or writing files in your app's private |
| 359 | directories does not require the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} |
| 360 | or {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} |
| 361 | permissions. So you can declare the permission should be requested only on the lower versions |
| 362 | of Android by adding the <a |
| 363 | href="{@docRoot}guide/topics/manifest/uses-permission-element.html#maxSdk">{@code maxSdkVersion}</a> |
| 364 | attribute:</p> |
| 365 | <pre> |
| 366 | <manifest ...> |
| 367 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" |
| 368 | android:maxSdkVersion="18" /> |
| 369 | ... |
| 370 | </manifest> |
| 371 | </pre> |
| 372 | |
| 373 | <p class="note"><strong>Note:</strong> |
| 374 | When the user uninstalls your application, this directory and all its contents are deleted. |
| 375 | Also, the system media scanner does not read files in these directories, so they are not accessible |
| 376 | from the {@link android.provider.MediaStore} content provider. As such, you <b>should not |
| 377 | use these directories</b> for media that ultimately belongs to the user, such as photos |
| 378 | captured or edited with your app, or music the user has purchased with your app—those |
| 379 | files should be <a href="#SavingSharedFiles">saved in the public directories</a>.</p> |
| 380 | |
| 381 | <p>Sometimes, a device that has allocated a partition of the |
| 382 | internal memory for use as the external storage may also offer an SD card slot. |
| 383 | When such a device is running Android 4.3 and lower, the {@link |
| 384 | android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} method provides |
| 385 | access to only the internal partition and your app cannot read or write to the SD card. |
| 386 | Beginning with Android 4.4, however, you can access both locations by calling |
| 387 | {@link android.content.Context#getExternalFilesDirs getExternalFilesDirs()}, |
| 388 | which returns a {@link |
| 389 | java.io.File} array with entries each location. The first entry in the array is considered |
| 390 | the primary external storage and you should use that location unless it's full or |
| 391 | unavailable. If you'd like to access both possible locations while also supporting Android |
| 392 | 4.3 and lower, use the <a href="{@docRoot}tools/support-library/index.html">support library's</a> |
| 393 | static method, {@link android.support.v4.content.ContextCompat#getExternalFilesDirs |
| 394 | ContextCompat.getExternalFilesDirs()}. This also returns a {@link |
| 395 | java.io.File} array, but always includes only one entry on Android 4.3 and lower.</p> |
| 396 | |
| 397 | <p class="caution"><strong>Caution</strong> Although the directories provided by {@link |
| 398 | android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} and {@link |
| 399 | android.content.Context#getExternalFilesDirs getExternalFilesDirs()} are not accessible by the |
| 400 | {@link android.provider.MediaStore} content provider, other apps with the {@link |
| 401 | android.Manifest.permission#READ_EXTERNAL_STORAGE} permission can access all files on the external |
| 402 | storage, including these. If you need to completely restrict access for your files, you should |
| 403 | instead write your files to the <a href="#filesInternal">internal storage</a>.</p> |
| 404 | |
| 405 | |
| 406 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 407 | |
| 408 | |
| 409 | <h3 id="ExternalCache">Saving cache files</h3> |
| 410 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 411 | <p>To open a {@link java.io.File} that represents the |
| 412 | external storage directory where you should save cache files, call {@link |
| 413 | android.content.Context#getExternalCacheDir()}. If the user uninstalls your |
| 414 | application, these files will be automatically deleted.</p> |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 415 | |
Scott Main | d13afd6 | 2013-12-12 19:01:24 -0800 | [diff] [blame] | 416 | <p>Similar to {@link android.support.v4.content.ContextCompat#getExternalFilesDirs |
| 417 | ContextCompat.getExternalFilesDirs()}, mentioned above, you can also access a cache directory on |
| 418 | a secondary external storage (if available) by calling |
| 419 | {@link android.support.v4.content.ContextCompat#getExternalCacheDirs |
| 420 | ContextCompat.getExternalCacheDirs()}.</p> |
| 421 | |
| 422 | <p class="note"><strong>Tip:</strong> |
| 423 | To preserve file space and maintain your app's performance, |
| 424 | it's important that you carefully manage your cache files and remove those that aren't |
| 425 | needed anymore throughout your app's lifecycle.</p> |
| 426 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 427 | |
| 428 | |
| 429 | |
| 430 | <h2 id="db">Using Databases</h2> |
| 431 | |
| 432 | <p>Android provides full support for <a href="http://www.sqlite.org/">SQLite</a> databases. |
| 433 | Any databases you create will be accessible by name to any |
| 434 | class in the application, but not outside the application.</p> |
| 435 | |
| 436 | <p>The recommended method to create a new SQLite database is to create a subclass of {@link |
| 437 | android.database.sqlite.SQLiteOpenHelper} and override the {@link |
| 438 | android.database.sqlite.SQLiteOpenHelper#onCreate(SQLiteDatabase) onCreate()} method, in which you |
| 439 | can execute a SQLite command to create tables in the database. For example:</p> |
| 440 | |
| 441 | <pre> |
Scott Main | c4367e5 | 2010-09-03 11:03:42 -0700 | [diff] [blame] | 442 | public class DictionaryOpenHelper extends SQLiteOpenHelper { |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 443 | |
| 444 | private static final int DATABASE_VERSION = 2; |
| 445 | private static final String DICTIONARY_TABLE_NAME = "dictionary"; |
| 446 | private static final String DICTIONARY_TABLE_CREATE = |
| 447 | "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" + |
| 448 | KEY_WORD + " TEXT, " + |
| 449 | KEY_DEFINITION + " TEXT);"; |
| 450 | |
| 451 | DictionaryOpenHelper(Context context) { |
| 452 | super(context, DATABASE_NAME, null, DATABASE_VERSION); |
| 453 | } |
| 454 | |
| 455 | @Override |
| 456 | public void onCreate(SQLiteDatabase db) { |
| 457 | db.execSQL(DICTIONARY_TABLE_CREATE); |
| 458 | } |
| 459 | } |
| 460 | </pre> |
| 461 | |
| 462 | <p>You can then get an instance of your {@link android.database.sqlite.SQLiteOpenHelper} |
| 463 | implementation using the constructor you've defined. To write to and read from the database, call |
| 464 | {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase()} and {@link |
| 465 | android.database.sqlite.SQLiteOpenHelper#getReadableDatabase()}, respectively. These both return a |
| 466 | {@link android.database.sqlite.SQLiteDatabase} object that represents the database and |
| 467 | provides methods for SQLite operations.</p> |
| 468 | |
| 469 | <div class="sidebox-wrapper"> |
| 470 | <div class="sidebox"> |
| 471 | <p>Android does not impose any limitations beyond the standard SQLite concepts. We do recommend |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 472 | including an autoincrement value key field that can be used as a unique ID to |
| 473 | quickly find a record. This is not required for private data, but if you |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 474 | implement a <a href="{@docRoot}guide/topics/providers/content-providers.html">content provider</a>, |
| 475 | you must include a unique ID using the {@link android.provider.BaseColumns#_ID BaseColumns._ID} |
| 476 | constant. |
| 477 | </p> |
| 478 | </div> |
| 479 | </div> |
| 480 | |
| 481 | <p>You can execute SQLite queries using the {@link android.database.sqlite.SQLiteDatabase} |
| 482 | {@link |
| 483 | android.database.sqlite.SQLiteDatabase#query(boolean,String,String[],String,String[],String,String,String,String) |
| 484 | query()} methods, which accept various query parameters, such as the table to query, |
| 485 | the projection, selection, columns, grouping, and others. For complex queries, such as |
| 486 | those that require column aliases, you should use |
| 487 | {@link android.database.sqlite.SQLiteQueryBuilder}, which provides |
| 488 | several convienent methods for building queries.</p> |
| 489 | |
| 490 | <p>Every SQLite query will return a {@link android.database.Cursor} that points to all the rows |
| 491 | found by the query. The {@link android.database.Cursor} is always the mechanism with which |
| 492 | you can navigate results from a database query and read rows and columns.</p> |
| 493 | |
| 494 | <p>For sample apps that demonstrate how to use SQLite databases in Android, see the |
| 495 | <a href="{@docRoot}resources/samples/NotePad/index.html">Note Pad</a> and |
| 496 | <a href="{@docRoot}resources/samples/SearchableDictionary/index.html">Searchable Dictionary</a> |
| 497 | applications.</p> |
| 498 | |
| 499 | |
| 500 | <h3 id="dbDebugging">Database debugging</h3> |
| 501 | |
| 502 | <p>The Android SDK includes a {@code sqlite3} database tool that allows you to browse |
| 503 | table contents, run SQL commands, and perform other useful functions on SQLite |
Scott Main | 50e990c | 2012-06-21 17:14:39 -0700 | [diff] [blame] | 504 | databases. See <a href="{@docRoot}tools/help/adb.html#sqlite">Examining sqlite3 |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 505 | databases from a remote shell</a> to learn how to run this tool. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 506 | </p> |
| 507 | |
| 508 | |
Scott Main | 779de5c | 2010-04-22 12:30:25 -0700 | [diff] [blame] | 509 | |
| 510 | |
| 511 | |
| 512 | <h2 id="netw">Using a Network Connection</h2> |
| 513 | |
| 514 | <!-- TODO MAKE THIS USEFUL!! --> |
| 515 | |
| 516 | <p>You can use the network (when it's available) to store and retrieve data on your own web-based |
| 517 | services. To do network operations, use classes in the following packages:</p> |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 518 | |
| 519 | <ul class="no-style"> |
| 520 | <li><code>{@link java.net java.net.*}</code></li> |
| 521 | <li><code>{@link android.net android.net.*}</code></li> |
| 522 | </ul> |