SlideShare ist ein Scribd-Unternehmen logo
1 von 63
Downloaden Sie, um offline zu lesen
Better Data Persistence on Android
Eric Maxwell

Credible Software
What to Expect
• Android Storage Options
• Focus on SQLite / Database Storage
• Make it better using the Realm Mobile Database
Android Storage Options
• Shared Preferences
Android Storage Options
• Shared Preferences
• Disk Storage
• Internal
• External
Android Storage Options
• Shared Preferences
• Disk Storage
• Internal
• External
• Relational Database w/ SQLite
SQLite
• Relational Database on the device
• android.database.sqlite.SQLiteDatabase
• Perform insert, query, update, delete, begin/end
transaction
• android.database.sqlite.SQLiteOpenHelper
• Handle Create, Upgrade events
Nae Nae Assistant App
• List of Nae Nae Lyrics
• Add New
• Delete
• Persistent across launches
View Layout
<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical" >



<GridLayout

android:id="@+id/lyricButtons"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:padding="10dp">



<Button

android:id="@+id/watch_me"

android:text="@string/lyric_watch_me"

android:onClick="add"/>



<Button

android:id="@+id/whip"

android:text="@string/lyric_whip"

android:onClick="add"/>



<Button

android:id="@+id/nea"

android:text="@string/lyric_nea"

android:onClick="add"/>



<Button

android:id="@+id/bop"

android:text="@string/lyric_bop"

android:onClick="add"/>



</GridLayout>



<ListView

android:id="@android:id/list"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:text="@string/hello_world" />



</LinearLayout>
Simple Data Object
public class Lyric {


private long id;

private String lyricText;



// Getters / Setters...



// Will be used by the ArrayAdapter in the ListView

@Override

public String toString() {

return lyricText;

}

}
Activity - Lifecycle Events
public class NaeNaeActivity extends ListActivity {



private LyricDataSource datasource;



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_naenae);



datasource = new LyricDataSource(this);

datasource.open();



List<Lyric> values = datasource.getAllLyrics();



// Use the SimpleCursorAdapter to show the

// elements in a ListView

ArrayAdapter<Lyric> adapter = new ArrayAdapter<Lyric>(this,

android.R.layout.simple_list_item_1, values);

setListAdapter(adapter);


}



@Override

protected void onResume() {

super.onResume();

datasource.open();

}



@Override

protected void onPause() {

super.onPause();

datasource.close();

}
...
}
The datasource gets
initialized and opened on
create and is then used to
get all of the lyrics and
placed into an array
adapter.
The datasource is opened
and closed on resume and
stop.
Activity - Events Add/Remove
public void add(View view) {

String lyricText = ((Button) view).getText().toString();

if (!TextUtils.isEmpty(lyricText)) {

ArrayAdapter<Lyric> adapter = getListAdapter();

Lyric lyric = null;

lyric = datasource.createLyric(lyricText);

adapter.add(lyric);

}

}



public void delete (int position) {

if (getListAdapter().getCount() > 0) {

ArrayAdapter<Lyric> adapter = getListAdapter();

Lyric lyric = adapter.getItem(position);

datasource.deleteLyric(lyric);

adapter.remove(lyric);

}

}




@Override

@SuppressWarnings("unchecked")

public ArrayAdapter<Lyric> getListAdapter() {

return (ArrayAdapter<Lyric>) super.getListAdapter();

}


Add
Remove
Custom SQLiteOpenHelper
public class MySQLiteHelper extends SQLiteOpenHelper {



public static final String TABLE_LYRICS = "lyrics";

public static final String COLUMN_ID = "_id";

public static final String COLUMN_LYRIC = "lyric";



private static final String DATABASE_NAME = "lyric.db";

private static final int DATABASE_VERSION = 1;



// Database creation sql statement

private static final String DATABASE_CREATE = "create table "

+ TABLE_LYRICS + "( " + COLUMN_ID

+ " integer primary key autoincrement, " + COLUMN_LYRIC

+ " text not null);";



public MySQLiteHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}



@Override

public void onCreate(SQLiteDatabase database) {

database.execSQL(DATABASE_CREATE);

}



@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

Log.w(MySQLiteHelper.class.getName(),

"Upgrading database from version " + oldVersion + " to "

+ newVersion + ", which will destroy all old data");

db.execSQL("DROP TABLE IF EXISTS " + TABLE_LYRICS);

onCreate(db);

}



}
Lyric Datasource
public class LyricDataSource {



// Database fields

private SQLiteDatabase database;

private MySQLiteHelper dbHelper;

private String[] allColumns = { MySQLiteHelper.COLUMN_ID,

MySQLiteHelper.COLUMN_LYRIC};



public LyricDataSource(Context context) {

dbHelper = new MySQLiteHelper(context);

}



public void open() throws SQLException {

database = dbHelper.getWritableDatabase();

}



public void close() {

dbHelper.close();

}
public List<Lyric> getAllLyrics() {

List<Lyric> lyrics = new ArrayList<Lyric>();



Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, null, null, null, null,
MySQLiteHelper.COLUMN_ID);

cursor.moveToFirst();

while (!cursor.isAfterLast()) {

Lyric lyric = cursorToLyric(cursor);

lyrics.add(lyric);

cursor.moveToNext();

}

// Make sure to close the cursor

cursor.close();

return lyrics;

}
public Lyric createLyric(String lyric) {

ContentValues values = new ContentValues();

values.put(MySQLiteHelper.COLUMN_LYRIC, lyric);

long insertId = database.insert(MySQLiteHelper.TABLE_LYRICS, null,

values);

Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, MySQLiteHelper.COLUMN_ID + " = " +
insertId, null,

null, null, null);

cursor.moveToFirst();

Lyric newLyric = cursorToLyric(cursor);

cursor.close();

return newLyric;

}



public void deleteLyric(Lyric lyric) {

long id = lyric.getId();

database.delete(MySQLiteHelper.TABLE_LYRICS,
MySQLiteHelper.COLUMN_ID

+ " = " + id, null);

}



public Lyric getLyricByValue(String lyricText) {

Lyric lyric = null;

Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, MySQLiteHelper.COLUMN_LYRIC + " = '" +
lyricText + "'" , null, null, null, null);

cursor.moveToFirst();

if (!cursor.isAfterLast()) {

lyric = cursorToLyric(cursor);

}

// Make sure to close the cursor

cursor.close();

return lyric;

}


private Lyric cursorToLyric(Cursor cursor) {

Lyric lyric = new Lyric();

lyric.setId(cursor.getLong(0));

lyric.setLyricText(cursor.getString(1));

return lyric;

}
Using SQLite Pros
• No additional dependencies
• Built in programatic transaction management
• Built in creation and upgrade event handling
What happens when you add a couple fields?
public class MySQLiteHelper extends SQLiteOpenHelper {



public static final String TABLE_LYRICS = "lyrics";

public static final String COLUMN_ID = "_id";

public static final String COLUMN_LYRIC = "lyric";



private static final String DATABASE_NAME = "lyric.db";

private static final int DATABASE_VERSION = 1;



// Database creation sql statement

private static final String DATABASE_CREATE = "create table "

+ TABLE_LYRICS + "( " + COLUMN_ID

+ " integer primary key autoincrement, " + COLUMN_LYRIC

+ " text not null);";



public MySQLiteHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}



@Override

public void onCreate(SQLiteDatabase database) {

database.execSQL(DATABASE_CREATE);

}



@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

Log.w(MySQLiteHelper.class.getName(),

"Upgrading database from version " + oldVersion + " to "

+ newVersion + ", which will destroy all old data");

db.execSQL("DROP TABLE IF EXISTS " + TABLE_LYRICS);

onCreate(db);

}



}
Update the data model
public class Lyric {

private long id;

private String lyricText;
private String source;
private boolean isChorus;



public long getId() {

return id;

}



public void setId(long id) {

this.id = id;

}



public String getLyricText() {

return lyricText;

}



public void setLyricText(String lyricText) {

this.lyricText = lyricText;

}
// Additional Getter/Setters



// Will be used by the ArrayAdapter in the ListView

@Override

public String toString() {

return lyricText;

}

}
Update the Datasource
public class LyricDataSource {



// Database fields

private SQLiteDatabase database;

private MySQLiteHelper dbHelper;

private String[] allColumns = { MySQLiteHelper.COLUMN_ID,

MySQLiteHelper.COLUMN_LYRIC,
MySQLiteHelper.COLUMN_SOURCE,
MySQLiteHelper.COLUMN_CHORUS};



public LyricDataSource(Context context) {

dbHelper = new MySQLiteHelper(context);

}



public void open() throws SQLException {

database = dbHelper.getWritableDatabase();

}



public void close() {

dbHelper.close();

}
public List<Lyric> getAllLyrics() {

List<Lyric> lyrics = new ArrayList<Lyric>();



Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, null, null, null, null,
MySQLiteHelper.COLUMN_ID);

cursor.moveToFirst();

while (!cursor.isAfterLast()) {

Lyric lyric = cursorToLyric(cursor);

lyrics.add(lyric);

cursor.moveToNext();

}

// Make sure to close the cursor

cursor.close();

return lyrics;

}
public Lyric createLyric(String lyric) {

ContentValues values = new ContentValues();

values.put(MySQLiteHelper.COLUMN_LYRIC, lyric);

values.put(MySQLiteHelper.COLUMN_CHORUS, isChorus ? 1 : 0);

values.put(MySQLiteHelper.COLUMN_SOURCE, source);

long insertId = database.insert(MySQLiteHelper.TABLE_LYRICS, null,

values);

Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId,
null,

null, null, null);

cursor.moveToFirst();

Lyric newLyric = cursorToLyric(cursor);

cursor.close();

return newLyric;

}



public void deleteLyric(Lyric lyric) {

long id = lyric.getId();

database.delete(MySQLiteHelper.TABLE_LYRICS, MySQLiteHelper.COLUMN_ID

+ " = " + id, null);

}



public Lyric getLyricByValue(String lyricText) {

Lyric lyric = null;

Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, MySQLiteHelper.COLUMN_LYRIC + " = '" +
lyricText + "'" , null, null, null, null);

cursor.moveToFirst();

if (!cursor.isAfterLast()) {

lyric = cursorToLyric(cursor);

}

// Make sure to close the cursor

cursor.close();

return lyric;

}


