Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android Data

Android Data

Android gives you several options to store your data, and the Android community gives you even more. This talk will cover the many different data storage options available to you and the reasons you might choose one over the other. We'll look at implementation details, common pitfalls, and examples of how you might use each in the real world.

Michael Pardo

September 21, 2014
Tweet

More Decks by Michael Pardo

Other Decks in Programming

Transcript

  1. SharedPreferences • Stores key-value pairs as XML • Good for

    a relatively small collection • Primitive data types only
  2. // Provide a name for the preferences file name SharedPreferences

    prefs = getSharedPreferences( PREFS_NAME, Context.MODE_PRIVATE);
  3. // Uses the activity's class name as the preferences file

    name SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
  4. // Uses the activity's class name as the preferences file

    name SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); ! // Same as above SharedPreferences prefs = getSharedPreferences( activity.getLocalClassName(), Context.MODE_PRIVATE);
  5. // Use package name as the preferences file name SharedPreferences

    prefs = PreferenceManager.getDefaultSharedPreferences( context);
  6. // Use package name as the preferences file name SharedPreferences

    prefs = PreferenceManager.getDefaultSharedPreferences( context); ! // Same as above SharedPreferences prefs = getSharedPreferences( getPackageName() + "_preferences", Context.MODE_PRIVATE);
  7. // Get instance of SharedPreferences SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); !

    // Retrieve stored value boolean firstRun = prefs.getBoolean("firstRun", true);
  8. // Get instance of SharedPreferences SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE); !

    // Retrieve stored value boolean firstRun = prefs.getBoolean("firstRun", true); ! if (firstRun) { // Get instance of editor and persist value SharedPreferences.Editor editor = prefs.edit(); editor.putInt("firstRun", false); editor.commit(); }
  9. Complex Preferences // Get instance of ComplexPreferences ComplexPreferences prefs =

    ComplexPreferences.getComplexPreferences( this, PREFS_NAME, Context.MODE_PRIVATE);
  10. Complex Preferences // Get instance of ComplexPreferences ComplexPreferences prefs =

    ComplexPreferences.getComplexPreferences( this, PREFS_NAME, Context.MODE_PRIVATE); ! // Persist Inventory prefs.putObject("inventory", inventory); prefs.commit();
  11. Complex Preferences // Get instance of ComplexPreferences ComplexPreferences prefs =

    ComplexPreferences.getComplexPreferences( this, PREFS_NAME, Context.MODE_PRIVATE); ! // Persist Inventory prefs.putObject("inventory", inventory); prefs.commit(); ! // Retrieve Inventory Inventory inventory = prefs.getObject("inventory", Inventory.class);
  12. SimpleSharedPreferences // Create instance of SimpleSharedPrefernces SimpleSharedPreferences prefs = new

    SimpleSharedPreferences(context); ! // Retrieve stored value boolean firstRun = prefs.getBoolean("firstRun", true);
  13. SimpleSharedPreferences // Create instance of SimpleSharedPrefernces SimpleSharedPreferences prefs = new

    SimpleSharedPreferences(context); ! // Retrieve stored value boolean firstRun = prefs.getBoolean("firstRun", true); ! if (firstRun) { // Persist value prefs.putBoolean("firstRun", false); }
  14. Typed Preferences // Get instance of SharedPreferences SharedPreferences prefs =

    getPreferences(Context.MODE_PRIVATE); ! // Create instance of BooleanPreference BooleanPreference firstRun = new BooleanPreference(prefs, "firstRun", true);
  15. Typed Preferences // Get instance of SharedPreferences SharedPreferences prefs =

    getPreferences(Context.MODE_PRIVATE); ! // Create instance of BooleanPreference BooleanPreference firstRun = new BooleanPreference(prefs, "firstRun", true); ! // Retrieve stored value if (firstRun.get()) { // Persist value firstRun.set(true); }
  16. Filesystem • Same as Java I/O API • Good for

    large amounts of data • Internal and external storage
  17. Internal Storage • Always available • Privately accessible by default

    • All files removed from internal storage upon uninstallation
  18. External Storage • Not always available • Publicly accessible •

    All files removed from getExternalFilesDir() upon uninstallation
  19. JSONObject gameState = game.getState(); ! String fileName = "game_state.json"; String

    fileContents = gameState.toString(); ! // Use context.openFileOutput() to open an output stream FileOutputStream fos = openFileOutput(fileName, Context.MODE_PRIVATE); ! fos.write(fileContents.getBytes()); fos.close();
  20. JSONObject gameState = game.getState(); ! String fileName = "game_state.json"; String

    fileContents = gameState.toString(); ! // Use context.getFilesDir() to open an output stream FileOutputStream fos = new FileOutputStream(new File(getFilesDir(), fileName)); ! fos.write(fileContents.getBytes()); fos.close();
  21. <!-- Read permission is implicit. --> <manifest ...> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"

    /> ... </manifest> ! ! <!-- Will be required in a future release, but not at the moment. --> <manifest ...> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ... </manifest>
  22. public boolean isExternalStorageWritable() { String state = Environment.getExternalStorageState(); return state.equals(Environment.MEDIA_MOUNTED);

    } ! public boolean isExternalStorageReadable() { String state = Environment.getExternalStorageState(); return state.equals(Environment.MEDIA_MOUNTED) || state.equals(Environment.MEDIA_MOUNTED_READ_ONLY); }
  23. context.openFileOutput(String name, int mode); ! context.openFileInput(String name); ! context.getFileStreamPath(String name);

    ! context.getFilesDir(); ! context.getCacheDir(); ! Environment.getDownloadCacheDirectory(); ! Environment.getExternalStorageDirectory(); ! Environment.getExternalStoragePublicDirectory(String type); ! Environment.getExternalStorageState();
  24. Apache Commons IO // Get URL content InputStream in =

    new URL( "http://developer.android.com" ).openStream(); try { String html = IOUtils.toString(in); } finally { IOUtils.closeQuietly(in); }
  25. Apache Commons IO // Get file lines File file =

    new File(getFilesDir() , "todo.txt"); List<String> lines = FileUtils.readLines(file, "UTF-8");
  26. Apache Commons IO String filename = "/data/data/com.michaelpardo.app/cache/../todo.txt"; String normalized =

    FilenameUtils.normalize(filename); // result is "/data/data/com.michaelpardo.app/todo.txt"
  27. Guava // Read the lines of a UTF-8 text file

    ImmutableList<String> lines = Files.asCharSource(file, Charsets.UTF_8) .readLines();
  28. Guava // Count distinct word occurrences in a file Multiset<String>

    wordOccurrences = HashMultiset.create( Splitter.on(CharMatcher.WHITESPACE) .trimResults() .omitEmptyStrings() .split(Files.asCharSource(file, Charsets.UTF_8).read()));
  29. Guava // Copy the data from a URL to a

    file Resources.asByteSource(url).copyTo(Files.asByteSink(file));
  30. public final class PostContract { public PostContract() {} ! public

    static abstract class Post implements BaseColumns { public static final String TABLE_NAME = "posts"; public static final String COLUMN_NAME_TITLE = "title"; public static final String COLUMN_NAME_AUTHOR_ID = “author_id"; ... } }
  31. public class PostsDbHelper extends SQLiteOpenHelper { public static final int

    DATABASE_VERSION = 1; public static final String DATABASE_NAME = "Posts.db"; ! public FeedReaderDbHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } ! public void onCreate(SQLiteDatabase db) { db.execSQL(SQL_CREATE_ENTRIES); } ! public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL(SQL_DELETE_ENTRIES); onCreate(db); } ! public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { onUpgrade(db, oldVersion, newVersion); } }
  32. // Create instance of database helper PostsDbHelper mDbHelper = new

    PostsDbHelper(getContext()); ! // Get writable database SQLiteDatabase db = mDbHelper.getWritableDatabase();
  33. // Create array of columns to retrieve String[] projection =

    { Post._ID, Post.COLUMN_NAME_TITLE, ... };
  34. // Create array of columns to retrieve String[] projection =

    { Post._ID, Post.COLUMN_NAME_TITLE, ... }; ! // Retrieve cursor Cursor c = db.query( Post.TABLE_NAME, projection, selection, selectionArgs, null, // groupBy null, // having null, // orderBy null // limit );
  35. // Move to first row cursor.moveToFirst(); ! // Get column

    index int index = cursor.getColumnIndexOrThrow(Post._ID);
  36. // Move to first row cursor.moveToFirst(); ! // Get column

    index int index = cursor.getColumnIndexOrThrow(Post._ID); ! // Get column value long id = cursor.getLong(index);
  37. // Move to first row cursor.moveToFirst(); ! // Get column

    index int index = cursor.getColumnIndexOrThrow(Post._ID); ! // Get column value long id = cursor.getLong(index); ! // Close cursor when finished cursor.close();
  38. // Create instance of ContentValues and set values ContentValues values

    = new ContentValues(); values.put(Post.COLUMN_NAME_TITLE, title); values.put(Post.COLUMN_NAME_AUTHOR_ID, authorId);
  39. // Create instance of ContentValues and set values ContentValues values

    = new ContentValues(); values.put(Post.COLUMN_NAME_TITLE, title); values.put(Post.COLUMN_NAME_AUTHOR_ID, authorId); ! // Insert row using ContentValues long newRowId = db.insert( Post.TABLE_NAME, null, values );
  40. // Create instance of ContentValues and set values ContentValues values

    = new ContentValues(); values.put(Post.COLUMN_NAME_AUTHOR_ID, authorId);
  41. // Create instance of ContentValues and set values ContentValues values

    = new ContentValues(); values.put(Post.COLUMN_NAME_AUTHOR_ID, authorId); ! // Create selection definition String selection = Post.COLUMN_NAME_AUTHOR_ID + " LIKE ?"; String[] selectionArgs = { String.valueOf(oldAuthorId) };
  42. // Create instance of ContentValues and set values ContentValues values

    = new ContentValues(); values.put(Post.COLUMN_NAME_AUTHOR_ID, authorId); ! // Create selection definition String selection = Post.COLUMN_NAME_AUTHOR_ID + " LIKE ?"; String[] selectionArgs = { String.valueOf(oldAuthorId) }; ! // Update rows using ContentValues and selection int count = db.update( Post.TABLE_NAME, values, selection, selectionArgs );
  43. // Create selection definition String selection = Post.COLUMN_NAME_AUTHOR_ID + "

    LIKE ?"; String[] selectionArgs = { String.valueOf(authorId) };
  44. // Create selection definition String selection = Post.COLUMN_NAME_AUTHOR_ID + "

    LIKE ?"; String[] selectionArgs = { String.valueOf(authorId) }; ! // Delete rows using selection db.delete( Post.TABLE_NAME, selection, selectionArgs );
  45. ActiveAndroid // Query List<Post> posts = new Select().from(Post.class).execute(); ! //

    Save or update Post post = new Post(); post.setTitle("ActiveAndroid"); post.setAuthor(user); post.save();
  46. ActiveAndroid // Query List<Post> posts = new Select().from(Post.class).execute(); ! //

    Save or update Post post = new Post(); post.setTitle("ActiveAndroid"); post.setAuthor(user); post.save(); ! // Delete post.delete();
  47. greenDAO Schema schema = new Schema(1, "de.greenrobot.posts"); ! Entity post

    = schema.addEntity("post"); post.addIdProperty(); post.addStringProperty("title"); ! Property userIdProperty = user.addLongProperty("author").getProperty(); post.addToOne(user, userIdProperty); ! DaoGenerator daoGenerator = new DaoGenerator(); daoGenerator.generateAll(schema, "../MyProject/src-gen");
  48. greenDAO // Query List<Post> posts = userDao.queryBuilder().list(); ! // Save

    Post post = new Post(); post.setTitle("greenDAO"); post.setAuthor(user); daoSession.insert(post);
  49. greenDAO // Query List<Post> posts = userDao.queryBuilder().list(); ! // Save

    Post post = new Post(); post.setTitle("greenDAO"); post.setAuthor(user); daoSession.insert(post); ! // Update post.setModifiedDate(new Date()); daoSession.update(post);
  50. greenDAO // Query List<Post> posts = userDao.queryBuilder().list(); ! // Save

    Post post = new Post(); post.setTitle("greenDAO"); post.setAuthor(user); daoSession.insert(post); ! // Update post.setModifiedDate(new Date()); daoSession.update(post); ! // Delete daoSession.delete(post);
  51. OrmLite @DatabaseTable(tableName = "posts") public class Post { @DatabaseField private

    String title; @DatabaseField private User author; ... }
  52. OrmLite // Query List<Post> posts = postDao.queryForAll(); ! // Save

    Post post = new Post(); post.setTitle("ORMLite"); post.setAuthor(user); postDao.create(post);
  53. OrmLite // Query List<Post> posts = postDao.queryForAll(); ! // Save

    Post post = new Post(); post.setTitle("ORMLite"); post.setAuthor(user); postDao.create(post); ! // Update post.setModifiedDate(new Date()); postDao.update(post);
  54. OrmLite // Query List<Post> posts = postDao.queryForAll(); ! // Save

    Post post = new Post(); post.setTitle("ORMLite"); post.setAuthor(user); postDao.create(post); ! // Update post.setModifiedDate(new Date()); postDao.update(post); ! // Delete postDao.delete(post);
  55. SugarORM // Query List<Post> posts = Post.find(Post.class); ! // Save

    or update Post post = new Post(); post.setTitle("SugarORM"); post.setAuthor(user); SugarRecord.save(post);
  56. SugarORM // Query List<Post> posts = Post.find(Post.class); ! // Save

    or update Post post = new Post(); post.setTitle("SugarORM"); post.setAuthor(user); SugarRecord.save(post); ! // Delete SugarRecord.delete(post);
  57. Network • File sync or mobile backend • Cross-device storage

    • Many storage options • Not always available
  58. BaasBox • Administration console • Users management • Content management

    • File management • “Friendship” • DB management • Push notifications • API access management
  59. Helios • Data synchronization • Push notifications • In-App purchases

    • Logging and Analytics • Passbook & Newsstand (iOS)
  60. Kinvey • Cloud datastore • Local datastore • User management

    • File management • Push notifications • Location content • Backend services • Encryption • External data sources
  61. NoSQL • Key value pairs or documents • Simple design

    • Non-relational • Implementations vary
  62. Couchbase Lite • JSON document store • Full query API

    • Server and peer-to-peer replication
  63. SnappyDB • Key value store • Use primitive type and

    array values • Based on Google’s LevelDB • Uses Snappy compression and Kryo serialization
  64. WaspDB • Key value store • Use complex key and

    value types • Uses Kryo serialization
  65. Easy to use Complex data A lot of data Distributed

    SharedPreferences Filesystem SQLite Network NoSQL