Integrating ObjectBox Database in Android application

ObjectBox is a NoSQL database. According to the performance benchmark here, it is much faster than SQLite database.
In this tutorial, we are going to demonstrate how to integrate ObjectBox database in Android application by developing a simple app that creates a database and do the insert,update and delete operation.

At first step we shall have to add the dependency library.
In the project level build.gradle file add the following

buildscript {
    ext.objectboxVersion = '1.4.0'
    repositories {
        maven { url "http://objectbox.net/beta-repo/" }
    }
    dependencies {
        classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
    }
 
}
 
allprojects {
    repositories {
        maven { url "http://objectbox.net/beta-repo/" }
    }
}

and in the app level build.gradle add the following line

implementation "io.objectbox:objectbox-android:$objectboxVersion"
....
apply plugin: 'io.objectbox' // after applying Android plugin

The two gradle files will look the following.

The project level build.gradle file

// Top-level build file where you can add configuration options common to all sub-projects/modules.
 
buildscript {
 
    ext.objectboxVersion = '1.4.0'
    repositories {
        google()
        jcenter()
        maven { url "http://objectbox.net/beta-repo/" }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.1'
        classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
 
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
 
allprojects {
    repositories {
        google()
        jcenter()
        maven { url "http://objectbox.net/beta-repo/" }
    }
}
 
task clean(type: Delete) {
    delete rootProject.buildDir
}

The app level build.gradle file

apply plugin: 'com.android.application'
 
android {
    compileSdkVersion 26
    defaultConfig {
        applicationId "com.example.objectboxdemo"
        minSdkVersion 15
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
apply plugin: 'io.objectbox' // after applying Android plugin
 
dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "com.android.support:appcompat-v7:26.1.0"
    implementation "com.android.support.constraint:constraint-layout:1.0.2"
    implementation "com.android.support:design:26.1.0"
    implementation "com.android.support:recyclerview-v7:26.1.0"
    implementation "com.android.support:support-v4:26.1.0"
    implementation "io.objectbox:objectbox-android:$objectboxVersion"
 
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

For the sake of simplicity, we are going to develop a simple app that stores the football players names and their jersey numbers.
Let’s create the Entity class Player that contains the properties ‘name’ and ‘jerseyNumber’ and it must contain an ‘id’ property of long type. The class like look like the following.

import io.objectbox.annotation.Entity;
import io.objectbox.annotation.Id;
 
 
@Entity
public class Player {
    @Id
    private long id;
    private String name;
    private int jerseyNumber;
 
    public Player() {
 
    }
 
    public Player(long id, String name, int jerseyNumber) {
        this.id = id;
        this.name = name;
        this.jerseyNumber = jerseyNumber;
    }
 
    public long getId() {
        return id;
    }
 
    public void setId(long id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getJerseyNumber() {
        return jerseyNumber;
    }
 
    public void setJerseyNumber(int jerseyNumber) {
        this.jerseyNumber = jerseyNumber;
    }
}

Now we shall have to build the project in android studio by clicking ‘Build > Make project’. This will generate some class like MyObjectBox.java and some other class that will be used internally.

At this step, we are going to create our ObjectBoxDemoApp class by extending android Application class to initialize and hold the BoxStore.java reference which will be needed to execute different data storing/retreiving operations. Our ObjectBoxDemoApp class will look like the following.

import android.app.Application;
import com.example.objectboxdemo.model.MyObjectBox;
import io.objectbox.BoxStore;
 
 
public class ObjectBoxDemoApp extends Application {
 
    private BoxStore boxStore;
 
    @Override
    public void onCreate() {
        super.onCreate();
        boxStore = MyObjectBox.builder().androidContext(ObjectBoxDemoApp.this).build();
    }
 
    public BoxStore getBoxStore() {
        return boxStore;
    }
}

The manifest.xml should be updated like the following

<!--?xml version="1.0" encoding="utf-8"?-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.objectboxdemo">
 
    <application android:name="com.example.objectboxdemo.ObjectBoxDemoApp" android:allowbackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundicon="@mipmap/ic_launcher_round" 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">
            </category></action></intent-filter>
        </activity>
    </application>
 
</manifest>

We are going to handle the adding new player on clicking the floating action button of our MainAcitivity.java class and updating, deleting player in the PlayerView adapter class. In detail explanation of those two java are not included in this tutorial rather focus is kept on the database updating part.

At first we shall have to get the BoxStore object from our Application class. In our example the code should look like the following

BoxStore boxStore = ((ObjectBoxDemoApp) ((MainActivity)context).getApplication()).getBoxStore();

Now we have to get the specific box type Object that we want to deal with, here we have only one that is Player. The following code will do that for us

Box<player> playerBox = boxStore.boxFor(Player.class);

We are going to start by writing a query that will find the Player object by a given id. The following simple code will do it for us,

private Player getPlayerById(long id) {
	return playerBox.query().equal(Player_.id, id).build().findUnique();
}

The above one is a very simple query, to learn how to write complex query you should have a look at this.

Now let’s we want to add a new player in our database, to do so we shall have to write code like the following

playerBox.put(new Player(0, "Chilavert", 1);

In the above code we are passing id as 0. Setting id or null will let ObjecBox create a new Player and generate id automatically.

To update an object fist we shall have to get the Object like the way it was shown earlier, then we could just edit the object and put it back to playerBox object.

Finally to delete a player from our database we shall have to find that obect and then call remove method of our Box object (playerBox in this example). The following method could be used to perform the delete operation.

private void deletePlayer(long id) {
        Player player = getPlayerById(id);
        if(player != null) {
            playerBox.remove(id);
        }
}

The MainActivity class should look like the following

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
 
import com.example.objectboxdemo.R;
import com.example.objectboxdemo.adapter.PlayerListAdapter;
import com.example.objectboxdemo.model.Player;
 
import java.util.ArrayList;
import java.util.List;
 
public class MainActivity extends AppCompatActivity {
 
    private RecyclerView rvPlayerList;
    private List<player> playerList = new ArrayList&lt;&gt;();
    private PlayerListAdapter playerListAdapter;
    private FloatingActionButton fabAddPlayer;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
 
    private void initView() {
        playerListAdapter = new PlayerListAdapter(MainActivity.this, playerList);
        playerListAdapter.updatePlayers();
        rvPlayerList = (RecyclerView) findViewById(R.id.rvPlayerList);
        rvPlayerList.setHasFixedSize(true);
        LinearLayoutManager llm2 = new LinearLayoutManager(MainActivity.this);
        llm2.setOrientation(LinearLayoutManager.VERTICAL);
        rvPlayerList.setLayoutManager(llm2);
        rvPlayerList.setAdapter(playerListAdapter);
        fabAddPlayer = (FloatingActionButton) findViewById(R.id.fabAddPlayer);
        fabAddPlayer.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                playerListAdapter.showAddEditDialog(PlayerListAdapter.MODE_ADD, 0);
            }
        });
    }
 
}

And our most important PlayerListAdapter class where all the operations were done will look like the following

import android.content.Context;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
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.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
 
import com.example.objectboxdemo.ObjectBoxDemoApp;
import com.example.objectboxdemo.R;
import com.example.objectboxdemo.activity.MainActivity;
import com.example.objectboxdemo.model.Player;
import com.example.objectboxdemo.model.Player_;
 
import java.util.List;
 
import io.objectbox.Box;
import io.objectbox.BoxStore;
 
/**
 * Created by AsifMoinul on 1/13/2018.
 */
 
public class PlayerListAdapter extends RecyclerView.Adapter<playerlistadapter.playerlistholder> {
 
    public static final int MODE_ADD = 0;
    public static final int MODE_EDIT = 1;
    public static final int MODE_DELETE = 2;
 
    private Context context;
    private List<player> playerList;
 
    private BoxStore boxStore;
    private Box<player> playerBox;
 
    public PlayerListAdapter(Context context, List<player> playerList) {
        this.context = context;
        this.playerList = playerList;
        //getting BoxStore object
        boxStore = ((ObjectBoxDemoApp) ((MainActivity)context).getApplication()).getBoxStore();
        //getting Player Box object
        playerBox = boxStore.boxFor(Player.class);
 
    }
 
    @Override
    public PlayerListAdapter.PlayerListHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).
                inflate(R.layout.row_player_list, parent, false);
        return new PlayerListHolder(itemView);
    }
 
    @Override
    public void onBindViewHolder(PlayerListAdapter.PlayerListHolder holder, int position) {
        final Player player = playerList.get(position);
        holder.tvPlayerWithJersey.setText(player.getName() +" ("+player.getJerseyNumber()+")");
    }
 
    @Override
    public int getItemCount() {
        return playerList.size();
    }
 
    public class PlayerListHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
 
        protected TextView tvPlayerWithJersey;
        protected ImageButton btnEdit, btnDelete;
 
        public PlayerListHolder(View itemView) {
            super(itemView);
            tvPlayerWithJersey = (TextView) itemView.findViewById(R.id.tvPlayerWithJersey);
            btnEdit = (ImageButton) itemView.findViewById(R.id.btnEdit);
            btnDelete = (ImageButton) itemView.findViewById(R.id.btnDelete);
            btnEdit.setOnClickListener(this);
            btnDelete.setOnClickListener(this);
        }
 
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btnEdit:
                    showAddEditDialog(MODE_EDIT, playerList.get(getAdapterPosition()).getId());
                    break;
                case R.id.btnDelete:
                    showAddEditDialog(MODE_DELETE, playerList.get(getAdapterPosition()).getId());
                    break;
            }
 
        }
    }
 
    /**
     * Shows a simple dialog to add/edit/delete
     * @param mode mode of operation i.e, add/edit/delete
     * @param id id of the player, 0 for new player
     */
    public void showAddEditDialog(final int mode, final long id) {
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
        LayoutInflater inflater = ((MainActivity)context).getLayoutInflater();
        final View dialogView = inflater.inflate(R.layout.dialog_player_add, null);
        dialogBuilder.setView(dialogView);
 
        final EditText etPlayerName = (EditText) dialogView.findViewById(R.id.etPlayerName);
        final EditText etJerseyNumber = (EditText) dialogView.findViewById(R.id.etJerseyNumber);
 
        String title = "";
        switch (mode) {
            case MODE_ADD:
                title = "Add Player";
                break;
            case MODE_EDIT:
                title = "Edit Player";
                Player playerToEdit = getPlayerById(id);
                etPlayerName.setText(playerToEdit.getName());
                etJerseyNumber.setText(String.valueOf(playerToEdit.getJerseyNumber()));
                break;
            case MODE_DELETE:
                title = "Delete Player";
                Player playerToDelete = getPlayerById(id);
                etPlayerName.setText(playerToDelete.getName());
                etJerseyNumber.setText(String.valueOf(playerToDelete.getJerseyNumber()));
                etPlayerName.setKeyListener(null);
                etJerseyNumber.setKeyListener(null);
                break;
            default:
                break;
        }
        dialogBuilder.setTitle(title);
 
        dialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                switch (mode) {
                    case MODE_ADD:
                        if(etPlayerName.getText().toString().trim().isEmpty() || etJerseyNumber.getText().toString().trim().isEmpty()) {
                            Toast.makeText(context, "Name and Jersey number can not be empty.", Toast.LENGTH_SHORT).show();
                            return;
                        }
                        addOrUpdatePlayer(new Player(0, etPlayerName.getText().toString().trim(), Integer.parseInt(etJerseyNumber.getText().toString().trim())));
                        updatePlayers();
                        break;
                    case MODE_EDIT:
                        addOrUpdatePlayer(new Player(id, etPlayerName.getText().toString().trim(), Integer.parseInt(etJerseyNumber.getText().toString().trim())));
                        updatePlayers();
                        break;
                    case MODE_DELETE:
                        deletePlayer(id);
                        updatePlayers();
                        break;
                    default:
                        break;
                }
            }
        });
        dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                //do nothing
            }
        });
        AlertDialog b = dialogBuilder.create();
        b.show();
    }
 
    public void setPlayers(List<player> players) {
        playerList = players;
        notifyDataSetChanged();
    }
    //Database related operation here
 
    private Player getPlayerById(long id) {
        return playerBox.query().equal(Player_.id, id).build().findUnique();
    }
 
    private void addOrUpdatePlayer(Player player) {
        playerBox.put(player);
    }
 
    private void deletePlayer(long id) {
        Player player = getPlayerById(id);
        if(player != null) {
            playerBox.remove(id);
        }
    }
 
    public void updatePlayers() {
        List<player> players = playerBox.query().build().find();
        this.setPlayers(players);
    }
 
}

The resulting app will look like following.

The source code of the app can be downloaded from here.

4 Comments

  1. Avil

    thanks buddy

    Reply
  2. Jordan

    Very helpful!

    Reply
  3. Irma

    You used the same gradle.build file for both the project level and app level.
    Can you please update the post with the correct code?

    Reply
    1. asif (Post author)

      Thanks Irma. Post updated with correct gradle files.

      Reply

Leave a Reply to Irma Cancel reply

Your email address will not be published. Required fields are marked *