private Lyric cursorToLyric(Cursor cursor) {

Lyric lyric = new Lyric();

lyric.setId(cursor.getLong(0));

lyric.setLyricText(cursor.getString(1));
lyric.setChorus(cursor.getInt(2) == 1);

lyric.setSource(cursor.getString(3));

return lyric;

}
Add the columns to our SQLiteOpenHelper
public class MySQLiteHelper extends SQLiteOpenHelper {



private static final String DATABASE_NAME = "lyric.db";

private static final int DATABASE_VERSION = 1;

public static final String COLUMN_ID = "_id";



public static final String TABLE_LYRICS = "lyrics";

public static final String COLUMN_LYRIC = "lyric";

public static final String COLUMN_SOURCE = "source";



public static final String COLUMN_CHORUS = "isChorus";





// Database creation sql statement

private static final String DATABASE_CREATE =



"create table "

+ TABLE_LYRICS + "( " + COLUMN_ID

+ " integer primary key autoincrement, “ + COLUMN_LYRIC + " text
not null, "

+ COLUMN_CHORUS + " text, "

+ COLUMN_SOURCE + " integer, "

+ " ); "

;



...



}
How about a second table
public class MySQLiteHelper extends SQLiteOpenHelper {



private static final String DATABASE_NAME = "lyric.db";

private static final int DATABASE_VERSION = 1;

public static final String COLUMN_ID = "_id";



public static final String TABLE_LYRICS = "lyrics";

public static final String COLUMN_LYRIC = "lyric";

public static final String COLUMN_SOURCE = "source";

public static final String COLUMN_CHORUS = "isChorus";



public static final String TABLE_ARTISTS = "artists";

public static final String COLUMN_ARTIST_NAME = "name";

public static final String COLUMN_ARTIST_LABEL = "label";



// Database creation sql statement

private static final String DATABASE_CREATE =



"create table "

+ TABLE_LYRICS + "( " + COLUMN_ID + " integer primary key autoincrement, "

+ COLUMN_LYRIC + " text not null, "

+ COLUMN_CHORUS + " text, "

+ COLUMN_SOURCE + " integer "

+ " ); "

+

"create table "

+ TABLE_ARTISTS + "( " + COLUMN_ID + " integer primary key autoincrement, "

+ COLUMN_ARTIST_NAME + " text not null, "

+ COLUMN_ARTIST_LABEL + " text "

+ " ); "

;




...



}
Or a many to many relationship
public class MySQLiteHelper extends SQLiteOpenHelper {



private static final String DATABASE_NAME = "lyric.db";

private static final int DATABASE_VERSION = 1;

public static final String COLUMN_ID = "_id";



public static final String TABLE_LYRICS = "lyrics";

public static final String COLUMN_LYRIC = "lyric";

public static final String COLUMN_SOURCE = "source";

public static final String COLUMN_CHORUS = "isChorus";



public static final String TABLE_ARTISTS = "artists";

public static final String COLUMN_ARTIST_NAME = "name";

public static final String COLUMN_ARTIST_LABEL = “label";
public static final String TABLE_LYRIC_ARTIST = "lyric_artist";

public static final String COLUMN_LYRIC_ID = "lyric_id";

public static final String COLUMN_ARTIST_ID = "artist_id";





// Database creation sql statement

private static final String DATABASE_CREATE =



"create table "

+ TABLE_LYRICS + "( " + COLUMN_ID + " integer primary key autoincrement, "

+ COLUMN_LYRIC + " text not null, "

+ COLUMN_CHORUS + " text, "

+ COLUMN_SOURCE + " integer "

+ " ); "

+

"create table "

+ TABLE_ARTISTS + "( " + COLUMN_ID + " integer primary key autoincrement, "

+ COLUMN_ARTIST_NAME + " text not null, "

+ COLUMN_ARTIST_LABEL + " text "

+ " ); “
+

"create table "

+ TABLE_LYRIC_ARTIST + "( "

+ COLUMN_LYRIC_ID + " integer, "

+ COLUMN_ARTIST_ID + " integer, "

+ " FOREIGN KEY(" + COLUMN_ARTIST_ID + ") REFERENCES " + TABLE_ARTISTS + "(" + COLUMN_ID + "), "

+ " FOREIGN KEY(" + COLUMN_LYRIC_ID + ") REFERENCES " + TABLE_LYRICS + "(" + COLUMN_ID + ") "

+ " ); "

;




...



}
Using SQLite Cons
• Queries / Updates are very tedious
• Changes become cumbersome
• Relationships between an object graph must be manually
managed
Realm Mobile Database Replacement
About Realm
• Realm is a Mobile Database:
• A replacement for Core Data or SQLite
• Feels like an Object Relational Mapping tool
• Free & Open Source Apache 2.0
• Comparable Performance to SQLite
Fast Queries
https://realm.io/news/introducing-realm/
Faster Counts
https://realm.io/news/introducing-realm/
Slower Inserts
https://realm.io/news/introducing-realm/
How it works
Realm Objects Look like Regular Objects…
public class Dog extends RealmObject {



private String name;

private int age;

@ignored private int dontPersistMe;



// + Standard setters and getters here



}



@RealmClass
public class Person implements RealmModel {



private String name;

private RealmList<Dog> dogs;



}



Easy to add / relate objects
try(Realm realm = Realm.getInstance(this.getContext())) {



realm.beginTransaction();



Dog dog = realm.createObject(Dog.class);

dog.setName("Rex");

dog.setAge(3);



Person person = realm.createObject(Person.class);

person.setName("Tim");

person.getDogs().add(dog);



realm.commitTransaction();

}
Updates must be wrapped in transactions
try(Realm realm = Realm.getInstance(this.getContext())) {



realm.beginTransaction();



Dog dog = realm.createObject(Dog.class);

dog.setName("Rex");

dog.setAge(3);



Person person = realm.createObject(Person.class);

person.setName("Tim");

person.getDogs().add(dog);



realm.commitTransaction();

}
Updates must be wrapped in transactions
try(Realm realm = Realm.getInstance(this.getContext())) {



realm.beginTransaction();



Dog dog = realm.createObject(Dog.class);

dog.setName("Rex");

dog.setAge(3);



Person person = realm.createObject(Person.class);

person.setName("Tim");

person.getDogs().add(dog);



realm.commitTransaction();

}
If an exception occurs, you must catch it
and rollback with realm.cancelTransaction( );
1 to Many
try(Realm realm = Realm.getInstance(this.getContext())) {



realm.beginTransaction();



Dog dog = realm.createObject(Dog.class);

dog.setName("Rex");

dog.setAge(3);



Person person = realm.createObject(Person.class);

person.setName("Tim");

person.getDogs().add(dog);



realm.commitTransaction();

}
1 to Many
Many to Many
try(Realm realm = Realm.getInstance(this.getContext())) {



realm.beginTransaction();



Dog rex = realm.createObject(Dog.class);

rex.setName("Rex");

rex.setAge(3);



Dog spot = realm.createObject(Dog.class);

spot.setName("Spot");

spot.setAge(4);

Person tim = realm.createObject(Person.class);

tim.setName(“Tim");
tim.getDogs().addAll(Arrays.asList(spot, rex));
Person mary = realm.createObject(Person.class);

mary.setName("Mary");

mary.getDogs().addAll(Arrays.asList(spot, rex));

rex.getOwners().addAll(Arrays.asList(tim, mary));
spot.getOwners().addAll(Arrays.asList(tim, mary));


realm.commitTransaction();

}
Many to Many
Querying
// Queries uses Builder pattern to build up the query conditions
// For this example, assume Dog has a property “Person owner”

RealmResults<Dog> results = realm.where(Dog.class)

.greaterThan("age", 8)
.equalTo("owner.name", "Tim")
.findAll();
// Queries are chainable

RealmResults<Dog> allRex = results.where()
.contains("name", "rex")

.findAll();
// Or they can be combined

RealmResults<Dog> result2 = realm.where(Dog.class)
.greaterThan("age", 8)
.equalTo(“owner.name", "Tim")
.contains("name", "rex")
.findAll();
More Queries
// Logical Query Grouping
boolean checkCase = false;
RealmResults<Dog> r = realm.where(Dog.class)
.greaterThan("age", 8) //implicit AND
.beginGroup()
.equalTo("name", “CuJo”, checkCase)
.or()
.contains("name", "rex")
.endGroup()
.findAll();
// Sorting
RealmResults<Dog> result = r.where(Dog.class).findAll();

result.sort("age"); // Sort ascending

result.sort("age", RealmResults.SORT_ORDER_DESCENDING);

// Result Aggregation
long sum = result.sum("age").longValue();

long min = result.min("age").longValue();

long max = result.max("age").longValue();

double average = result.average("age");

long matches = result.size();
Query Conditions
• between, greaterThan, lessThan, 

greaterThanOrEqualTo & lessThanOrEqualTo
• equalTo, notEqualTo, in, not & distinct
• contains, beginsWith & endsWith
• isNull & isNotNull
• isEmpty & isNotEmpty
Realm Object Field Types
• Java primitives
• Wrapper types
• byte[] for blob
• Realm Object
• RealmList<? extends RealmObject>
Realm Annotations
• @Required - Not Null
• @Ignore - Transient
• @PrimaryKey - string or integer (short, int or long)
• @Index - Implicitly set by Primary Key
Integrating Realm
Realm Installation
1. Add a classpath dependency to the project level build.grade file



buildscript {

repositories {
jcenter()
}
dependencies {
classpath "io.realm:realm-gradle-plugin:2.1.1"
}
}

2. Apply the realm-android plugin at the app module level build.grade file

apply plugin: 'realm-android'
Custom SQLiteOpenHelper Goes Away!
public class MySQLiteHelper extends SQLiteOpenHelper {



public static final String TABLE_LYRICS = "lyrics";

public static final String COLUMN_ID = "_id";

public static final String COLUMN_LYRIC = "lyric";



private static final String DATABASE_NAME = "lyric.db";

private static final int DATABASE_VERSION = 1;



// Database creation sql statement

private static final String DATABASE_CREATE = "create table "

+ TABLE_LYRICS + "( " + COLUMN_ID

+ " integer primary key autoincrement, " + COLUMN_LYRIC

+ " text not null);";



public MySQLiteHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}



@Override

public void onCreate(SQLiteDatabase database) {

database.execSQL(DATABASE_CREATE);

}



@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

Log.w(MySQLiteHelper.class.getName(),

"Upgrading database from version " + oldVersion + " to "

+ newVersion + ", which will destroy all old data");

db.execSQL("DROP TABLE IF EXISTS " + TABLE_LYRICS);

onCreate(db);

}



}
public class Lyric extends RealmObject {



private int sortKey;
@PrimaryKey private String id;

@Required private String lyricText;





// Getters / Setters...



// Will be used by the ArrayAdapter in the ListView

@Override

public String toString() {

return lyricText;

}

}
Simple Data Object - Still Simple
RealmObject
and
Annotations
Lyric Datasource
public class LyricDataSource {



// Database fields

private SQLiteDatabase database;

private MySQLiteHelper dbHelper;

private String[] allColumns = { MySQLiteHelper.COLUMN_ID,

MySQLiteHelper.COLUMN_LYRIC};



public LyricDataSource(Context context) {

dbHelper = new MySQLiteHelper(context);

}



public void open() throws SQLException {

database = dbHelper.getWritableDatabase();

}



public void close() {

dbHelper.close();

}
public List<Lyric> getAllLyrics() {

List<Lyric> lyrics = new ArrayList<Lyric>();



Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, null, null, null, null,
MySQLiteHelper.COLUMN_ID);

cursor.moveToFirst();

while (!cursor.isAfterLast()) {

Lyric lyric = cursorToLyric(cursor);

lyrics.add(lyric);

cursor.moveToNext();

}

// Make sure to close the cursor

cursor.close();

return lyrics;

}
public Lyric createLyric(String lyric) {

ContentValues values = new ContentValues();

values.put(MySQLiteHelper.COLUMN_LYRIC, lyric);

long insertId = database.insert(MySQLiteHelper.TABLE_LYRICS, null,

values);

Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId,
null,

null, null, null);

