Why Realm

1fa9cb8c7997c8c4d3d251fb5e41f749?s=47 Realm
October 20, 2015

Why Realm

GDG Android Seoul talk by by Leonardo Taehwan Kim
1. Introduction to Realm
https://realm.io/

2. Use case of Realm with Instagram tag API
https://github.com/TheFinestArtist/InstagRealm

1fa9cb8c7997c8c4d3d251fb5e41f749?s=128

Realm

October 20, 2015
Tweet

Transcript

  1. 6.

    Realm Replacement for SQLite & Core Data Android, Android Wear,

    iOS, OS X, Watch OS Java, Kotlin, Objective-C, Swift
  2. 8.

    Realm Very Fast ORM like models & queries RealmResults auto

    refresh More features… Open source Documentation in Korean
  3. 10.
  4. 11.
  5. 12.
  6. 13.

    Gson vs Realm This test is to compare the speed

    of Gson and Realm with an extremely simple object model. The overall result of the test shows that Realm performs a little faster than Gson. However, it could show different results in other test conditions. Refer to the appendix for further information. Gson.toJson Gson.fromJson Realm.createObject copyToRealm Milisecond 0 300 600 900 1200
  7. 15.

    Model public class User extends RealmObject { @PrimaryKey private String

    name; private int age; @Ignore private int sessionId; // + Standard getters & setters generated by your IDE }
  8. 16.

    Relation public class Email extends RealmObject { private String address;

    private boolean active; } // Many to One public class Contact extends RealmObject { private Email email; } // Many to Many public class Contact extends RealmObject { private RealmList<Email> emails; }
  9. 17.

    Write realm.beginTransaction(); User user = realm.createObject(User.class); // Create a new

    object user.setName("John"); user.setEmail("john@corporation.com"); realm.commitTransaction();
  10. 18.

    Write User user = new User("John"); user.setEmail("john@corporation.com"); realm.beginTransaction(); realm.copyToRealm(user); //

    Copy the object to Realm. realm.copyToRealmOrUpdate(user); realm.commitTransaction();
  11. 19.

    Query // Fluent interface RealmResults<User> result = realm.where(User.class) .sort("age"); .beginGroup()

    .equalTo("name", "John") .or() .equalTo("name", "Peter") .endGroup() .findAll(); for (User user : result) { // do something... }
  12. 20.

    Query Options // Conditions between(), greaterThan(), lessThan(), greaterThanOrEqualTo() & lessThanOrEqualTo()

    equalTo() & notEqualTo() contains(), beginsWith() & endsWith() isNull() & isNotNull() beginsWith() & endsWith() & contains() // Conditions Grouping beginGroup() & endGroup() & not() & or() // Sorting RealmResults<User> result = realm.where(User.class).findAll(); result.sort("age", RealmResults.SORT_ORDER_DESCENDING); // Querying findAll() & findFirst() & findAllSorted()
  13. 22.

    RealmResults public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> { RealmResults<Post> realmResults; public

    RecyclerViewAdapter(Realm realm) { realmResults = realm.where(Post.class).findAll(); } @Override public int getItemCount() { return realmResults.size(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Post post = realmResults.get(position); // do something... } }
  14. 23.

    RealmResults public class UserRecyclerAdapter extends RecyclerView.Adapter<ChatRecyclerAdapter.ViewHolder> { List<User> users; public

    ChatRecyclerAdapter() { /*...*/ } public void setUsers(List<User> users) { this.users = users; } @Override public int getItemCount() { return users == null ? 0 : users.size(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { User user = users.get(position); /*...*/ } }
  15. 26.

    Realm Configuration RealmConfiguration config1 = new RealmConfiguration.Builder(context) .name("myrealm1.realm") .encryptionKey(getKey1()) .schemaVersion(1)

    .setModules(new MySchemaModule1()) .migration(new MyMigration1()) .build(); RealmConfiguration config2 = new RealmConfiguration.Builder(context) .name("myrealm2.realm") .encryptionKey(null) .inMemory() .schemaVersion(2) .setModules(new MySchemaModule2()) .migration(new MyMigration2()) .build();
  16. 27.

    Realm Listener private RealmChangeListener realmListener; @Override public void onCreate(@Nullable Bundle

    savedInstanceState) { super.onCreate(savedInstanceState); realmListener = new RealmChangeListener() { @Override public void onChange() { // ... do something with the updates (UI, etc.) ... } }; realm.addChangeListener(realmListener); } @Override public void onDestroy() { super.onDestroy(); realm.removeChangeListener(realmListener); }
  17. 28.

    Realm Migration public class Migration implements RealmMigration { @Override public

    long execute(Realm realm, long version) { // Migrate from version 0 to version 1 if (version == 0) { Table personTable = realm.getTable(Person.class); long fistNameIndex = getIndexForProperty(personTable, "firstName"); long lastNameIndex = getIndexForProperty(personTable, "lastName"); long fullNameIndex = personTable.addColumn(ColumnType.STRING, "fullName"); personTable.removeColumn(getIndexForProperty(personTable, "firstName")); personTable.removeColumn(getIndexForProperty(personTable, "lastName")); version++; } return version; } } https://github.com/realm/realm-java/blob/master/examples/migrationExample
  18. 32.

    Current Limitations RealmObject Only private field Only default getter &

    setter Static field & method are allowed Null Values Threads
  19. 33.
  20. 37.

    Features Instagram Tag API ScrollView, ListView, RecyclerView, CardView Infinite Scroll

    (Paging), Swipe to Refresh Retrofit Gson EventBus Royal Fresco, Butterknife, RecyclerView-Animator, Logger
  21. 38.

    Flow Retrofit (Instagram Tag API) => Gson (Serialize) => Realm

    (Insert data) => EventBus => Update UI & Notify Adpater
  22. 39.

    RestAdapter private static Gson gson = new GsonBuilder() .setExclusionStrategies(new ExclusionStrategy()

    { @Override public boolean shouldSkipField(FieldAttributes f) { return f.getDeclaringClass().equals(RealmObject.class); } @Override public boolean shouldSkipClass(Class<?> clazz) { return false; } }) .create(); private static RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint(END_POINT) .setConverter(new GsonConverter(gson)) .setRequestInterceptor(requestInterceptor) .build(); private static InstagramService instagramService = restAdapter.create(InstagramService.class);
  23. 40.

    Instagram API public static void getTag(final Activity activity, final Class<?

    extends RoyalDatabase> clazz, String next) { instagramService.getTags("art", accessToken, next, new Callback<TagsCallback>() { @Override public void success(TagsCallback tagsCallback, Response response) { RoyalTransaction.save(clazz, tagsCallback.data); if (ScrollViewDatabase.class.equals(clazz)) EventBus.getDefault().post(new OnScrollViewUpdateEvent(tagsCallback.pagination.next_max_tag_id, tagsCallback.data)); if (ListViewDatabase.class.equals(clazz)) EventBus.getDefault().post(new OnListViewUpdateEvent(tagsCallback.pagination.next_max_tag_id)); if (RecyclerViewDatabase.class.equals(clazz)) EventBus.getDefault().post(new OnRecyclerViewUpdateEvent(tagsCallback.pagination.next_max_tag_id)); if (CardViewDatabase.class.equals(clazz)) EventBus.getDefault().post(new OnCardViewUpdateEvent(tagsCallback.pagination.next_max_tag_id)); } @Override public void failure(RetrofitError error) { SnackBar.alert(activity, "Please check your network status!"); } }); }
  24. 41.

    OnEvent int itemCount = 0; public void onEvent(OnRecyclerViewUpdateEvent event) {

    swipeRefreshLayout.setRefreshing(false); if (event.isFailed()) return; next = event.getNext(); if (itemCount < adapter.getItemCount()) adapter.notifyItemRangeInserted(itemCount, adapter.getItemCount() - itemCount); else adapter.notifyItemRangeRemoved(itemCount, itemCount - adapter.getItemCount()); itemCount = adapter.getItemCount(); }
  25. 42.

    RecyclerViewAdapter public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> { RealmResults<Post> realmResults; public

    RecyclerViewAdapter(Realm realm) { realmResults = realm.where(Post.class).findAll(); } @Override public int getItemCount() { return realmResults.size(); } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(layoutRes, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { Post post = realmResults.get(position); // do something... } }
  26. 43.

    ListViewAdapter public class ListViewAdapter extends RealmBaseAdapter<Post> implements ListAdapter { public

    ListViewAdapter(Context context, RealmResults<Post> realmResults) { super(context, realmResults, true); } static class ViewHolder { ViewHolder(View view) { /*...*/ } public void setPost(Post post) { /*...*/ } } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; /* ViewHolder Inflating */ Post post = realmResults.get(position); viewHolder.setPost(post); return convertView; } }
  27. 45.
  28. 46.
  29. 48.

    Appendix Test Device: Galaxy S3 Test Model public class Contact

    { public String address; public String number; public boolean active; } 10000 times iteration per each test. 5 times test per each method Test Code: https://github.com/Test-Codes/Realm-Java-Benchmark