We all know the good old SQLite when times are asking for an internal storage. But times are changing and here it comes Realm which is on a great way to replace SQLite.

Note: The Realm version for this demo is 0.82.1, as a more stable version. The latest version at the moment is 0.90.0. For further info check https://realm.io/docs/java/latest/

android working with realm database

What is Realm?

Realm is a mobile database and a replacement for SQLite. Although is an OO database it has some differences with other databases. Realm is not using SQLite as it’s engine. Instead it has own C++ core and aims to provide a mobile-first alternative to SQLite. Realm store data in a universal, table-based format by a C++ core. This is what allows Realm to allow data access from multiple languages as well as a range of ad hoc queries.

Below are the advantages of Realm over SQLite:
> faster than SQLite (up to 10x speed up over raw SQLite for normal operations)
> easy to use
> object conversion handled for you
> convenient for creating and storing data on the fly
> very responsive team

Also there are some disadvantages which might be taken into consideration:
> no importing
> still under active development
> not a lot of content online
> can’t access objects across threads

Realm at the moment is missing the following features:
> null support
> auto incrementing id’s
> Map support
> easy migrations
> notifications on specific data changed
> compound primary keys

android-realm-database-tutorial

Building E-Book App

Note: If you receive any problems during running the project after changes have been done to the realm, you might need to uninstall the app and run it again.

android-studio-creating-realm-database-app

1. Create a new project in Android Studio from File ⇒ New Project. When it prompts you to select the default activity, select Blank Activity and proceed.

2. Open build.gradle and add Realm, Glide, CardView and RecyclerView dependencies. RecyclerView and CardView are used to show the realm data and Glide is for showing images.

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:support-v4:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.github.bumptech.glide:glide:3.7.0'

    // Realm
    compile 'io.realm:realm-android:0.82.1'
    // RecyclerView
    compile 'com.android.support:recyclerview-v7:23.3.0'
    // CardView
    compile 'com.android.support:cardview-v7:23.3.0'
}

3. Open dimens.xml located under res ⇒ values and add the following dimensions.

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="margin_normal">8dp</dimen>
    <dimen name="margin_large">16dp</dimen>
    <dimen name="text_size_large">16sp</dimen>
    <dimen name="margin_small">0dp</dimen>
    <dimen name="text_size_normal">13sp</dimen>
    <dimen name="imge_book_detail">80dp</dimen>
</resources>

4. Add the below styles to your styles.xml located under res ⇒ values. Here we define styles for the CardView.

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

    <style name="AppTheme.Card.Margins" parent="CardView">
        <item name="android:layout_marginTop">@dimen/margin_normal</item>
        <item name="android:layout_marginBottom">@dimen/margin_normal</item>
        <item name="android:layout_marginLeft">@dimen/margin_large</item>
        <item name="android:layout_marginRight">@dimen/margin_large</item>
        <item name="android:clickable">true</item>
        <item name="android:focusable">true</item>
        <item name="android:foreground">?android:attr/selectableItemBackground</item>
        <item name="cardCornerRadius">@dimen/margin_small</item>
        <item name="cardPreventCornerOverlap">false</item>
        <item name="cardBackgroundColor">@android:color/white</item>
    </style>

</resources>

5. Create four packages named app, activity, adapters, model and realm and place your MainActivity.java under activity package. These packages helps in keeping your project organized.

6. Realms are the equivalent of a database: they contain different kinds of objects, and map to one file on disk. The most basic setup for realm is by calling:

// Obtain realm instance
Realm realm = Realm.getInstance(this);

Calling Realm.getInstance(context) makes it easy to get started with Realm. For more fine-grained control, it is possible to create a RealmConfiguration object that controls all aspects of how a Realm is created.

Create a class named MyApplication.java under app package. Here we setup the realm configuration.

package app.androidhive.info.realm.app;

import android.app.Application;

import io.realm.Realm;
import io.realm.RealmConfiguration;

public class MyApplication extends Application {

    @Override
    public void onCreate() {

        super.onCreate();
        RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
                .name(Realm.DEFAULT_REALM_NAME)
                .schemaVersion(0)
                .deleteRealmIfMigrationNeeded()
                .build();
        Realm.setDefaultConfiguration(realmConfiguration);

    }
}

The RealmConfiguration can be saved as a default configuration. Setting a default configuration in your custom Application class, will ensure that it is available in the rest of your code.

It is also possible to have multiple RealmConfigurations. In this way you can control the version, schema and location of each Realm independently.

/*
RealmConfiguration myConfig = new RealmConfiguration.Builder(context)
        .name("myrealm.realm").
.schemaVersion(2)
        .setModules(new MyCustomSchema())
        .build();

RealmConfiguration otherConfig = new RealmConfiguration.Builder(context)
        .name("otherrealm.realm")
        .schemaVersion(5)
        .setModules(new MyOtherSchema())
        .build();

Realm myRealm = Realm.getInstance(myConfig);
Realm otherRealm = Realm.getInstance(otherConfig);
*/

7. Open AndroidManifest.xml and add the MyApplication to <application> tag. Also add the INTERNET permission as we need to make HTTP calls for the images.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="app.androidhive.info.realm">

<uses-permission android:name="android.permission.INTERNET" />

<application
    android:name=".app.MyApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".activity.MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
</manifest>

8. In the model package add a class named Book.java. Realm data models are created by extending the the RealmObject base class. A Realm data model also supports public, protected and private fields as well as custom methods.

package app.androidhive.info.realm.model;

import io.realm.RealmObject;
import io.realm.annotations.Ignore;
import io.realm.annotations.PrimaryKey;

public class Book extends RealmObject {

    @PrimaryKey
    private int id;

    private String title;

    private String description;

    private String author;

    private String imageUrl;

    // Standard getters & setters generated by your IDE…
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}

The @PrimaryKey annotation indicates that this field is set as a Primary key and must not be null.
Also you can use the @Ignore annotation for the fields that should not be persisted to the disk:

@Ignore
private String isbn;

9. Open the layout files of your main activity and add the recyclerView. For my main activity I have three layout files activity_main.xml, content_main.xml and item_books.xml

The activity_main.xml contains the general AppBar, Toolbar and floating action button and includes the content_main.xml layout.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:fab="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="enterAlways" />

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@mipmap/ic_add_white_24dp"
        app:backgroundTint="@color/colorPrimary"
        app:elevation="4dp"
        app:layout_anchor="@+id/recycler"
        app:layout_anchorGravity="bottom|right|end" />