cursor.moveToFirst();

Lyric newLyric = cursorToLyric(cursor);

cursor.close();

return newLyric;

}



public void deleteLyric(Lyric lyric) {

long id = lyric.getId();

System.out.println("Lyric deleted with id: " + id);

database.delete(MySQLiteHelper.TABLE_LYRICS, MySQLiteHelper.COLUMN_ID

+ " = " + id, null);

}



public Lyric getLyricByValue(String lyricText) {

Lyric lyric = null;

Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,

allColumns, MySQLiteHelper.COLUMN_LYRIC + " = '" +
lyricText + "'" , null, null, null, null);

cursor.moveToFirst();

if (!cursor.isAfterLast()) {

lyric = cursorToLyric(cursor);

}

// Make sure to close the cursor

cursor.close();

return lyric;

}


private Lyric cursorToLyric(Cursor cursor) {

Lyric lyric = new Lyric();

lyric.setId(cursor.getLong(0));

lyric.setLyricText(cursor.getString(1));

return lyric;

}
Lyric Datasource
private Realm r;



public LyricDataSource(Realm realm) {

r = realm;

}


public void deleteAllLyrics() {

r.executeTransaction(new Realm.Transaction() {

@Override

public void execute(Realm realm) {

realm.delete(Lyric.class);

}

});

}



public Lyric getLyricByValue(String lyricText) {

return r.where(Lyric.class)
.equalTo("lyricText", lyricText)
.findFirst();

}



public List<Lyric> getAllLyrics() {

return r.where(Lyric.class)
.findAllSorted("sortKey");


}
public Lyric createLyric(String lyricString) {

final Lyric lyric = new Lyric();

lyric.setId(UUID.randomUUID().toString());

lyric.setLyricText(lyricString);
lyric.setSortKey(System.currentTimeMillis());


r.executeTransaction(new Realm.Transaction() {

@Override

public void execute(Realm realm) {

lyric = realm.copyToRealm(lyric);

}

});

return lyric;

}



public void deleteLyric(Lyric lyric) {

r.executeTransaction(new Realm.Transaction() {

@Override

public void execute(Realm realm) {

realm.where(Lyric.class)

.equalTo("id", lyric.getId())

.findAll()

.deleteAllFromRealm();

}

});

}
Application / Activity - Lifecycle Events
public class TestDatabaseActivity extends ListActivity {



private LyricDataSource datasource;
private Realm realm;


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

realm = Realm.getDefaultInstance();

datasource = new LyricDataSource(realm);



List<Lyric> values = datasource.getAllLyrics();



// Use the SimpleCursorAdapter to show the

// elements in a ListView

ArrayAdapter<Lyric> adapter =
new ArrayAdapter<Lyric>(this,

android.R.layout.simple_list_item_1,
values);

setListAdapter(adapter);

}



@Override

protected void onDestroy() {

super.onDestory();

realm.close();

}

...
}
public class NaeNaeApplication extends Application {



@Override

public void onCreate() {

super.onCreate();

Realm.init(this);
RealmConfiguration realmConfiguration =

new RealmConfiguration.Builder()

.deleteRealmIfMigrationNeeded()

.build();

Realm.setDefaultConfiguration(realmConfiguration);

}



}
Application / Activity - Lifecycle Events
public class TestDatabaseActivity extends ListActivity {



private LyricDataSource datasource;
private Realm realm;


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

realm = Realm.getDefaultInstance();

datasource = new LyricDataSource(realm);



List<Lyric> values = datasource.getAllLyrics();



// Use the SimpleCursorAdapter to show the

// elements in a ListView

ArrayAdapter<Lyric> adapter =
new ArrayAdapter<Lyric>(this,

android.R.layout.simple_list_item_1,
values);

setListAdapter(adapter);

}



@Override

protected void onDestroy() {

super.onDestory();

realm.close();

}

...
}
Keep reference
Get new instance of
realm datasource
on create and pass
to the datasource to
use.
1
public class NaeNaeApplication extends Application {



@Override

public void onCreate() {

super.onCreate();

Realm.init(this);
RealmConfiguration realmConfiguration =

new RealmConfiguration.Builder()

.deleteRealmIfMigrationNeeded()

.build();

Realm.setDefaultConfiguration(realmConfiguration);

}



}
Application / Activity - Lifecycle Events
public class TestDatabaseActivity extends ListActivity {



private LyricDataSource datasource;
private Realm realm;


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

realm = Realm.getDefaultInstance();

datasource = new LyricDataSource(realm);



List<Lyric> values = datasource.getAllLyrics();



// Use the SimpleCursorAdapter to show the

// elements in a ListView

ArrayAdapter<Lyric> adapter =
new ArrayAdapter<Lyric>(this,

android.R.layout.simple_list_item_1,
values);

setListAdapter(adapter);

}



@Override

protected void onDestroy() {

super.onDestory();

realm.close();

}

...
}
Keep reference
Get new instance of
realm datasource
on create and pass
to the datasource to
use.
For
getDefaultInstance
to work, we must
set the default
configuration once
1
2
public class NaeNaeApplication extends Application {



@Override

public void onCreate() {

super.onCreate();

Realm.init(this);
RealmConfiguration realmConfiguration =

new RealmConfiguration.Builder()

.deleteRealmIfMigrationNeeded()

.build();

Realm.setDefaultConfiguration(realmConfiguration);

}



}
Application / Activity - Lifecycle Events
public class TestDatabaseActivity extends ListActivity {



private LyricDataSource datasource;
private Realm realm;


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.main);

realm = Realm.getDefaultInstance();

datasource = new LyricDataSource(realm);



List<Lyric> values = datasource.getAllLyrics();



// Use the SimpleCursorAdapter to show the

// elements in a ListView

ArrayAdapter<Lyric> adapter =
new ArrayAdapter<Lyric>(this,

android.R.layout.simple_list_item_1,
values);

setListAdapter(adapter);

}



@Override

protected void onDestroy() {

super.onDestory();

realm.close();

}

...
} Close on destroy
Keep reference
Get new instance of
realm datasource
on create and pass
to the datasource to
use.
For
getDefaultInstance
to work, we must
set the default
configuration once
1
2
3
public class NaeNaeApplication extends Application {



@Override

public void onCreate() {

super.onCreate();

Realm.init(this);
RealmConfiguration realmConfiguration =

new RealmConfiguration.Builder()

.deleteRealmIfMigrationNeeded()

.build();

Realm.setDefaultConfiguration(realmConfiguration);

}



}
Checkpoint
• Remove SQLite DataHelper
• Made our datasource code easier to read
• Reduced Code:
SQLite Realm
Lyric 28 40
Activity 77 72
DataSource 92 61
MySQLiteHelper 41 0
Application
 0 21
Total 238 194
Additional Realm Features
Change Listeners
public class MyActivity extends Activity {

private Realm realm;

private RealmChangeListener<RealmResults<Lyric>> listener;

private RealmResults<Lyric> lyrics;



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

realm = Realm.getDefaultInstance();

lyrics = realm.where(Lyric.class).contains("lyricText", "Bop").findAll();

listener = new RealmChangeListener<RealmResults<Lyric>>() {

@Override

public void onChange(RealmResults<Lyric> updatedResults) {

// Do something with the updated results, actually the results here

// match the ones stored as a reference in this activity.

}

};

lyrics.addChangeListener(listener);

}



@Override

protected void onDestroy() {

super.onDestroy();

realm.removeAllChangeListeners();

realm.close();

}
}
Async Operations
// Async with Callback
private RealmChangeListener callback = new RealmChangeListener() {

@Override

public void onChange() { // called once the query complete and on every update

// use the result

}

};

public void onStart() {

try(Realm r = Realm.getInstance(context)) {

RealmResults<Lyric> result = r.where(Lyric.class).findAllAsync();

result.addChangeListener(callback);

}

}
// Or you can block (be careful)
while (!result.isLoaded()) {

// Results are now available

}
// Or to block until async results are loaded
result.load()
Transaction Blocks & Async Transactions
// Transaction will be committed after block unless exception occurs.
realm.executeTransaction(new Realm.Transaction() {

@Override

public void execute(Realm realm) {

Lyric user = realm.createObject(Lyric.class);

user.setId(UUID.randomUUID().toString());

user.setLyricText("Let's get it started!");

}

});

// Asynchronous Transaction
realm.executeTransactionAsync(new Realm.Transaction() {

@Override

public void execute(Realm bgRealm) {

Lyric user = bgRealm.createObject(Lyric.class);



user.setId(UUID.randomUUID().toString());



user.setLyricText("Let's get it started in here");



}

}, new Realm.Transaction.OnSuccess() {

@Override

public void onSuccess() {

// Do something on the thread you were on.

}

}, new Realm.Transaction.OnError() {

@Override

public void onError(Throwable error) {

// Transaction failed and was automatically canceled.

// Do something on the thread you were on.

}

});
Insert JSON Directly
// Insert from a string

r.beginTransaction();

r.createObjectFromJson(Lyric.class,

"{ lyricText: "Bidi-bidi-bop", " +

"id: "864dee8a-d9ac-4e5a-a843-e051ad2d6e8a" }");

r.commitTransaction();



// Insert multiple items using a InputStream

InputStream is = new FileInputStream(new File("path_to_file"));

r.beginTransaction();

try {

r.createAllFromJson(Lyric.class, is);

r.commitTransaction();

} catch (IOException e) {

r.cancelTransaction();

}
ListAdapter & Recycler Adapters
dependencies {
compile ‘io.realm:android-adapters:1.4.0'
}
ListAdapter & Recycler Adapters
dependencies {
compile ‘io.realm:android-adapters:1.4.0'
}
public class MyAdapter extends RealmBaseAdapter<Lyric> implements ListAdapter {



private static class ViewHolder {

TextView lyricTextView;

}

public MyAdapter(Context context, int resId,

RealmResults<Lyric> realmResults,

boolean automaticUpdate) {

super(context, realmResults, automaticUpdate);

}



@Override

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder viewHolder;

if (convertView == null) {

convertView = inflater.inflate(android.R.layout.simple_list_item_1,

parent, false);

viewHolder = new ViewHolder();

viewHolder.lyricTextView = (TextView) convertView.findViewById(android.R.id.text1);

convertView.setTag(viewHolder);

} else {

viewHolder = (ViewHolder) convertView.getTag();

}



Lyric item = realmResults.get(position);

viewHolder.lyricTextView.setText(item.getLyricText());

return convertView;

}



public RealmResults<Lyric> getRealmResults() {

return realmResults;

}

}
ListAdapter & Recycler Adapters
dependencies {
compile ‘io.realm:android-adapters:1.4.0'
}
MyRecyclerViewAdapter extends RealmRecyclerViewAdapter<Promotion, MyRecyclerViewAdapter.ViewHolder> {



private final MyActivity activity;



public RealmRecyclerViewAdapter(@NonNull MyActivity activity, @Nullable OrderedRealmCollection<Lyric> lyrics)
{

super(promoListActivity, lyrics, true);

this.activity = activity;

}



@Override

public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = LayoutInflater.from(parent.getContext())

.inflate(R.layout.lyric_list_item, parent, false);

return new ViewHolder(view);

}