</android.support.design.widget.CoordinatorLayout>

The content_main.xml contains the recyclerView to load the data.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/recycler"
    android:layout_width="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:layout_height="match_parent" />

The item_books.xml contains the CardView with the ImageView and TextView’s for the recycler to display the data.

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_books"
    style="@style/AppTheme.Card.Margins"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/image_background"
            android:layout_width="130dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical|start" />

        <LinearLayout
            android:id="@+id/layout_partner"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:paddingBottom="@dimen/margin_normal">

            <TextView
                android:id="@+id/text_books_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/margin_small"
                android:paddingBottom="@dimen/margin_normal"
                android:paddingLeft="@dimen/margin_large"
                android:paddingRight="@dimen/margin_large"
                android:paddingTop="@dimen/margin_large"
                android:textSize="@dimen/text_size_large"
                android:textColor="#555555"
                android:textStyle="bold" />

            <TextView
                android:id="@+id/text_books_author"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:paddingLeft="@dimen/margin_large"
                android:paddingRight="@dimen/margin_large"
                android:textSize="@dimen/text_size_normal"
                android:textStyle="italic" />

            <TextView
                android:id="@+id/text_books_description"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="@dimen/margin_small"
                android:maxLines="2"
                android:paddingBottom="@dimen/margin_normal"
                android:paddingLeft="@dimen/margin_large"
                android:paddingRight="@dimen/margin_large"
                android:paddingTop="@dimen/margin_small"
                android:textSize="@dimen/text_size_normal" />

        </LinearLayout>
    </LinearLayout>
</android.support.v7.widget.CardView>

10. Under the realm package, create a class named RealmController.java. This is a singleton class where we put our realm methods for usage through the app.

package app.androidhive.info.realm.realm;


import android.app.Activity;
import android.app.Application;
import android.support.v4.app.Fragment;

import app.androidhive.info.realm.model.Book;
import io.realm.Realm;
import io.realm.RealmResults;


public class RealmController {

    private static RealmController instance;
    private final Realm realm;

    public RealmController(Application application) {
        realm = Realm.getDefaultInstance();
    }

    public static RealmController with(Fragment fragment) {

        if (instance == null) {
            instance = new RealmController(fragment.getActivity().getApplication());
        }
        return instance;
    }

    public static RealmController with(Activity activity) {

        if (instance == null) {
            instance = new RealmController(activity.getApplication());
        }
        return instance;
    }

    public static RealmController with(Application application) {

        if (instance == null) {
            instance = new RealmController(application);
        }
        return instance;
    }

    public static RealmController getInstance() {

        return instance;
    }

    public Realm getRealm() {

        return realm;
    }

    //Refresh the realm istance
    public void refresh() {

        realm.refresh();
    }

    //clear all objects from Book.class
    public void clearAll() {

        realm.beginTransaction();
        realm.clear(Book.class);
        realm.commitTransaction();
    }

    //find all objects in the Book.class
    public RealmResults<Book> getBooks() {

        return realm.where(Book.class).findAll();
    }

    //query a single item with the given id
    public Book getBook(String id) {

        return realm.where(Book.class).equalTo("id", id).findFirst();
    }

    //check if Book.class is empty
    public boolean hasBooks() {

        return !realm.allObjects(Book.class).isEmpty();
    }

    //query example
    public RealmResults<Book> queryedBooks() {

        return realm.where(Book.class)
                .contains("author", "Author 0")
                .or()
                .contains("title", "Realm")
                .findAll();

    }
}

The usage of this class is quite simple. Let’s say if we want to get all the objects saved in the Book.class, all we need to do in the wanted activity is call the following getBooks() method from the RealmController.java class:

RealmController.with(this).getBooks()

11. Under the adapters package create the following classes: RealmRecyclerViewAdapater.java, RealmModelAdapter.java, RealmBooksAdapter.java and BooksAdapter.java.

Inside RealmRecyclerViewAdapater.java place the following code:

package app.androidhive.info.realm.adapters;

import android.support.v7.widget.RecyclerView;

import io.realm.RealmBaseAdapter;
import io.realm.RealmObject;

public abstract class RealmRecyclerViewAdapter<T extends RealmObject> extends RecyclerView.Adapter {

    private RealmBaseAdapter<T> realmBaseAdapter;

    public T getItem(int position) {

        return realmBaseAdapter.getItem(position);
    }

    public RealmBaseAdapter<T> getRealmAdapter() {

        return realmBaseAdapter;
    }

    public void setRealmAdapter(RealmBaseAdapter<T> realmAdapter) {

        realmBaseAdapter = realmAdapter;
    }
}

This is a wrapper class that allows a RealmBaseAdapter instance to serve as the data source for a RecyclerView.Adapter

Inside RealmModelAdapter.java place the following code:

package app.androidhive.info.realm.adapters;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

import io.realm.RealmBaseAdapter;
import io.realm.RealmObject;
import io.realm.RealmResults;


public class RealmModelAdapter<T extends RealmObject> extends RealmBaseAdapter<T> {

    public RealmModelAdapter(Context context, RealmResults<T> realmResults, boolean automaticUpdate) {

        super(context, realmResults, automaticUpdate);
    }

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

        return null;
    }
}

In RealmBooksAdaper.java place the following code:

package app.androidhive.info.realm.adapters;

import android.content.Context;

import app.androidhive.info.realm.model.Book;
import io.realm.RealmResults;

public class RealmBooksAdapter extends RealmModelAdapter<Book> {

    public RealmBooksAdapter(Context context, RealmResults<Book> realmResults, boolean automaticUpdate) {

        super(context, realmResults, automaticUpdate);
    }
}

This classes are needed to make the recycler view adapter work with the realm data.

Finally create BooksAdapter.java.

package app.androidhive.info.realm.adapters;

import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.bumptech.glide.Glide;

import app.androidhive.info.realm.R;
import app.androidhive.info.realm.app.Prefs;
import app.androidhive.info.realm.model.Book;
import app.androidhive.info.realm.realm.RealmController;
import io.realm.Realm;
import io.realm.RealmResults;

public class BooksAdapter extends RealmRecyclerViewAdapter<Book> {