@Override

public void onBindViewHolder(final ViewHolder holder, int position) {

Lyric lyric = getData().get(position);

holder.lyrcTextView.setText(lyric.getLyricText());
holder.lyricId = lyric.getId());

}



public class ViewHolder extends RecyclerView.ViewHolder {

public TextView titleView;

public String promotionId;



public ViewHolder(View view) {

super(view);

lyricTextView = (TextView) view.findViewById(R.id.lyric_itle);

}

}
Encryption
RealmConfiguration config = new RealmConfiguration.Builder(context)

.encryptionKey(getKey())

.build();
• The Realm file can be stored encrypted on disk by
passing an encryption key (byte [])
• All data persisted to disk is transparently encrypted and
decrypted with standard AES-256 encryption
Migrations
RealmConfiguration config = new RealmConfiguration.Builder(context)

.schemaVersion(2) // Must be bumped when the schema changes

.migration(new MyMigration()) // Migration handler class

.build();
• Bump the version with each change
• Point the RealmConfiguration to you custom
RealmMigration Implementation
Migrations
RealmConfiguration config = new RealmConfiguration.Builder(context)

.schemaVersion(2) // Must be bumped when the schema changes

.migration(new MyMigration()) // Migration handler class

.build();
public class MyMigration implements RealmMigration {

public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {



RealmSchema schema = realm.getSchema(); // DynamicRealm exposes an editable schema



if (oldVersion == 0) { // Migrate to version 1: Add a new class

schema.create("Person")

.addField("name", String.class)

.addField("age", int.class);

oldVersion++; // Bump the version after each updgrade

}



if (oldVersion == 1) { // Migrate to version 2: Add PK + relationships

schema.get("Person")

.addField("id", long.class, FieldAttribute.PRIMARY_KEY)

.addRealmObjectField("favoriteDog", schema.get("Dog"))

.addRealmListField("dogs", schema.get("Dog"));

oldVersion++;

}

}

}
Migrations
public class MyMigration implements RealmMigration {

public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {



RealmSchema schema = realm.getSchema(); // DynamicRealm exposes an editable schema



if (oldVersion == 0) { // Migrate to version 1: Add a new class

schema.create("Person")

.addField("name", String.class)

.addField("age", int.class);

oldVersion++; // Bump the version after each updgrade

}



if (oldVersion == 1) { // Migrate to version 2: Add PK + relationships

schema.get("Person")

.addField("id", long.class, FieldAttribute.PRIMARY_KEY)

.addRealmObjectField("favoriteDog", schema.get("Dog"))

.addRealmListField("dogs", schema.get("Dog"));

oldVersion++;

}

}

}
Realm Browser
Resources
• Realm - https://realm.io/
• Source Code - https://github.com/realm/realm-java
• Code Samples
• Presentation Examples

https://github.com/ericmaxwell2003/
roboguiceRealmNaeNae
• Credible Software - http://credible.software

Weitere ähnliche Inhalte

Was ist angesagt?

Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...
Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...
Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...Dave Stokes
 
Datacon LA - MySQL without the SQL - Oh my!
Datacon LA - MySQL without the SQL - Oh my! Datacon LA - MySQL without the SQL - Oh my!
Datacon LA - MySQL without the SQL - Oh my! Dave Stokes
 
Open Source World June '21 -- JSON Within a Relational Database
Open Source World June '21 -- JSON Within a Relational DatabaseOpen Source World June '21 -- JSON Within a Relational Database
Open Source World June '21 -- JSON Within a Relational DatabaseDave Stokes
 
cPanel now supports MySQL 8.0 - My Top Seven Features
cPanel now supports MySQL 8.0 - My Top Seven FeaturescPanel now supports MySQL 8.0 - My Top Seven Features
cPanel now supports MySQL 8.0 - My Top Seven FeaturesDave Stokes
 
Discover the Power of the NoSQL + SQL with MySQL
Discover the Power of the NoSQL + SQL with MySQLDiscover the Power of the NoSQL + SQL with MySQL
Discover the Power of the NoSQL + SQL with MySQLDave Stokes
 
Json within a relational database
Json within a relational databaseJson within a relational database
Json within a relational databaseDave Stokes
 
How Clean is your database? Data scrubbing for all skills sets
How Clean is your database? Data scrubbing for all skills setsHow Clean is your database? Data scrubbing for all skills sets
How Clean is your database? Data scrubbing for all skills setsChad Petrovay
 
Php &amp; my sql - how do pdo, mysq-li, and x devapi do what they do
Php &amp; my sql  - how do pdo, mysq-li, and x devapi do what they doPhp &amp; my sql  - how do pdo, mysq-li, and x devapi do what they do
Php &amp; my sql - how do pdo, mysq-li, and x devapi do what they doDave Stokes
 
MySQL 8.0 Operational Changes
MySQL 8.0 Operational ChangesMySQL 8.0 Operational Changes
MySQL 8.0 Operational ChangesDave Stokes
 
Indexing and Query Optimisation
Indexing and Query OptimisationIndexing and Query Optimisation
Indexing and Query OptimisationMongoDB
 
MySQL Replication Update - DEbconf 2020 presentation
MySQL Replication Update - DEbconf 2020 presentationMySQL Replication Update - DEbconf 2020 presentation
MySQL Replication Update - DEbconf 2020 presentationDave Stokes
 
Develop PHP Applications with MySQL X DevAPI
Develop PHP Applications with MySQL X DevAPIDevelop PHP Applications with MySQL X DevAPI
Develop PHP Applications with MySQL X DevAPIDave Stokes
 
MySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source SummitMySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source SummitDave Stokes
 
Integrating OpenStack with Active Directory
Integrating OpenStack with Active DirectoryIntegrating OpenStack with Active Directory
Integrating OpenStack with Active Directorycjellick
 
Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...
Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...
Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...Dave Stokes
 
MySQL without the SQL -- Cascadia PHP
MySQL without the SQL -- Cascadia PHPMySQL without the SQL -- Cascadia PHP
MySQL without the SQL -- Cascadia PHPDave Stokes
 
Codemotion 2013: Feliz 15 aniversario, SQL Injection
Codemotion 2013: Feliz 15 aniversario, SQL InjectionCodemotion 2013: Feliz 15 aniversario, SQL Injection
Codemotion 2013: Feliz 15 aniversario, SQL InjectionChema Alonso
 
Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.
Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.
Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.Lucidworks
 

Was ist angesagt? (20)

iOS5 NewStuff
iOS5 NewStuffiOS5 NewStuff
iOS5 NewStuff
 
Lokijs
LokijsLokijs
Lokijs
 
Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...
Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...
Open Source 1010 and Quest InSync presentations March 30th, 2021 on MySQL Ind...
 
Datacon LA - MySQL without the SQL - Oh my!
Datacon LA - MySQL without the SQL - Oh my! Datacon LA - MySQL without the SQL - Oh my!
Datacon LA - MySQL without the SQL - Oh my!
 
Open Source World June '21 -- JSON Within a Relational Database
Open Source World June '21 -- JSON Within a Relational DatabaseOpen Source World June '21 -- JSON Within a Relational Database
Open Source World June '21 -- JSON Within a Relational Database
 
cPanel now supports MySQL 8.0 - My Top Seven Features
cPanel now supports MySQL 8.0 - My Top Seven FeaturescPanel now supports MySQL 8.0 - My Top Seven Features
cPanel now supports MySQL 8.0 - My Top Seven Features
 
Discover the Power of the NoSQL + SQL with MySQL
Discover the Power of the NoSQL + SQL with MySQLDiscover the Power of the NoSQL + SQL with MySQL
Discover the Power of the NoSQL + SQL with MySQL
 
Json within a relational database
Json within a relational databaseJson within a relational database
Json within a relational database
 
How Clean is your database? Data scrubbing for all skills sets
How Clean is your database? Data scrubbing for all skills setsHow Clean is your database? Data scrubbing for all skills sets
How Clean is your database? Data scrubbing for all skills sets
 
Php &amp; my sql - how do pdo, mysq-li, and x devapi do what they do
Php &amp; my sql  - how do pdo, mysq-li, and x devapi do what they doPhp &amp; my sql  - how do pdo, mysq-li, and x devapi do what they do
Php &amp; my sql - how do pdo, mysq-li, and x devapi do what they do
 
MySQL 8.0 Operational Changes
MySQL 8.0 Operational ChangesMySQL 8.0 Operational Changes
MySQL 8.0 Operational Changes
 
Indexing and Query Optimisation
Indexing and Query OptimisationIndexing and Query Optimisation
Indexing and Query Optimisation
 
MySQL Replication Update - DEbconf 2020 presentation
MySQL Replication Update - DEbconf 2020 presentationMySQL Replication Update - DEbconf 2020 presentation
MySQL Replication Update - DEbconf 2020 presentation
 
Develop PHP Applications with MySQL X DevAPI
Develop PHP Applications with MySQL X DevAPIDevelop PHP Applications with MySQL X DevAPI
Develop PHP Applications with MySQL X DevAPI
 
MySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source SummitMySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source Summit
 
Integrating OpenStack with Active Directory
Integrating OpenStack with Active DirectoryIntegrating OpenStack with Active Directory
Integrating OpenStack with Active Directory
 
Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...
Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...
Longhorn PHP - MySQL Indexes, Histograms, Locking Options, and Other Ways to ...
 
MySQL without the SQL -- Cascadia PHP
MySQL without the SQL -- Cascadia PHPMySQL without the SQL -- Cascadia PHP
MySQL without the SQL -- Cascadia PHP
 
Codemotion 2013: Feliz 15 aniversario, SQL Injection
Codemotion 2013: Feliz 15 aniversario, SQL InjectionCodemotion 2013: Feliz 15 aniversario, SQL Injection
Codemotion 2013: Feliz 15 aniversario, SQL Injection
 
Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.
Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.
Optimize Is (Not) Bad For You - Rafał Kuć, Sematext Group, Inc.
 

Ähnlich wie Better Data Persistence on Android

Accessing data with android cursors
Accessing data with android cursorsAccessing data with android cursors
Accessing data with android cursorsinfo_zybotech
 
Accessing data with android cursors
Accessing data with android cursorsAccessing data with android cursors
Accessing data with android cursorsinfo_zybotech
 
Android Training (Storing data using SQLite)
Android Training (Storing data using SQLite)Android Training (Storing data using SQLite)
Android Training (Storing data using SQLite)Khaled Anaqwa
 
Exemple de création de base
Exemple de création de baseExemple de création de base
Exemple de création de baseSaber LAJILI
 
Sqlite virtual-tables written in Perl
Sqlite virtual-tables written in PerlSqlite virtual-tables written in Perl
Sqlite virtual-tables written in PerlLaurent Dami
 
Create an android app for database creation using.pptx
Create an android app for database creation using.pptxCreate an android app for database creation using.pptx
Create an android app for database creation using.pptxvishal choudhary
 
Json Persistence Framework
Json Persistence FrameworkJson Persistence Framework
Json Persistence Frameworkdanieloskarsson
 