    final Context context;
    private Realm realm;
    private LayoutInflater inflater;

    public BooksAdapter(Context context) {

        this.context = context;
    }

    // create new views (invoked by the layout manager)
    @Override
    public CardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // inflate a new card view
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_books, parent, false);
        return new CardViewHolder(view);
    }

    // replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {

        realm = RealmController.getInstance().getRealm();

        // get the article
        final Book book = getItem(position);
        // cast the generic view holder to our specific one
        final CardViewHolder holder = (CardViewHolder) viewHolder;

        // set the title and the snippet
        holder.textTitle.setText(book.getTitle());
        holder.textAuthor.setText(book.getAuthor());
        holder.textDescription.setText(book.getDescription());

        // load the background image
        if (book.getImageUrl() != null) {
            Glide.with(context)
                    .load(book.getImageUrl().replace("https", "http"))
                    .asBitmap()
                    .fitCenter()
                    .into(holder.imageBackground);
        }

        //remove single match from realm
        holder.card.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {

                RealmResults<Book> results = realm.where(Book.class).findAll();

                // Get the book title to show it in toast message
                Book b = results.get(position);
                String title = b.getTitle();

                // All changes to data must happen in a transaction
                realm.beginTransaction();

                // remove single match
                results.remove(position);
                realm.commitTransaction();

                if (results.size() == 0) {
                    Prefs.with(context).setPreLoad(false);
                }

                notifyDataSetChanged();

                Toast.makeText(context, title + " is removed from Realm", Toast.LENGTH_SHORT).show();
                return false;
            }
        });

        //update single match from realm
        holder.card.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View content = inflater.inflate(R.layout.edit_item, null);
                final EditText editTitle = (EditText) content.findViewById(R.id.title);
                final EditText editAuthor = (EditText) content.findViewById(R.id.author);
                final EditText editThumbnail = (EditText) content.findViewById(R.id.thumbnail);

                editTitle.setText(book.getTitle());
                editAuthor.setText(book.getAuthor());
                editThumbnail.setText(book.getImageUrl());

                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setView(content)
                        .setTitle("Edit Book")
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                                RealmResults<Book> results = realm.where(Book.class).findAll();

                                realm.beginTransaction();
                                results.get(position).setAuthor(editAuthor.getText().toString());
                                results.get(position).setTitle(editTitle.getText().toString());
                                results.get(position).setImageUrl(editThumbnail.getText().toString());

                                realm.commitTransaction();

                                notifyDataSetChanged();
                            }
                        })
                        .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });
    }

    // return the size of your data set (invoked by the layout manager)
    public int getItemCount() {

        if (getRealmAdapter() != null) {
            return getRealmAdapter().getCount();
        }
        return 0;
    }

    public static class CardViewHolder extends RecyclerView.ViewHolder {

        public CardView card;
        public TextView textTitle;
        public TextView textAuthor;
        public TextView textDescription;
        public ImageView imageBackground;

        public CardViewHolder(View itemView) {
            // standard view holder pattern with Butterknife view injection
            super(itemView);

            card = (CardView) itemView.findViewById(R.id.card_books);
            textTitle = (TextView) itemView.findViewById(R.id.text_books_title);
            textAuthor = (TextView) itemView.findViewById(R.id.text_books_author);
            textDescription = (TextView) itemView.findViewById(R.id.text_books_description);
            imageBackground = (ImageView) itemView.findViewById(R.id.image_background);
        }
    }
}

12. Now that everything is set we can add code to the MainActivity.java

> Get realm instance from the RealmController.java
> Setup the recycler. setupRecycler() method is used for this purpose.
> Write some data in realm to be displayed in the recyclerView. setRealmData() method is used for this.
> Refresh the realm instance
> Set the realm adapter, get the realm data and pass it to the adapter

package app.androidhive.info.realm.activity;

import android.content.DialogInterface;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;

import app.androidhive.info.realm.app.Prefs;
import app.androidhive.info.realm.R;
import app.androidhive.info.realm.adapters.BooksAdapter;
import app.androidhive.info.realm.adapters.RealmBooksAdapter;
import app.androidhive.info.realm.model.Book;
import app.androidhive.info.realm.realm.RealmController;
import io.realm.Realm;
import io.realm.RealmResults;

public class MainActivity extends AppCompatActivity {

    private BooksAdapter adapter;
    private Realm realm;
    private LayoutInflater inflater;
    private FloatingActionButton fab;
    private RecyclerView recycler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        fab = (FloatingActionButton) findViewById(R.id.fab);
        recycler = (RecyclerView) findViewById(R.id.recycler);

        //get realm instance
        this.realm = RealmController.with(this).getRealm();

        //set toolbar
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        setupRecycler();

        if (!Prefs.with(this).getPreLoad()) {
            setRealmData();
        }

        // refresh the realm instance
        RealmController.with(this).refresh();
        // get all persisted objects
        // create the helper adapter and notify data set changes
        // changes will be reflected automatically
        setRealmAdapter(RealmController.with(this).getBooks());

        Toast.makeText(this, "Press card item for edit, long press to remove item", Toast.LENGTH_LONG).show();

        //add new item
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                inflater = MainActivity.this.getLayoutInflater();
                View content = inflater.inflate(R.layout.edit_item, null);
                final EditText editTitle = (EditText) content.findViewById(R.id.title);
                final EditText editAuthor = (EditText) content.findViewById(R.id.author);
                final EditText editThumbnail = (EditText) content.findViewById(R.id.thumbnail);

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setView(content)
                        .setTitle("Add book")
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                                Book book = new Book();
                                //book.setId(RealmController.getInstance().getBooks().size() + 1);
                                book.setId(RealmController.getInstance().getBooks().size() + System.currentTimeMillis());
                                book.setTitle(editTitle.getText().toString());
                                book.setAuthor(editAuthor.getText().toString());
                                book.setImageUrl(editThumbnail.getText().toString());

                                if (editTitle.getText() == null || editTitle.getText().toString().equals("") || editTitle.getText().toString().equals(" ")) {
                                    Toast.makeText(MainActivity.this, "Entry not saved, missing title", Toast.LENGTH_SHORT).show();
                                } else {
                                    // Persist your data easily
                                    realm.beginTransaction();
                                    realm.copyToRealm(book);
                                    realm.commitTransaction();

                                    adapter.notifyDataSetChanged();

                                    // scroll the recycler view to bottom
                                    recycler.scrollToPosition(RealmController.getInstance().getBooks().size() - 1);
                                }
                            }
                        })
                        .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });
    }

    public void setRealmAdapter(RealmResults<Book> books) {

        RealmBooksAdapter realmAdapter = new RealmBooksAdapter(this.getApplicationContext(), books, true);
        // Set the data and tell the RecyclerView to draw
        adapter.setRealmAdapter(realmAdapter);
        adapter.notifyDataSetChanged();
    }

    private void setupRecycler() {
        // use this setting to improve performance if you know that changes
        // in content do not change the layout size of the RecyclerView
        recycler.setHasFixedSize(true);

        // use a linear layout manager since the cards are vertically scrollable
        final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recycler.setLayoutManager(layoutManager);

        // create an empty adapter and add it to the recycler view
        adapter = new BooksAdapter(this);
        recycler.setAdapter(adapter);
    }

    private void setRealmData() {

        ArrayList<Book> books = new ArrayList<>();

        Book book = new Book();
        book.setId(1 + System.currentTimeMillis());
        book.setAuthor("Reto Meier");
        book.setTitle("Android 4 Application Development");
        book.setImageUrl("https://api.androidhive.info/images/realm/1.png");
        books.add(book);

        book = new Book();
        book.setId(2 + System.currentTimeMillis());
        book.setAuthor("Itzik Ben-Gan");
        book.setTitle("Microsoft SQL Server 2012 T-SQL Fundamentals");
        book.setImageUrl("https://api.androidhive.info/images/realm/2.png");
        books.add(book);

        book = new Book();
        book.setId(3 + System.currentTimeMillis());
        book.setAuthor("Magnus Lie Hetland");
        book.setTitle("Beginning Python: From Novice To Professional Paperback");
        book.setImageUrl("https://api.androidhive.info/images/realm/3.png");
        books.add(book);

        book = new Book();
        book.setId(4 + System.currentTimeMillis());
        book.setAuthor("Chad Fowler");
        book.setTitle("The Passionate Programmer: Creating a Remarkable Career in Software Development");
        book.setImageUrl("https://api.androidhive.info/images/realm/4.png");
        books.add(book);

        book = new Book();
        book.setId(5 + System.currentTimeMillis());
        book.setAuthor("Yashavant Kanetkar");
        book.setTitle("Written Test Questions In C Programming");
        book.setImageUrl("https://api.androidhive.info/images/realm/5.png");
        books.add(book);


        for (Book b : books) {
            // Persist your data easily
            realm.beginTransaction();
            realm.copyToRealm(b);
            realm.commitTransaction();
        }

        Prefs.with(this).setPreLoad(true);

    }
}

What is happening in this activity is when it is started, if there is no data in the realm, the setRealmData() method creates couple of objects and save it to the realm. After that realm instance is refreshed, the data is called with getBooks() and the adapter is notifyed about the changes:

        // refresh the realm instance
        RealmController.with(this).refresh();
        // get all persisted objects
        // create the helper adapter and notify data set changes
        // changes will be reflected automatically
        setRealmAdapter(RealmController.with(this).getBooks());

Run the app, and you can now see the data displayed in the recycler view.

android-realm-database-tutorial

Performing Write, Update & Delete Operations

13. We have set the app to read the realm data, now let’s do some simple write, update and delete to the data. Under res ⇒ layout, create a layout named edit_item.xml. This layout will be use in a dialog interface for writing and updating.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <EditText
    android:id="@+id/title"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="@dimen/activity_horizontal_margin"
    android:hint="Title"
    android:inputType="text" />

    <EditText
        android:id="@+id/author"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:hint="Author"
        android:inputType="text" />

    <EditText
        android:id="@+id/thumbnail"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:hint="Image"
        android:inputType="text" />

</LinearLayout>

14. Open again the MainActivity.java and the following code:

//add new item
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                inflater = MainActivity.this.getLayoutInflater();
                View content = inflater.inflate(R.layout.edit_item, null);
                final EditText editTitle = (EditText) content.findViewById(R.id.title);
                final EditText editAuthor = (EditText) content.findViewById(R.id.author);
                final EditText editThumbnail = (EditText) content.findViewById(R.id.thumbnail);

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setView(content)
                        .setTitle("Add book")
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                                Book book = new Book();
                                //book.setId(RealmController.getInstance().getBooks().size() + 1);
                                book.setId(RealmController.getInstance().getBooks().size() + System.currentTimeMillis());
                                book.setTitle(editTitle.getText().toString());
                                book.setAuthor(editAuthor.getText().toString());
                                book.setImageUrl(editThumbnail.getText().toString());

                                if (editTitle.getText() == null || editTitle.getText().toString().equals("") || editTitle.getText().toString().equals(" ")) {
                                    Toast.makeText(MainActivity.this, "Entry not saved, missing title", Toast.LENGTH_SHORT).show();
                                } else {
                                    // Persist your data easily
                                    realm.beginTransaction();
                                    realm.copyToRealm(book);
                                    realm.commitTransaction();

                                    adapter.notifyDataSetChanged();

                                    // scroll the recycler view to bottom
                                    recycler.scrollToPosition(RealmController.getInstance().getBooks().size() - 1);
                                }
                            }
                        })
                        .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });

Here we set and dialog on the floating action button to add new item. Run the following code and try to add some new data. (Note: you might need to uninstall and run the app again for the changes to take place) .

15. In order to make some update and delete actions open BooksAdapter.java and add the following code:

//remove single match from realm
holder.card.setOnLongClickListener(new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {

        RealmResults<Book> results = realm.where(Book.class).findAll();

                // Get the book title to show it in toast message
                Book b = results.get(position);
                String title = b.getTitle();

                // All changes to data must happen in a transaction
                realm.beginTransaction();

                // remove single match
                results.remove(position);
                realm.commitTransaction();

                if (results.size() == 0) {
                    Prefs.with(context).setPreLoad(false);
                }

                notifyDataSetChanged();

                Toast.makeText(context, title + " is removed from Realm", Toast.LENGTH_SHORT).show();
                return false;
    }
});