Is the database a solved problem?
Is the database a solved problem?Is the database a solved problem?
Is the database a solved problem?Kenneth Geisshirt
 
DIWE - Working with MySQL Databases
DIWE - Working with MySQL DatabasesDIWE - Working with MySQL Databases
DIWE - Working with MySQL DatabasesRasan Samarasinghe
 
All Things Open 2016 -- Database Programming for Newbies
All Things Open 2016 -- Database Programming for NewbiesAll Things Open 2016 -- Database Programming for Newbies
All Things Open 2016 -- Database Programming for NewbiesDave Stokes
 
I am looking for some assistance with SQLite database. I have tried se.pdf
I am looking for some assistance with SQLite database. I have tried se.pdfI am looking for some assistance with SQLite database. I have tried se.pdf
I am looking for some assistance with SQLite database. I have tried se.pdfConint29
 
Object Relational model for SQLIite in android
Object Relational model for SQLIite  in android Object Relational model for SQLIite  in android
Object Relational model for SQLIite in android yugandhar vadlamudi
 
Jdbc example program with access and MySql
Jdbc example program with access and MySqlJdbc example program with access and MySql
Jdbc example program with access and MySqlkamal kotecha
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database JonesJohn David Duncan
 

Ähnlich wie Better Data Persistence on Android (20)

Accessing data with android cursors
Accessing data with android cursorsAccessing data with android cursors
Accessing data with android cursors
 
Accessing data with android cursors
Accessing data with android cursorsAccessing data with android cursors
Accessing data with android cursors
 
Save data in to sqlite
Save data in to sqliteSave data in to sqlite
Save data in to sqlite
 
Android Training (Storing data using SQLite)
Android Training (Storing data using SQLite)Android Training (Storing data using SQLite)
Android Training (Storing data using SQLite)
 
Android sq lite-chapter 22
Android sq lite-chapter 22Android sq lite-chapter 22
Android sq lite-chapter 22
 
Exemple de création de base
Exemple de création de baseExemple de création de base
Exemple de création de base
 
Using database in android
Using database in androidUsing database in android
Using database in android
 
Python database access
Python database accessPython database access
Python database access
 
Sqlite virtual-tables written in Perl
Sqlite virtual-tables written in PerlSqlite virtual-tables written in Perl
Sqlite virtual-tables written in Perl
 
Create an android app for database creation using.pptx
Create an android app for database creation using.pptxCreate an android app for database creation using.pptx
Create an android app for database creation using.pptx
 
Json Persistence Framework
Json Persistence FrameworkJson Persistence Framework
Json Persistence Framework
 
Android Data Persistence
Android Data PersistenceAndroid Data Persistence
Android Data Persistence
 
Is the database a solved problem?
Is the database a solved problem?Is the database a solved problem?
Is the database a solved problem?
 
DIWE - Working with MySQL Databases
DIWE - Working with MySQL DatabasesDIWE - Working with MySQL Databases
DIWE - Working with MySQL Databases
 
All Things Open 2016 -- Database Programming for Newbies
All Things Open 2016 -- Database Programming for NewbiesAll Things Open 2016 -- Database Programming for Newbies
All Things Open 2016 -- Database Programming for Newbies
 
Phinx talk
Phinx talkPhinx talk
Phinx talk
 
I am looking for some assistance with SQLite database. I have tried se.pdf
I am looking for some assistance with SQLite database. I have tried se.pdfI am looking for some assistance with SQLite database. I have tried se.pdf
I am looking for some assistance with SQLite database. I have tried se.pdf
 
Object Relational model for SQLIite in android
Object Relational model for SQLIite  in android Object Relational model for SQLIite  in android
Object Relational model for SQLIite in android
 
Jdbc example program with access and MySql
Jdbc example program with access and MySqlJdbc example program with access and MySql
Jdbc example program with access and MySql
 
Building node.js applications with Database Jones
Building node.js applications with Database JonesBuilding node.js applications with Database Jones
Building node.js applications with Database Jones
 

Kürzlich hochgeladen

Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...masabamasaba
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Hararemasabamasaba
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...masabamasaba
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park masabamasaba
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrainmasabamasaba
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension AidPhilip Schwarz
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024VictoriaMetrics
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Bert Jan Schrijver
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in sowetomasabamasaba
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrandmasabamasaba
 

Kürzlich hochgeladen (20)

CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
%+27788225528 love spells in Colorado Springs Psychic Readings, Attraction sp...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare%in Harare+277-882-255-28 abortion pills for sale in Harare
%in Harare+277-882-255-28 abortion pills for sale in Harare
 
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
%+27788225528 love spells in Huntington Beach Psychic Readings, Attraction sp...
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
WSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go PlatformlessWSO2CON2024 - It's time to go Platformless
WSO2CON2024 - It's time to go Platformless
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
Direct Style Effect Systems -The Print[A] Example- A Comprehension AidDirect Style Effect Systems -The Print[A] Example- A Comprehension Aid
Direct Style Effect Systems - The Print[A] Example - A Comprehension Aid
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
Large-scale Logging Made Easy: Meetup at Deutsche Bank 2024
 
WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?WSO2CON 2024 - Does Open Source Still Matter?
WSO2CON 2024 - Does Open Source Still Matter?
 
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
Devoxx UK 2024 - Going serverless with Quarkus, GraalVM native images and AWS...
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto%in Soweto+277-882-255-28 abortion pills for sale in soweto
%in Soweto+277-882-255-28 abortion pills for sale in soweto
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 