//update single match from realm
holder.card.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                View content = inflater.inflate(R.layout.edit_item, null);
                final EditText editTitle = (EditText) content.findViewById(R.id.title);
                final EditText editAuthor = (EditText) content.findViewById(R.id.author);
                final EditText editThumbnail = (EditText) content.findViewById(R.id.thumbnail);

                editTitle.setText(book.getTitle());
                editAuthor.setText(book.getAuthor());
                editThumbnail.setText(book.getImageUrl());

                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setView(content)
                        .setTitle("Edit Book")
                        .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {

                                RealmResults<Book> results = realm.where(Book.class).findAll();

                                realm.beginTransaction();
                                results.get(position).setAuthor(editAuthor.getText().toString());
                                results.get(position).setTitle(editTitle.getText().toString());
                                results.get(position).setImageUrl(editThumbnail.getText().toString());

                                realm.commitTransaction();

                                notifyDataSetChanged();
                            }
                        })
                        .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                            }
                        });
                AlertDialog dialog = builder.create();
                dialog.show();
            }
        });

Here we set delete of a match through long click on the card item and update dialog on click. The removing of an item is very easy. All we need is the bellow code with the position passed to the realm.

// All changes to data must happen in a transaction
        realm.beginTransaction();

        // remove single match
        results.remove(position);
        realm.commitTransaction();

The same happens with the update.

realm.beginTransaction();
                        results.get(position).setAuthor(editAuthor.getText().toString());
                        results.get(position).setTitle(editTitle.getText().toString());
                        results.get(position).setDescription(editDescription.getText().toString());
                        results.get(position).setImageUrl("https://realm.io/assets/RealmSquare.png");

realm.commitTransaction();

Now run the code again (uninstall or clear data if necessary ) and check the changes. Try updating or deleting some items.

android-realm-database-read-write-update-delete

Migration from SQLite

If you have currently have an app that uses SQLite and want to migrate to Realm, there is definitely some work involved. It is not a drop-in change. SQLite prefer a very normalized-form that doesn’t necessarily work the best with Realm. It’s better to rethink your schema and model it as objects.

Once you’ve modified the schema to work well with Realm however, it is much easier to migrate any existing data from SQLite. Just setup a migration (from version 0 to 1 of your Realm database), and in this migration, load your SQLite data into Realm objects and then just save them.

Or, if your data also resides on a remote server, you could just build the Realm database from scratch.
Before adopting Realm though, note that it must be considered as bleeding edge software, with an API that can have breaking changes in future versions.

Subscribe
Notify of
guest
172 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Ziigic
Ziigic
4 years ago

Thank you very much, you are awesome.

Ravi Tamada
4 years ago
Reply to  Ziigic

🙂

Narola
Narola
4 years ago
Reply to  Ravi Tamada

Hi Ravi can you plz provide tutorial for realm with retrofit lib

Syed Danish Haider
Syed Danish Haider
2 years ago
Reply to  Ravi Tamada

Hi ravi thanks for the tutorial.

after importing this project i am getting below error
Caused by: java.lang.IllegalArgumentException: Book is not part of the schema for this Realm

Can u check

Ravi Tamada
2 years ago

There are lot of discussion around this error. Please search find the suitable one for your case.

Dia Bader
Dia Bader
4 years ago

I don`t know how to thank you …
you are really gave an amazing and very very useful Idea ,Tutorial and projects ,
you are awesome.

Ravi Tamada
4 years ago
Reply to  Dia Bader

Thanks Dia

Åmol Çhavhan
Åmol Çhavhan
4 years ago

you always bring something new 😀

Ravi Tamada
4 years ago
Reply to  Åmol Çhavhan

🙂

sina shaloudegi
sina shaloudegi
4 years ago

Thanks Ravi;
Do you think we have to say goodbye to Sqlite ?
is it the time to migrate to OODBs ?

Ravi Tamada
4 years ago

I can see people are migrating to Realm. You can check big companies which are already using this
https://realm.io/

Vajeng Patidar
Vajeng Patidar
4 years ago

Thank you Very Much and God bless Ravi, though its not enough…

Ravi Tamada
4 years ago
Reply to  Vajeng Patidar

Thank you Vajeng, I wish you the same.

Myth
Myth
4 years ago

Thank you very much Ravi,
I’m from Vietnamese. my idol !

vikash
vikash
4 years ago

Will you please make a tutorial about in app billing ?

kid kaito
kid kaito
4 years ago

Thanks for posts
Next time you can write post android toturial to Alarms ?
It ‘s seem very good !

Mezooo
Mezooo
4 years ago

Thank you “Super professional Developer” Really you are a amazing programmer thank you Mr. Ravi.

Ravi Tamada
4 years ago
Reply to  Mezooo

Thanks for the appreciation 🙂

Cheers!

Adel Jaffan
Adel Jaffan
4 years ago

it’s very interesting, can you publish for us “p2p wifi” courses
Love from Syria.

Ravi Tamada
4 years ago
Reply to  Adel Jaffan

Yes, thanks for the suggestion.

dedidorez
dedidorez
4 years ago

Thanks men..

Hu Zhong
Hu Zhong
4 years ago

How to hide the title bar?

Gon Her
Gon Her
4 years ago

I need help please.

JSONArray want to dump a database and can not. Not like sending the database.
This is my json: http://fliveer.com/api/fliveer/home_php/home/realM.php

This is my test activity.: http://fliveer.com/api/download-center/MainActivity.zip

Please help.

Gon Her
Gon Her
4 years ago

Because delete my comment? I need help and you eliminate my request for help? Are you a good person?

Gon Her
Gon Her
4 years ago

I have a mysql database and json. You can expand your tutorial and upload this json in REALM please?

http://fliveer.com/api/fliveer/home_php/home/realM.php

sam
sam
4 years ago

Thank you so much for this tutorial

Sandeep Pradhan
Sandeep Pradhan
4 years ago

Hey bro how we can use custom images instead of movies images?…..in Image Glide Viewer

Murat
Murat
4 years ago

Thanks for tutorial Ravi but i’m getting error.

Error:(45, 17) error: Getter getId is not associated to any field
or
Error:(25, 17) error: Setter setId is not associated to any field

What could be the reasons for the error?

Ahmet Cevahir Çinar
Ahmet Cevahir Çinar
4 years ago
Reply to  Murat

I am get same error, please help.

rose
rose
4 years ago

hi…thanks for all learnings…

here is a wrong in BooksAdapter.java there isn’t “Prefs” and give error in running…???

thanks…!!!

Sadegh_khan
Sadegh_khan
4 years ago
Reply to  rose

I have this problem too, can you help me Ravi !? meghsi

Mouad Ghandi
Mouad Ghandi
4 years ago
Reply to  Sadegh_khan

Indeed, The problem is that the Class Prefs in file app is missed.

If you want to get the class you should download the code source, you’ll find it there.

Sadegh_khan
Sadegh_khan
4 years ago
Reply to  Mouad Ghandi

tnx, i had download the code source, but there is not any Prefs Class in app folder!!!

David Evhade
David Evhade
4 years ago

Realm is not working…I can’t build the gradle but when I used version 0.91.0, it built but no more RealmBaseAdapter…It is just throwing errors

sizwe
sizwe
4 years ago
Reply to  David Evhade

Ravi is using a RealmRecyclerViewAdapter and to use a RealmRecyclerViewAdapter and/or RealmBaseAdapter, you need to add extra dependencies to the application level build.gradle file.

dependencies {

compile ‘io.realm:android-adapters:1.2.2’

}

Check Realm documentation under “Working With Android”

Hope To Have Help You…Cheers

Mezooo
Mezooo
4 years ago

Thank you For Awesome tutorial Mr. Ravi. I really appreciate your efforts.
I hope to make tutorial about firebase. with Most of features like realtime database connection and GCM

https://firebase.google.com/

Feature image:
https://lh3.googleusercontent.com/Jp5DG28Mj668TyylbnjcCjNvzh-9-IjxT1IixnKrOziswXJzQZZ8GUpRobmQPba0vvINC8c6GymEni3UYcAX3uLVdHFz0Z_x=s888

Ravi Tamada
4 years ago
Reply to  Mezooo

Yeah I am studying Firebase.

Jojo
Jojo
4 years ago
Reply to  Ravi Tamada

Bro… go ahead

Martin Hurtiš
Martin Hurtiš
4 years ago

I have error on row : this.realm = RealmController.with(this).getRealm();

Caused by: java.lang.NullPointerException: No default RealmConfiguration was found. Call setDefaultConfiguration() first

at io.realm.Realm.getDefaultInstance(Realm.java:519)

at realm.RealmController.(RealmController.java:19)

Please help me 🙁

Kris Lai
Kris Lai
4 years ago
Reply to  Martin Hurtiš

Hi Martin,
it is because you forgot to add the declaration ‘android:name=”.app.MyApplication”‘ in the manifest file.

Martin Hurtiš
Martin Hurtiš
4 years ago
Reply to  Kris Lai

oh, thanks you are amazing 😀

Dr. Atul Tiwari
4 years ago

Hi Ravi, Thanks for this tutorial.
After reading that Realm 1.0 has released, I tried to update your demo e.g. to 1.0, but it failed. Can you please provide an update on what changes should be done in gradle file, so that your e.g. can work with Realm 1.0.

Edit 1 – After some trial and errors, I figured out a way to sync gradle correctly with Realm 1.0. But now, I learnt that, all the adapters are throwing errors. It seems there has been some changes in coding of Realm. Please help.

Ravi Tamada
4 years ago

Hi Atul

I still have to get good knowledge over realm. Please try figuring out the things by yourself.

sizwe
sizwe
4 years ago

Ravi is using a RealmRecyclerViewAdapter and to use a RealmRecyclerViewAdapter and/or RealmBaseAdapter, you need to add extra dependencies to the application level build.gradle file.

dependencies {
compile ‘io.realm:android-adapters:1.2.2’
}

Check Realm documentation under “Working With Android”

Hope To Have Help You…Cheers

Dr. Atul Tiwari
4 years ago
Reply to  sizwe

Hi @sizwe thank you for your help.. unfortunately i won’t be able to test it for next 2 days… will try to test asap.

Zhuinden
Zhuinden
4 years ago

I updated the sample to v1.1.1 in my Github repository called “realm-book-example”.

WeekendCoder
WeekendCoder
4 years ago

Any chance of making a sync adapter tutorial (for contacts, incoming messages etc) 🙂

Dibyajyot
4 years ago
Reply to  WeekendCoder

Thanks bro:)

WeekendCoder
WeekendCoder
4 years ago
Reply to  Dibyajyot

Had to ask 🙂 Ravi has the best step by step tutorials for android I could find, and I couldn’t find any good sync adapter tutorial so far.

fadi qua
fadi qua
4 years ago

great example, if i have 2 classes, and the main class has list attribute of second class, how to deal with list attribute, to explain my idea, when i click on the item, it will open detail activity that display information of ” list ” attribute .. ?

Sabahat Sana
Sabahat Sana
4 years ago

hi Ravi,please help me . i use realm with asynctask classes. And my app is crashed.

return this error:
Realm access from incorrect thread. Realm objects can only be accessed on the thread they were created.

Saad Saeed
Saad Saeed
4 years ago

i want to upload mp3 file into external database through my android application can anybody help.

Kuldeep Mishra
Kuldeep Mishra
4 years ago

Hi Ravi, What is Pref Class in this tutorial, as you have not mentioned anywhere in this post. And also i try to get source code but always it is giving connection time out after try of 2-3 min…i think may be source code repository is down or something else…please help me to download source code for this post.

Dibyajyot
4 years ago

Please do a sync adapter tutorial

Ravi Tamada
4 years ago
Reply to  Dibyajyot

Oh the way… got busy from few weeks ..

Ahmet Cevahir Çinar
Ahmet Cevahir Çinar
4 years ago

At Book.java file,
I get an error:
“Error:(24, 17) error: Setter setId is not associated to any field”
I look some sources but I dont resolve my problem. Please help.

Ravi Tamada
4 years ago

Can you paste your Class code here Book.java

Ahmet Cevahir Çinar
Ahmet Cevahir Çinar
4 years ago
Reply to  Ravi Tamada

Hi Ravi Tamada,
I change variable names and this error end.
For example: Id= book_id
Thanks for your reply.

Ravi Tamada
4 years ago

I need to see your setter / getter method. Anyways use Android Studio code generate option to generate the setter / getter methods.

Kuldeep Mishra
Kuldeep Mishra
4 years ago

Hi :disqus @disqus_VqKuJF0GgB:disqus ,
On item delete i’m getting error plz help me…
Exception:
java.lang.IllegalStateException: Object is no longer managed by Realm. Has it been deleted?

I’m using realm 1.0.0. so there no constructor like this RealmBaseAdapter(Context context, RealmResults realmResults, boolean automaticUpdate) is available…no automaticUpdate parameter is there..

Zhuinden
Zhuinden
4 years ago
Reply to  Kuldeep Mishra

You should not call `adapter.notifyDataSetChanged()` manually after you commit synchronous transaction on the UI thread. You should use a change listener on your results, and notify the adapter in that.

Harsh
Harsh
4 years ago

Hi Ravi, How to scan business card and fetch information from the card? Do you have any example of that type? If not please develop this kind of example also as this will be more helpful for large amount of people including me as well.
Thanks.

Ravi Tamada
4 years ago
Reply to  Harsh

Hi Harsh

You need to use OCR library to read the text from an image. Please search for android open source OCR library. I don’t have a name to suggest right now.

Harsh
Harsh
4 years ago
Reply to  Ravi Tamada

Thanks for the reply Ravi. I have used OCR library but not getting results as expected. I want to develop business card scanning app like CamCard. So is there any way that you can help me?

Ravi Tamada
4 years ago
Reply to  Harsh

What you mean by not getting results as expected?

Harsh
Harsh
4 years ago
Reply to  Ravi Tamada

Hi, When i scan any business card, very few time it gives some of the expected result, otherwise it will displays the junk characters. I have used tesseract library for scanning.

Karani Anand
Karani Anand
4 years ago

I would like to say thanks for all your efforts. All the best for Great Future.

i want to build Dictionary App using Realm database. and i have words in text file format. please any one suggest, how to do?

Androider
Androider
4 years ago

Hello, Ravi Tamada!

I have a problem.. please see it here:

http://stackoverflow.com/questions/37903176/cannot-pass-parameters-to-super-in-a-classs-constructor-that-extends-realmba

I try to solve it from days ago, but I didn’t solve it until now! 🙁

Androider
Androider
4 years ago

Hello, Ravi Tamada!

I have a problem.. please see it here:

http://stackoverflow.com/questions/37903176/cannot-pass-parameters-to-super-in-a-classs-constructor-that-extends-realmba

I try to solve it from days ago, but I didn’t solve it until now! 🙁

Suresh Basnet
Suresh Basnet
4 years ago

how can i use foreign keys to establish connection between two tables?

Zhuinden
Zhuinden
4 years ago
Reply to  Suresh Basnet

`RealmList`

Desarrollo Theworkshop
Desarrollo Theworkshop
4 years ago

new version of realm.io dont have methods reamlm.allobjects, realm.refresh and maybe more

Zhuinden
Zhuinden
4 years ago

I’ve updated this guide’s content to the latest Realm in my `realm-book-example` on Github.

Collins Mucheru
Collins Mucheru
4 years ago
Reply to  Zhuinden

@disqus_vnjmcP8nNZ:disqus could you kindly do a blog post that explains your genius (https://github.com/Zhuinden/realm-book-example), or work with Ravi to explain it. Us rookies would really appreciate it. Thanks in advance.

Zhuinden
Zhuinden
4 years ago

Technically I wrote the README.MD file for that, and also at the top of the github page, it says this is a repository that accompanies my Medium article called “How to use Realm like a champ”

Collins Mucheru
Collins Mucheru
4 years ago
Reply to  Zhuinden

Yeah, I saw all that before I wrote this comment. It’s just that some of the patterns you’ve used are pretty interesting and seem complex. I’ll have to do quite a bit of reading before I can even begin to comprehend what you’ve written. Thank you for the guide though.

Zhuinden
Zhuinden
4 years ago

If anything is unclear, please specify it and I’ll add it to either the readme or the article or I’ll just make a third article that’s more tutorial-y. I’m monitoring my GitHub issues along with Realm-Java’s issues (which I check pretty often), so it’s likely I’ll respond at a reasonable time too

Collins Mucheru
Collins Mucheru
4 years ago
Reply to  Zhuinden

You rewrote the tutorial and used complex concepts that rookies who come to help from Ravi barely understand. Let me break down what I don’t understand using the packages:

Nothing is happening in the MainActivity.java class, why?

application: I get what RealmInitialData.java does but the last 3 methods of the class are incomprehensible.

data.entity: I get what the Book.java Class does, but I can’t for the life of me get what RealmString.java does

paths.books: BooksActivity is understandable but the moment you implement BooksPresenter.ViewContract I’m lost and I can no longer understand BooksActivity. I’ve used the normal RecyclerViewAdapter so I kinda comprehend BooksAdapter.java. As for BooksAddBookView.java, BooksPresenter.java and BooksAddBookView.java I’m completely lost.

You seem to be using some interesting ‘veteran’ design pattern where even your presentation of views is modularized. I’m also new to Butterknife, which i think contributes to my scanty understanding of your poetic code.

NB: Even Realm themselves are stuck showing us examples based on version 0.8.XX (https://realm.io/news/android-recycler-view/)

Kindly make an effort to explain your work to us so we can also use Realm and Butterknife like champs. Thank you 🙂

Zhuinden
Zhuinden
4 years ago

– Actually, lots of things are happening in MainActivity.

It creates the retained fragment (BooksScopeListener) that reference counts the activity count and opens/closes the Realm, and also creates the presenter instance (because retained fragments survive configuration change.) It also handles all events that have UI stuff going on – showing the “add book” dialog and the “edit book” dialog.

The AddBookView is the content of the dialog that’s inflated when you click the button that has to show a dialog in R.layout.edit_item’s XML.

Ravi did the same thing when he calls `inflater.inflate(R.layout.edit_item, null)` and sets this as the content of the dialog, except he set the click listeners manually after inflation, while I used a custom viewgroup instead which handles the binding with ButterKnife by default.

RealmString is pretty much a placeholder for the workaround of list of primitives (the workaround is `RealmList` ) but I don’t use that anywhere so heed it no mind.

`RealmInitialData` is a transaction. It inserts the elements into the Realm on first execution. The hashcode/equals just makes it so that every instance of `RealmInitialData` is the same. You’d have to do this for Migration too.

As for the presenter, well, it’s for your own benefit to delegate UI events to an external class and handle logic there instead of mashing everything in the Activity 🙂 For more info, you should to the GOOGLE CODELABS ANDROID TESTING guide, that is where `.ViewContract` is from.

Collins Mucheru
Collins Mucheru
4 years ago
Reply to  Zhuinden

Thank you. You’ve cleared up for me what I was finding so hard to grasp. Now it’s so much simpler 🙂

Collins Mucheru
Collins Mucheru
4 years ago
Reply to  Zhuinden
Raja Sekaran
Raja Sekaran
4 years ago

Hi Ravi,

Try GreenDao database, it really better than this.

Zhuinden
Zhuinden
4 years ago
Reply to  Raja Sekaran

honestly, this example is overcomplicated and outdated (0.82.1? The latest version is 1.1.1). I’ve updated this guide’s content to the latest Realm in my `realm-book-example` on Github.

Imam Kashif
Imam Kashif
4 years ago

Hello Ravi, I am using Sugar ORM for most of my apps. Please suggest me which one is better, Realm or Sugar ORM by satyan.

Zhuinden
Zhuinden
4 years ago
Reply to  Imam Kashif

Well, SugarORM is terrible. So Realm.

Nikolai Vasilev
Nikolai Vasilev
4 years ago

I cannot understand why you request all these fragments, activities and application in the .with() method parameters. They are not used in the constructor at all…. All the different .with() methods are same and can be removed when the different parameter logic is not making difference

Zhuinden
Zhuinden
4 years ago

Yeah, me neither, and it’s not even a proper solution because the Realm instance is never closed.

Mouad Ghandi
Mouad Ghandi
4 years ago

Thanks Ravi for this great article,
Please if you can underscores the utility of Prefs used in both “BooksAdapter” and “MainActivity” as Prefs.with(this).setPreLoad(true);
and how can we import it ? it still red in my project.

Best regards,

Kiran Benny Joseph
Kiran Benny Joseph
3 years ago
Reply to  Mouad Ghandi

He is not included Prefs class. anyway thanks for the tutorial

Govarthanan Ravi
Govarthanan Ravi
4 years ago

Hi can someone tell me what is the difference between adding library as classpath Vs adding it as a dependency

For example on Realm website they tell that inorder to include realm the following two steps should be followed
Step:1
dependencies {
classpath “io.realm:realm-gradle-plugin:1.1.0”
}
Step:2
apply plugin: ‘realm-android’ on build.gradle file

but in the above example ravi has asked to include
compile ‘io.realm:realm-android:0.82.1’

how do they both differ and in what means

In other words what is the difference between compile dependencies and classpath dependencies

Zhuinden
Zhuinden
4 years ago

Using the `compile` dependency adds the project as a JAR, but adding it on the classpath adds it as a Gradle Plugin (which will add it through AAR)

Govarthanan Ravi
Govarthanan Ravi
4 years ago
Reply to  Zhuinden

Thanks Zhuinden

Viet Nam
Viet Nam
4 years ago

good

Vladimir Yerokhin
Vladimir Yerokhin
4 years ago

Nice article! Thank you!

Zhuinden
Zhuinden
4 years ago

It’s actually very outdated.

Zhuinden
Zhuinden
4 years ago

This article is outdated and not structured well, so I rewrote it in my `realm-book-example` repository on Github. (I can’t link it because if I do, the comment becomes “Pending”).

Vyshnav Ramesh
4 years ago
Reply to  Zhuinden

hello how can i find your github files?

Zhuinden
Zhuinden
4 years ago
Reply to  Vyshnav Ramesh

it’s on github com Zhuinden realm-book-example

Just add the “.” before the com, and add “/” between the spaces

Ganesh Giri
Ganesh Giri
4 years ago

How can find Realm database ?Any tool to export Realm DB.And view Db.Like SQLITE Browser.

Zhuinden
Zhuinden
4 years ago
Reply to  Ganesh Giri

You just have to copy the file out from the internal storage to somewhere accessible, or you can use stetho-realm (I don’t know if that can export it, but it can definitely view it)

Raj
Raj
4 years ago
Reply to  Ganesh Giri

Only option is to use stetho. Please refer simple video to know about it.
https://www.youtube.com/watch?v=iyXpdkqBsG8

Vishal Kumar
Vishal Kumar
4 years ago

Hello Ravi ,

How can get distinct” or “group by” results in realm Database

Zhuinden
Zhuinden
4 years ago
Reply to  Vishal Kumar

Distinct with distinct. Group by is not supported.

webserveis
4 years ago

Please migrate code for realm 2.0.0

Zhuinden
Zhuinden
4 years ago
Reply to  webserveis

Refer to my example / guide on Github under the name “realm-book-example”, it is up-to-date to Realm 1.2.0, which is close to 2.0.0 compatible apart from the `Realm.init(Context)` call

Mahdi Pishguy
4 years ago
Reply to  Zhuinden

new version of Realm has 6MB!!

Zhuinden
Zhuinden
4 years ago
Reply to  Mahdi Pishguy

If that is too much, you can do abiSplits, although I think it’s more hassle than it’s worth.

Vicky Donor
Vicky Donor
4 years ago

You should declare getInstance() method as an instance Method not Class(Static) method it is not good approach.

Ravi Tamada
4 years ago
Reply to  Vicky Donor

Could you explain why?

Vicky Donor
Vicky Donor
4 years ago
Reply to  Ravi Tamada

If we firstly call Controller.getInstance() it will return null so i believe this is not good pattern.you may observe that Controller.with(Application).getRealm() is the better approach .If you want to call in Adapter then Controller.with((Activity)context.getApplicationContext()).getRealm() is another approach.

Ravi Tamada
4 years ago
Reply to  Vicky Donor

I never found Controller.getInstance() when you add the Application class in Manifest file.

Mahdi Pishguy
4 years ago

How can i use checkbox on RecyclerView without save selected items into database? when i use model which is extends from RealmObject on recyclerview, for every change one of this model must be we use Transaction, 😐 but i dont want to save it to database, its only for getting user selected Items, i can’t resolve this problem

Zhuinden
Zhuinden
4 years ago
Reply to  Mahdi Pishguy

I know this has been mentioned before, but you can contain temporary state in the adapter itself in a Map, and use onBindViewHolder based on that map rather than the objects directly.

172
0
Would love your thoughts, please comment.x
()
x