Better Data Persistence on Android

  • 1. Better Data Persistence on Android Eric Maxwell Credible Software
  • 2. What to Expect • Android Storage Options • Focus on SQLite / Database Storage • Make it better using the Realm Mobile Database
  • 3. Android Storage Options • Shared Preferences
  • 4. Android Storage Options • Shared Preferences • Disk Storage • Internal • External
  • 5. Android Storage Options • Shared Preferences • Disk Storage • Internal • External • Relational Database w/ SQLite
  • 6. SQLite • Relational Database on the device • android.database.sqlite.SQLiteDatabase • Perform insert, query, update, delete, begin/end transaction • android.database.sqlite.SQLiteOpenHelper • Handle Create, Upgrade events
  • 7. Nae Nae Assistant App • List of Nae Nae Lyrics • Add New • Delete • Persistent across launches
  • 8. View Layout <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:orientation="vertical" >
 
 <GridLayout
 android:id="@+id/lyricButtons"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:padding="10dp">
 
 <Button
 android:id="@+id/watch_me"
 android:text="@string/lyric_watch_me"
 android:onClick="add"/>
 
 <Button
 android:id="@+id/whip"
 android:text="@string/lyric_whip"
 android:onClick="add"/>
 
 <Button
 android:id="@+id/nea"
 android:text="@string/lyric_nea"
 android:onClick="add"/>
 
 <Button
 android:id="@+id/bop"
 android:text="@string/lyric_bop"
 android:onClick="add"/>
 
 </GridLayout>
 
 <ListView
 android:id="@android:id/list"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="@string/hello_world" />
 
 </LinearLayout>
  • 9. Simple Data Object public class Lyric { 
 private long id;
 private String lyricText;
 
 // Getters / Setters...
 
 // Will be used by the ArrayAdapter in the ListView
 @Override
 public String toString() {
 return lyricText;
 }
 }
  • 10. Activity - Lifecycle Events public class NaeNaeActivity extends ListActivity {
 
 private LyricDataSource datasource;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_naenae);
 
 datasource = new LyricDataSource(this);
 datasource.open();
 
 List<Lyric> values = datasource.getAllLyrics();
 
 // Use the SimpleCursorAdapter to show the
 // elements in a ListView
 ArrayAdapter<Lyric> adapter = new ArrayAdapter<Lyric>(this,
 android.R.layout.simple_list_item_1, values);
 setListAdapter(adapter); 
 }
 
 @Override
 protected void onResume() {
 super.onResume();
 datasource.open();
 }
 
 @Override
 protected void onPause() {
 super.onPause();
 datasource.close();
 } ... } The datasource gets initialized and opened on create and is then used to get all of the lyrics and placed into an array adapter. The datasource is opened and closed on resume and stop.
  • 11. Activity - Events Add/Remove public void add(View view) {
 String lyricText = ((Button) view).getText().toString();
 if (!TextUtils.isEmpty(lyricText)) {
 ArrayAdapter<Lyric> adapter = getListAdapter();
 Lyric lyric = null;
 lyric = datasource.createLyric(lyricText);
 adapter.add(lyric);
 }
 }
 
 public void delete (int position) {
 if (getListAdapter().getCount() > 0) {
 ArrayAdapter<Lyric> adapter = getListAdapter();
 Lyric lyric = adapter.getItem(position);
 datasource.deleteLyric(lyric);
 adapter.remove(lyric);
 }
 } 
 
 @Override
 @SuppressWarnings("unchecked")
 public ArrayAdapter<Lyric> getListAdapter() {
 return (ArrayAdapter<Lyric>) super.getListAdapter();
 } 
 Add Remove
  • 12. Custom SQLiteOpenHelper public class MySQLiteHelper extends SQLiteOpenHelper {
 
 public static final String TABLE_LYRICS = "lyrics";
 public static final String COLUMN_ID = "_id";
 public static final String COLUMN_LYRIC = "lyric";
 
 private static final String DATABASE_NAME = "lyric.db";
 private static final int DATABASE_VERSION = 1;
 
 // Database creation sql statement
 private static final String DATABASE_CREATE = "create table "
 + TABLE_LYRICS + "( " + COLUMN_ID
 + " integer primary key autoincrement, " + COLUMN_LYRIC
 + " text not null);";
 
 public MySQLiteHelper(Context context) {
 super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }
 
 @Override
 public void onCreate(SQLiteDatabase database) {
 database.execSQL(DATABASE_CREATE);
 }
 
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 Log.w(MySQLiteHelper.class.getName(),
 "Upgrading database from version " + oldVersion + " to "
 + newVersion + ", which will destroy all old data");
 db.execSQL("DROP TABLE IF EXISTS " + TABLE_LYRICS);
 onCreate(db);
 }
 
 }
  • 13. Lyric Datasource public class LyricDataSource {
 
 // Database fields
 private SQLiteDatabase database;
 private MySQLiteHelper dbHelper;
 private String[] allColumns = { MySQLiteHelper.COLUMN_ID,
 MySQLiteHelper.COLUMN_LYRIC};
 
 public LyricDataSource(Context context) {
 dbHelper = new MySQLiteHelper(context);
 }
 
 public void open() throws SQLException {
 database = dbHelper.getWritableDatabase();
 }
 
 public void close() {
 dbHelper.close();
 } public List<Lyric> getAllLyrics() {
 List<Lyric> lyrics = new ArrayList<Lyric>();
 
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, null, null, null, null, MySQLiteHelper.COLUMN_ID);
 cursor.moveToFirst();
 while (!cursor.isAfterLast()) {
 Lyric lyric = cursorToLyric(cursor);
 lyrics.add(lyric);
 cursor.moveToNext();
 }
 // Make sure to close the cursor
 cursor.close();
 return lyrics;
 } public Lyric createLyric(String lyric) {
 ContentValues values = new ContentValues();
 values.put(MySQLiteHelper.COLUMN_LYRIC, lyric);
 long insertId = database.insert(MySQLiteHelper.TABLE_LYRICS, null,
 values);
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId, null,
 null, null, null);
 cursor.moveToFirst();
 Lyric newLyric = cursorToLyric(cursor);
 cursor.close();
 return newLyric;
 }
 
 public void deleteLyric(Lyric lyric) {
 long id = lyric.getId();
 database.delete(MySQLiteHelper.TABLE_LYRICS, MySQLiteHelper.COLUMN_ID
 + " = " + id, null);
 }
 
 public Lyric getLyricByValue(String lyricText) {
 Lyric lyric = null;
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, MySQLiteHelper.COLUMN_LYRIC + " = '" + lyricText + "'" , null, null, null, null);
 cursor.moveToFirst();
 if (!cursor.isAfterLast()) {
 lyric = cursorToLyric(cursor);
 }
 // Make sure to close the cursor
 cursor.close();
 return lyric;
 } 
 private Lyric cursorToLyric(Cursor cursor) {
 Lyric lyric = new Lyric();
 lyric.setId(cursor.getLong(0));
 lyric.setLyricText(cursor.getString(1));
 return lyric;
 }
  • 14. Using SQLite Pros • No additional dependencies • Built in programatic transaction management • Built in creation and upgrade event handling
  • 15. What happens when you add a couple fields? public class MySQLiteHelper extends SQLiteOpenHelper {
 
 public static final String TABLE_LYRICS = "lyrics";
 public static final String COLUMN_ID = "_id";
 public static final String COLUMN_LYRIC = "lyric";
 
 private static final String DATABASE_NAME = "lyric.db";
 private static final int DATABASE_VERSION = 1;
 
 // Database creation sql statement
 private static final String DATABASE_CREATE = "create table "
 + TABLE_LYRICS + "( " + COLUMN_ID
 + " integer primary key autoincrement, " + COLUMN_LYRIC
 + " text not null);";
 
 public MySQLiteHelper(Context context) {
 super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }
 
 @Override
 public void onCreate(SQLiteDatabase database) {
 database.execSQL(DATABASE_CREATE);
 }
 
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 Log.w(MySQLiteHelper.class.getName(),
 "Upgrading database from version " + oldVersion + " to "
 + newVersion + ", which will destroy all old data");
 db.execSQL("DROP TABLE IF EXISTS " + TABLE_LYRICS);
 onCreate(db);
 }
 
 }
  • 16. Update the data model public class Lyric {
 private long id;
 private String lyricText; private String source; private boolean isChorus;
 
 public long getId() {
 return id;
 }
 
 public void setId(long id) {
 this.id = id;
 }
 
 public String getLyricText() {
 return lyricText;
 }
 
 public void setLyricText(String lyricText) {
 this.lyricText = lyricText;
 } // Additional Getter/Setters
 
 // Will be used by the ArrayAdapter in the ListView
 @Override
 public String toString() {
 return lyricText;
 }
 }
  • 17. Update the Datasource public class LyricDataSource {
 
 // Database fields
 private SQLiteDatabase database;
 private MySQLiteHelper dbHelper;
 private String[] allColumns = { MySQLiteHelper.COLUMN_ID,
 MySQLiteHelper.COLUMN_LYRIC, MySQLiteHelper.COLUMN_SOURCE, MySQLiteHelper.COLUMN_CHORUS};
 
 public LyricDataSource(Context context) {
 dbHelper = new MySQLiteHelper(context);
 }
 
 public void open() throws SQLException {
 database = dbHelper.getWritableDatabase();
 }
 
 public void close() {
 dbHelper.close();
 } public List<Lyric> getAllLyrics() {
 List<Lyric> lyrics = new ArrayList<Lyric>();
 
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, null, null, null, null, MySQLiteHelper.COLUMN_ID);
 cursor.moveToFirst();
 while (!cursor.isAfterLast()) {
 Lyric lyric = cursorToLyric(cursor);
 lyrics.add(lyric);
 cursor.moveToNext();
 }
 // Make sure to close the cursor
 cursor.close();
 return lyrics;
 } public Lyric createLyric(String lyric) {
 ContentValues values = new ContentValues();
 values.put(MySQLiteHelper.COLUMN_LYRIC, lyric);
 values.put(MySQLiteHelper.COLUMN_CHORUS, isChorus ? 1 : 0);
 values.put(MySQLiteHelper.COLUMN_SOURCE, source);
 long insertId = database.insert(MySQLiteHelper.TABLE_LYRICS, null,
 values);
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId, null,
 null, null, null);
 cursor.moveToFirst();
 Lyric newLyric = cursorToLyric(cursor);
 cursor.close();
 return newLyric;
 }
 
 public void deleteLyric(Lyric lyric) {
 long id = lyric.getId();
 database.delete(MySQLiteHelper.TABLE_LYRICS, MySQLiteHelper.COLUMN_ID
 + " = " + id, null);
 }
 
 public Lyric getLyricByValue(String lyricText) {
 Lyric lyric = null;
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, MySQLiteHelper.COLUMN_LYRIC + " = '" + lyricText + "'" , null, null, null, null);
 cursor.moveToFirst();
 if (!cursor.isAfterLast()) {
 lyric = cursorToLyric(cursor);
 }
 // Make sure to close the cursor
 cursor.close();
 return lyric;
 } 
 private Lyric cursorToLyric(Cursor cursor) {
 Lyric lyric = new Lyric();
 lyric.setId(cursor.getLong(0));
 lyric.setLyricText(cursor.getString(1)); lyric.setChorus(cursor.getInt(2) == 1);
 lyric.setSource(cursor.getString(3));
 return lyric;
 }
  • 18. Add the columns to our SQLiteOpenHelper public class MySQLiteHelper extends SQLiteOpenHelper {
 
 private static final String DATABASE_NAME = "lyric.db";
 private static final int DATABASE_VERSION = 1;
 public static final String COLUMN_ID = "_id";
 
 public static final String TABLE_LYRICS = "lyrics";
 public static final String COLUMN_LYRIC = "lyric";
 public static final String COLUMN_SOURCE = "source";
 
 public static final String COLUMN_CHORUS = "isChorus";
 
 
 // Database creation sql statement
 private static final String DATABASE_CREATE =
 
 "create table "
 + TABLE_LYRICS + "( " + COLUMN_ID
 + " integer primary key autoincrement, “ + COLUMN_LYRIC + " text not null, "
 + COLUMN_CHORUS + " text, "
 + COLUMN_SOURCE + " integer, "
 + " ); "
 ;
 
 ...
 
 }
  • 19. How about a second table public class MySQLiteHelper extends SQLiteOpenHelper {
 
 private static final String DATABASE_NAME = "lyric.db";
 private static final int DATABASE_VERSION = 1;
 public static final String COLUMN_ID = "_id";
 
 public static final String TABLE_LYRICS = "lyrics";
 public static final String COLUMN_LYRIC = "lyric";
 public static final String COLUMN_SOURCE = "source";
 public static final String COLUMN_CHORUS = "isChorus";
 
 public static final String TABLE_ARTISTS = "artists";
 public static final String COLUMN_ARTIST_NAME = "name";
 public static final String COLUMN_ARTIST_LABEL = "label";
 
 // Database creation sql statement
 private static final String DATABASE_CREATE =
 
 "create table "
 + TABLE_LYRICS + "( " + COLUMN_ID + " integer primary key autoincrement, "
 + COLUMN_LYRIC + " text not null, "
 + COLUMN_CHORUS + " text, "
 + COLUMN_SOURCE + " integer "
 + " ); "
 +
 "create table "
 + TABLE_ARTISTS + "( " + COLUMN_ID + " integer primary key autoincrement, "
 + COLUMN_ARTIST_NAME + " text not null, "
 + COLUMN_ARTIST_LABEL + " text "
 + " ); "
 ; 
 
 ...
 
 }
  • 20. Or a many to many relationship public class MySQLiteHelper extends SQLiteOpenHelper {
 
 private static final String DATABASE_NAME = "lyric.db";
 private static final int DATABASE_VERSION = 1;
 public static final String COLUMN_ID = "_id";
 
 public static final String TABLE_LYRICS = "lyrics";
 public static final String COLUMN_LYRIC = "lyric";
 public static final String COLUMN_SOURCE = "source";
 public static final String COLUMN_CHORUS = "isChorus";
 
 public static final String TABLE_ARTISTS = "artists";
 public static final String COLUMN_ARTIST_NAME = "name";
 public static final String COLUMN_ARTIST_LABEL = “label"; public static final String TABLE_LYRIC_ARTIST = "lyric_artist";
 public static final String COLUMN_LYRIC_ID = "lyric_id";
 public static final String COLUMN_ARTIST_ID = "artist_id";
 
 
 // Database creation sql statement
 private static final String DATABASE_CREATE =
 
 "create table "
 + TABLE_LYRICS + "( " + COLUMN_ID + " integer primary key autoincrement, "
 + COLUMN_LYRIC + " text not null, "
 + COLUMN_CHORUS + " text, "
 + COLUMN_SOURCE + " integer "
 + " ); "
 +
 "create table "
 + TABLE_ARTISTS + "( " + COLUMN_ID + " integer primary key autoincrement, "
 + COLUMN_ARTIST_NAME + " text not null, "
 + COLUMN_ARTIST_LABEL + " text "
 + " ); “ +
 "create table "
 + TABLE_LYRIC_ARTIST + "( "
 + COLUMN_LYRIC_ID + " integer, "
 + COLUMN_ARTIST_ID + " integer, "
 + " FOREIGN KEY(" + COLUMN_ARTIST_ID + ") REFERENCES " + TABLE_ARTISTS + "(" + COLUMN_ID + "), "
 + " FOREIGN KEY(" + COLUMN_LYRIC_ID + ") REFERENCES " + TABLE_LYRICS + "(" + COLUMN_ID + ") "
 + " ); "
 ; 
 
 ...
 
 }
  • 21. Using SQLite Cons • Queries / Updates are very tedious • Changes become cumbersome • Relationships between an object graph must be manually managed
  • 22. Realm Mobile Database Replacement
  • 23. About Realm • Realm is a Mobile Database: • A replacement for Core Data or SQLite • Feels like an Object Relational Mapping tool • Free & Open Source Apache 2.0 • Comparable Performance to SQLite
  • 28. Realm Objects Look like Regular Objects… public class Dog extends RealmObject {
 
 private String name;
 private int age;
 @ignored private int dontPersistMe;
 
 // + Standard setters and getters here
 
 }
 
 @RealmClass public class Person implements RealmModel {
 
 private String name;
 private RealmList<Dog> dogs;
 
 }
 

  • 29. Easy to add / relate objects try(Realm realm = Realm.getInstance(this.getContext())) {
 
 realm.beginTransaction();
 
 Dog dog = realm.createObject(Dog.class);
 dog.setName("Rex");
 dog.setAge(3);
 
 Person person = realm.createObject(Person.class);
 person.setName("Tim");
 person.getDogs().add(dog);
 
 realm.commitTransaction();
 }
  • 30. Updates must be wrapped in transactions try(Realm realm = Realm.getInstance(this.getContext())) {
 
 realm.beginTransaction();
 
 Dog dog = realm.createObject(Dog.class);
 dog.setName("Rex");
 dog.setAge(3);
 
 Person person = realm.createObject(Person.class);
 person.setName("Tim");
 person.getDogs().add(dog);
 
 realm.commitTransaction();
 }
  • 31. Updates must be wrapped in transactions try(Realm realm = Realm.getInstance(this.getContext())) {
 
 realm.beginTransaction();
 
 Dog dog = realm.createObject(Dog.class);
 dog.setName("Rex");
 dog.setAge(3);
 
 Person person = realm.createObject(Person.class);
 person.setName("Tim");
 person.getDogs().add(dog);
 
 realm.commitTransaction();
 } If an exception occurs, you must catch it and rollback with realm.cancelTransaction( );
  • 32. 1 to Many try(Realm realm = Realm.getInstance(this.getContext())) {
 
 realm.beginTransaction();
 
 Dog dog = realm.createObject(Dog.class);
 dog.setName("Rex");
 dog.setAge(3);
 
 Person person = realm.createObject(Person.class);
 person.setName("Tim");
 person.getDogs().add(dog);
 
 realm.commitTransaction();
 } 1 to Many
  • 33. Many to Many try(Realm realm = Realm.getInstance(this.getContext())) {
 
 realm.beginTransaction();
 
 Dog rex = realm.createObject(Dog.class);
 rex.setName("Rex");
 rex.setAge(3);
 
 Dog spot = realm.createObject(Dog.class);
 spot.setName("Spot");
 spot.setAge(4);
 Person tim = realm.createObject(Person.class);
 tim.setName(“Tim"); tim.getDogs().addAll(Arrays.asList(spot, rex)); Person mary = realm.createObject(Person.class);
 mary.setName("Mary");
 mary.getDogs().addAll(Arrays.asList(spot, rex));
 rex.getOwners().addAll(Arrays.asList(tim, mary)); spot.getOwners().addAll(Arrays.asList(tim, mary)); 
 realm.commitTransaction();
 } Many to Many
  • 34. Querying // Queries uses Builder pattern to build up the query conditions // For this example, assume Dog has a property “Person owner”
 RealmResults<Dog> results = realm.where(Dog.class)
 .greaterThan("age", 8) .equalTo("owner.name", "Tim") .findAll(); // Queries are chainable
 RealmResults<Dog> allRex = results.where() .contains("name", "rex")
 .findAll(); // Or they can be combined
 RealmResults<Dog> result2 = realm.where(Dog.class) .greaterThan("age", 8) .equalTo(“owner.name", "Tim") .contains("name", "rex") .findAll();
  • 35. More Queries // Logical Query Grouping boolean checkCase = false; RealmResults<Dog> r = realm.where(Dog.class) .greaterThan("age", 8) //implicit AND .beginGroup() .equalTo("name", “CuJo”, checkCase) .or() .contains("name", "rex") .endGroup() .findAll(); // Sorting RealmResults<Dog> result = r.where(Dog.class).findAll();
 result.sort("age"); // Sort ascending
 result.sort("age", RealmResults.SORT_ORDER_DESCENDING);
 // Result Aggregation long sum = result.sum("age").longValue();
 long min = result.min("age").longValue();
 long max = result.max("age").longValue();
 double average = result.average("age");
 long matches = result.size();
  • 36. Query Conditions • between, greaterThan, lessThan, 
 greaterThanOrEqualTo & lessThanOrEqualTo • equalTo, notEqualTo, in, not & distinct • contains, beginsWith & endsWith • isNull & isNotNull • isEmpty & isNotEmpty
  • 37. Realm Object Field Types • Java primitives • Wrapper types • byte[] for blob • Realm Object • RealmList<? extends RealmObject>
  • 38. Realm Annotations • @Required - Not Null • @Ignore - Transient • @PrimaryKey - string or integer (short, int or long) • @Index - Implicitly set by Primary Key
  • 40. Realm Installation 1. Add a classpath dependency to the project level build.grade file
 
 buildscript { repositories { jcenter() } dependencies { classpath "io.realm:realm-gradle-plugin:2.1.1" } }
 2. Apply the realm-android plugin at the app module level build.grade file apply plugin: 'realm-android'
  • 41. Custom SQLiteOpenHelper Goes Away! public class MySQLiteHelper extends SQLiteOpenHelper {
 
 public static final String TABLE_LYRICS = "lyrics";
 public static final String COLUMN_ID = "_id";
 public static final String COLUMN_LYRIC = "lyric";
 
 private static final String DATABASE_NAME = "lyric.db";
 private static final int DATABASE_VERSION = 1;
 
 // Database creation sql statement
 private static final String DATABASE_CREATE = "create table "
 + TABLE_LYRICS + "( " + COLUMN_ID
 + " integer primary key autoincrement, " + COLUMN_LYRIC
 + " text not null);";
 
 public MySQLiteHelper(Context context) {
 super(context, DATABASE_NAME, null, DATABASE_VERSION);
 }
 
 @Override
 public void onCreate(SQLiteDatabase database) {
 database.execSQL(DATABASE_CREATE);
 }
 
 @Override
 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 Log.w(MySQLiteHelper.class.getName(),
 "Upgrading database from version " + oldVersion + " to "
 + newVersion + ", which will destroy all old data");
 db.execSQL("DROP TABLE IF EXISTS " + TABLE_LYRICS);
 onCreate(db);
 }
 
 }
  • 42. public class Lyric extends RealmObject {
 
 private int sortKey; @PrimaryKey private String id;
 @Required private String lyricText;
 
 
 // Getters / Setters...
 
 // Will be used by the ArrayAdapter in the ListView
 @Override
 public String toString() {
 return lyricText;
 }
 } Simple Data Object - Still Simple RealmObject and Annotations
  • 43. Lyric Datasource public class LyricDataSource {
 
 // Database fields
 private SQLiteDatabase database;
 private MySQLiteHelper dbHelper;
 private String[] allColumns = { MySQLiteHelper.COLUMN_ID,
 MySQLiteHelper.COLUMN_LYRIC};
 
 public LyricDataSource(Context context) {
 dbHelper = new MySQLiteHelper(context);
 }
 
 public void open() throws SQLException {
 database = dbHelper.getWritableDatabase();
 }
 
 public void close() {
 dbHelper.close();
 } public List<Lyric> getAllLyrics() {
 List<Lyric> lyrics = new ArrayList<Lyric>();
 
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, null, null, null, null, MySQLiteHelper.COLUMN_ID);
 cursor.moveToFirst();
 while (!cursor.isAfterLast()) {
 Lyric lyric = cursorToLyric(cursor);
 lyrics.add(lyric);
 cursor.moveToNext();
 }
 // Make sure to close the cursor
 cursor.close();
 return lyrics;
 } public Lyric createLyric(String lyric) {
 ContentValues values = new ContentValues();
 values.put(MySQLiteHelper.COLUMN_LYRIC, lyric);
 long insertId = database.insert(MySQLiteHelper.TABLE_LYRICS, null,
 values);
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, MySQLiteHelper.COLUMN_ID + " = " + insertId, null,
 null, null, null);
 cursor.moveToFirst();
 Lyric newLyric = cursorToLyric(cursor);
 cursor.close();
 return newLyric;
 }
 
 public void deleteLyric(Lyric lyric) {
 long id = lyric.getId();
 System.out.println("Lyric deleted with id: " + id);
 database.delete(MySQLiteHelper.TABLE_LYRICS, MySQLiteHelper.COLUMN_ID
 + " = " + id, null);
 }
 
 public Lyric getLyricByValue(String lyricText) {
 Lyric lyric = null;
 Cursor cursor = database.query(MySQLiteHelper.TABLE_LYRICS,
 allColumns, MySQLiteHelper.COLUMN_LYRIC + " = '" + lyricText + "'" , null, null, null, null);
 cursor.moveToFirst();
 if (!cursor.isAfterLast()) {
 lyric = cursorToLyric(cursor);
 }
 // Make sure to close the cursor
 cursor.close();
 return lyric;
 } 
 private Lyric cursorToLyric(Cursor cursor) {
 Lyric lyric = new Lyric();
 lyric.setId(cursor.getLong(0));
 lyric.setLyricText(cursor.getString(1));
 return lyric;
 }
  • 44. Lyric Datasource private Realm r;
 
 public LyricDataSource(Realm realm) {
 r = realm;
 } 
 public void deleteAllLyrics() {
 r.executeTransaction(new Realm.Transaction() {
 @Override
 public void execute(Realm realm) {
 realm.delete(Lyric.class);
 }
 });
 }
 
 public Lyric getLyricByValue(String lyricText) {
 return r.where(Lyric.class) .equalTo("lyricText", lyricText) .findFirst();
 }
 
 public List<Lyric> getAllLyrics() {
 return r.where(Lyric.class) .findAllSorted("sortKey"); 
 } public Lyric createLyric(String lyricString) {
 final Lyric lyric = new Lyric();
 lyric.setId(UUID.randomUUID().toString());
 lyric.setLyricText(lyricString); lyric.setSortKey(System.currentTimeMillis()); 
 r.executeTransaction(new Realm.Transaction() {
 @Override
 public void execute(Realm realm) {
 lyric = realm.copyToRealm(lyric);
 }
 });
 return lyric;
 }
 
 public void deleteLyric(Lyric lyric) {
 r.executeTransaction(new Realm.Transaction() {
 @Override
 public void execute(Realm realm) {
 realm.where(Lyric.class)
 .equalTo("id", lyric.getId())
 .findAll()
 .deleteAllFromRealm();
 }
 });
 }
  • 45. Application / Activity - Lifecycle Events public class TestDatabaseActivity extends ListActivity {
 
 private LyricDataSource datasource; private Realm realm; 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 realm = Realm.getDefaultInstance();
 datasource = new LyricDataSource(realm);
 
 List<Lyric> values = datasource.getAllLyrics();
 
 // Use the SimpleCursorAdapter to show the
 // elements in a ListView
 ArrayAdapter<Lyric> adapter = new ArrayAdapter<Lyric>(this,
 android.R.layout.simple_list_item_1, values);
 setListAdapter(adapter);
 }
 
 @Override
 protected void onDestroy() {
 super.onDestory();
 realm.close();
 }
 ... } public class NaeNaeApplication extends Application {
 
 @Override
 public void onCreate() {
 super.onCreate();
 Realm.init(this); RealmConfiguration realmConfiguration =
 new RealmConfiguration.Builder()
 .deleteRealmIfMigrationNeeded()
 .build();
 Realm.setDefaultConfiguration(realmConfiguration);
 }
 
 }
  • 46. Application / Activity - Lifecycle Events public class TestDatabaseActivity extends ListActivity {
 
 private LyricDataSource datasource; private Realm realm; 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 realm = Realm.getDefaultInstance();
 datasource = new LyricDataSource(realm);
 
 List<Lyric> values = datasource.getAllLyrics();
 
 // Use the SimpleCursorAdapter to show the
 // elements in a ListView
 ArrayAdapter<Lyric> adapter = new ArrayAdapter<Lyric>(this,
 android.R.layout.simple_list_item_1, values);
 setListAdapter(adapter);
 }
 
 @Override
 protected void onDestroy() {
 super.onDestory();
 realm.close();
 }
 ... } Keep reference Get new instance of realm datasource on create and pass to the datasource to use. 1 public class NaeNaeApplication extends Application {
 
 @Override
 public void onCreate() {
 super.onCreate();
 Realm.init(this); RealmConfiguration realmConfiguration =
 new RealmConfiguration.Builder()
 .deleteRealmIfMigrationNeeded()
 .build();
 Realm.setDefaultConfiguration(realmConfiguration);
 }
 
 }
  • 47. Application / Activity - Lifecycle Events public class TestDatabaseActivity extends ListActivity {
 
 private LyricDataSource datasource; private Realm realm; 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 realm = Realm.getDefaultInstance();
 datasource = new LyricDataSource(realm);
 
 List<Lyric> values = datasource.getAllLyrics();
 
 // Use the SimpleCursorAdapter to show the
 // elements in a ListView
 ArrayAdapter<Lyric> adapter = new ArrayAdapter<Lyric>(this,
 android.R.layout.simple_list_item_1, values);
 setListAdapter(adapter);
 }
 
 @Override
 protected void onDestroy() {
 super.onDestory();
 realm.close();
 }
 ... } Keep reference Get new instance of realm datasource on create and pass to the datasource to use. For getDefaultInstance to work, we must set the default configuration once 1 2 public class NaeNaeApplication extends Application {
 
 @Override
 public void onCreate() {
 super.onCreate();
 Realm.init(this); RealmConfiguration realmConfiguration =
 new RealmConfiguration.Builder()
 .deleteRealmIfMigrationNeeded()
 .build();
 Realm.setDefaultConfiguration(realmConfiguration);
 }
 
 }
  • 48. Application / Activity - Lifecycle Events public class TestDatabaseActivity extends ListActivity {
 
 private LyricDataSource datasource; private Realm realm; 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
 realm = Realm.getDefaultInstance();
 datasource = new LyricDataSource(realm);
 
 List<Lyric> values = datasource.getAllLyrics();
 
 // Use the SimpleCursorAdapter to show the
 // elements in a ListView
 ArrayAdapter<Lyric> adapter = new ArrayAdapter<Lyric>(this,
 android.R.layout.simple_list_item_1, values);
 setListAdapter(adapter);
 }
 
 @Override
 protected void onDestroy() {
 super.onDestory();
 realm.close();
 }
 ... } Close on destroy Keep reference Get new instance of realm datasource on create and pass to the datasource to use. For getDefaultInstance to work, we must set the default configuration once 1 2 3 public class NaeNaeApplication extends Application {
 
 @Override
 public void onCreate() {
 super.onCreate();
 Realm.init(this); RealmConfiguration realmConfiguration =
 new RealmConfiguration.Builder()
 .deleteRealmIfMigrationNeeded()
 .build();
 Realm.setDefaultConfiguration(realmConfiguration);
 }
 
 }
  • 49. Checkpoint • Remove SQLite DataHelper • Made our datasource code easier to read • Reduced Code: SQLite Realm Lyric 28 40 Activity 77 72 DataSource 92 61 MySQLiteHelper 41 0 Application 0 21 Total 238 194
  • 51. Change Listeners public class MyActivity extends Activity {
 private Realm realm;
 private RealmChangeListener<RealmResults<Lyric>> listener;
 private RealmResults<Lyric> lyrics;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 realm = Realm.getDefaultInstance();
 lyrics = realm.where(Lyric.class).contains("lyricText", "Bop").findAll();
 listener = new RealmChangeListener<RealmResults<Lyric>>() {
 @Override
 public void onChange(RealmResults<Lyric> updatedResults) {
 // Do something with the updated results, actually the results here
 // match the ones stored as a reference in this activity.
 }
 };
 lyrics.addChangeListener(listener);
 }
 
 @Override
 protected void onDestroy() {
 super.onDestroy();
 realm.removeAllChangeListeners();
 realm.close();
 } }
  • 52. Async Operations // Async with Callback private RealmChangeListener callback = new RealmChangeListener() {
 @Override
 public void onChange() { // called once the query complete and on every update
 // use the result
 }
 };
 public void onStart() {
 try(Realm r = Realm.getInstance(context)) {
 RealmResults<Lyric> result = r.where(Lyric.class).findAllAsync();
 result.addChangeListener(callback);
 }
 } // Or you can block (be careful) while (!result.isLoaded()) {
 // Results are now available
 } // Or to block until async results are loaded result.load()
  • 53. Transaction Blocks & Async Transactions // Transaction will be committed after block unless exception occurs. realm.executeTransaction(new Realm.Transaction() {
 @Override
 public void execute(Realm realm) {
 Lyric user = realm.createObject(Lyric.class);
 user.setId(UUID.randomUUID().toString());
 user.setLyricText("Let's get it started!");
 }
 });
 // Asynchronous Transaction realm.executeTransactionAsync(new Realm.Transaction() {
 @Override
 public void execute(Realm bgRealm) {
 Lyric user = bgRealm.createObject(Lyric.class);
 
 user.setId(UUID.randomUUID().toString());
 
 user.setLyricText("Let's get it started in here");
 
 }
 }, new Realm.Transaction.OnSuccess() {
 @Override
 public void onSuccess() {
 // Do something on the thread you were on.
 }
 }, new Realm.Transaction.OnError() {
 @Override
 public void onError(Throwable error) {
 // Transaction failed and was automatically canceled.
 // Do something on the thread you were on.
 }
 });
  • 54. Insert JSON Directly // Insert from a string
 r.beginTransaction();
 r.createObjectFromJson(Lyric.class,
 "{ lyricText: "Bidi-bidi-bop", " +
 "id: "864dee8a-d9ac-4e5a-a843-e051ad2d6e8a" }");
 r.commitTransaction();
 
 // Insert multiple items using a InputStream
 InputStream is = new FileInputStream(new File("path_to_file"));
 r.beginTransaction();
 try {
 r.createAllFromJson(Lyric.class, is);
 r.commitTransaction();
 } catch (IOException e) {
 r.cancelTransaction();
 }
  • 55. ListAdapter & Recycler Adapters dependencies { compile ‘io.realm:android-adapters:1.4.0' }
  • 56. ListAdapter & Recycler Adapters dependencies { compile ‘io.realm:android-adapters:1.4.0' } public class MyAdapter extends RealmBaseAdapter<Lyric> implements ListAdapter {
 
 private static class ViewHolder {
 TextView lyricTextView;
 }
 public MyAdapter(Context context, int resId,
 RealmResults<Lyric> realmResults,
 boolean automaticUpdate) {
 super(context, realmResults, automaticUpdate);
 }
 
 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 ViewHolder viewHolder;
 if (convertView == null) {
 convertView = inflater.inflate(android.R.layout.simple_list_item_1,
 parent, false);
 viewHolder = new ViewHolder();
 viewHolder.lyricTextView = (TextView) convertView.findViewById(android.R.id.text1);
 convertView.setTag(viewHolder);
 } else {
 viewHolder = (ViewHolder) convertView.getTag();
 }
 
 Lyric item = realmResults.get(position);
 viewHolder.lyricTextView.setText(item.getLyricText());
 return convertView;
 }
 
 public RealmResults<Lyric> getRealmResults() {
 return realmResults;
 }
 }
  • 57. ListAdapter & Recycler Adapters dependencies { compile ‘io.realm:android-adapters:1.4.0' } MyRecyclerViewAdapter extends RealmRecyclerViewAdapter<Promotion, MyRecyclerViewAdapter.ViewHolder> {
 
 private final MyActivity activity;
 
 public RealmRecyclerViewAdapter(@NonNull MyActivity activity, @Nullable OrderedRealmCollection<Lyric> lyrics) {
 super(promoListActivity, lyrics, true);
 this.activity = activity;
 }
 
 @Override
 public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 View view = LayoutInflater.from(parent.getContext())
 .inflate(R.layout.lyric_list_item, parent, false);
 return new ViewHolder(view);
 }
 
 @Override
 public void onBindViewHolder(final ViewHolder holder, int position) {
 Lyric lyric = getData().get(position);
 holder.lyrcTextView.setText(lyric.getLyricText()); holder.lyricId = lyric.getId());
 }
 
 public class ViewHolder extends RecyclerView.ViewHolder {
 public TextView titleView;
 public String promotionId;
 
 public ViewHolder(View view) {
 super(view);
 lyricTextView = (TextView) view.findViewById(R.id.lyric_itle);
 }
 }
  • 58. Encryption RealmConfiguration config = new RealmConfiguration.Builder(context)
 .encryptionKey(getKey())
 .build(); • The Realm file can be stored encrypted on disk by passing an encryption key (byte []) • All data persisted to disk is transparently encrypted and decrypted with standard AES-256 encryption
  • 59. Migrations RealmConfiguration config = new RealmConfiguration.Builder(context)
 .schemaVersion(2) // Must be bumped when the schema changes
 .migration(new MyMigration()) // Migration handler class
 .build(); • Bump the version with each change • Point the RealmConfiguration to you custom RealmMigration Implementation
  • 60. Migrations RealmConfiguration config = new RealmConfiguration.Builder(context)
 .schemaVersion(2) // Must be bumped when the schema changes
 .migration(new MyMigration()) // Migration handler class
 .build(); public class MyMigration implements RealmMigration {
 public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
 
 RealmSchema schema = realm.getSchema(); // DynamicRealm exposes an editable schema
 
 if (oldVersion == 0) { // Migrate to version 1: Add a new class
 schema.create("Person")
 .addField("name", String.class)
 .addField("age", int.class);
 oldVersion++; // Bump the version after each updgrade
 }
 
 if (oldVersion == 1) { // Migrate to version 2: Add PK + relationships
 schema.get("Person")
 .addField("id", long.class, FieldAttribute.PRIMARY_KEY)
 .addRealmObjectField("favoriteDog", schema.get("Dog"))
 .addRealmListField("dogs", schema.get("Dog"));
 oldVersion++;
 }
 }
 }
  • 61. Migrations public class MyMigration implements RealmMigration {
 public void migrate(DynamicRealm realm, long oldVersion, long newVersion) {
 
 RealmSchema schema = realm.getSchema(); // DynamicRealm exposes an editable schema
 
 if (oldVersion == 0) { // Migrate to version 1: Add a new class
 schema.create("Person")
 .addField("name", String.class)
 .addField("age", int.class);
 oldVersion++; // Bump the version after each updgrade
 }
 
 if (oldVersion == 1) { // Migrate to version 2: Add PK + relationships
 schema.get("Person")
 .addField("id", long.class, FieldAttribute.PRIMARY_KEY)
 .addRealmObjectField("favoriteDog", schema.get("Dog"))
 .addRealmListField("dogs", schema.get("Dog"));
 oldVersion++;
 }
 }
 }
  • 63. Resources • Realm - https://realm.io/ • Source Code - https://github.com/realm/realm-java • Code Samples • Presentation Examples
 https://github.com/ericmaxwell2003/ roboguiceRealmNaeNae • Credible Software - http://credible.software