Getting started

Discover ObjectBox: The Lightning-Fast Mobile Database for Persistent Object Storage. Streamline Your Workflow, Eliminate Repetitive Tasks, and Enjoy a User-Friendly Data Interface.

Add ObjectBox to your project

You can get ObjectBox from the Central repository. To add ObjectBox to your Android project, follow these steps:

  1. Open the Gradle build file of your root project (not the ones for your app or module subprojects) and add a global variable for the version and the ObjectBox Gradle plugin:

/build.gradle(.kts)
buildscript {
    ext.objectboxVersion = "4.0.2" // For Groovy build scripts
    // val objectboxVersion by extra("4.0.2") // For KTS build scripts
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        // Android Gradle Plugin 4.1.0 or later supported
        classpath("com.android.tools.build:gradle:8.1.0")
        classpath("io.objectbox:objectbox-gradle-plugin:$objectboxVersion")
    }
}
  1. Open the Gradle build file for your app or module subproject and, after the com.android.application plugin, apply the io.objectbox plugin:

/app/build.gradle(.kts)
// Using plugins syntax:
plugins {
    id("com.android.application")
    id("kotlin-android") // Only for Kotlin projects
    id("kotlin-kapt") // Only for Kotlin projects
    id("io.objectbox") // Apply last
}

// Or using the old apply syntax:
apply plugin: "com.android.application"
apply plugin: "kotlin-android" // Only for Kotlin projects
apply plugin: "kotlin-kapt" // Only for Kotlin projects
apply plugin: "io.objectbox" // Apply last

If you encounter any problems in this or later steps, check out the FAQ and Troubleshooting pages.

  1. Then do "Sync Project with Gradle Files" in Android Studio so the Gradle plugin automatically adds the required ObjectBox libraries and code generation tasks.

Optional: Advanced Setup

The ObjectBox plugin uses reasonable defaults and detects most configurations automatically. However, if needed you can configure the model file path, the MyObjectBox package, enable debug mode and more using advanced setup options.

Define Entity Classes

Define your model by adding an @Entity (internal name for database objects) annotation to at least one class and an @Id annotation to one of the class variables. Learn more about the ObjectBox model here.

A simple entity representing a user could look like this:

User.java
@Entity
public class User {
    @Id 
    public long id;
    public String name;
}

Important:

  • Entities must have one ID property of type long (or Long in Kotlin, int in Dart). If you need to use other types, like a String ID, see the @Id annotation docs. Also, it must have non-private visibility (or non-private getter and setter methods).

  • Entities must also have a no-args constructor, or for better performance, a constructor with all properties as arguments. In the above example, a default, no-args constructor is generated by the compiler.

Support for many property types is already built-in, but almost any type can be stored with a converter.

For a deeper explanation and a look at all other available annotations (e.g. for relations and indexes) check the Entity Annotations page.

Generate ObjectBox code

Next, we generate some binding code based on the model defined in the previous step.

Build your project to generate the classes required to use ObjectBox, for example using Build > Make Project in Android Studio.

Note: If you make significant changes to your entities, e.g. by moving them or modifying annotations, make sure to rebuild the project so generated ObjectBox code is updated.

Among other files ObjectBox generates a JSON model file, by default to

  • app/objectbox-models/default.json for Android projects,

  • lib/objectbox-model.json for Dart/Flutter projects, or

  • <user-module-dir>/objectbox-model.json for Python projects

In Android Studio you might have to switch the Project view from Android to Project to see the default.json model file. Python checks for the call-stack to determine the user-module directory in which the JSON file is stored.

This JSON file changes when you change your entity classes (or sometimes with a new version of ObjectBox).

Keep this JSON file, commit the changes to version control!

This file keeps track of unique IDs assigned to your entities and properties. This ensures that an older version of your database can be smoothly upgraded if your entities or properties change.

The model file also enables you to keep data when renaming entities or properties or to resolve conflicts when two of your developers make changes at the same time.

Create a Store

BoxStore (Java) or Store (Dart) is the entry point for using ObjectBox. It is the direct interface to the database and manages Boxes. Typically, you want to only have a single Store (single database) and keep it open while your app is running, not closing it explicitly.

Create it using the builder returned by the generated MyObjectBox class, for example in a small helper class like this:

public class ObjectBox {
    private static BoxStore store;

    public static void init(Context context) {
        store = MyObjectBox.builder()
                .androidContext(context)
                .build();
    }

    public static BoxStore get() { return store; }
}

If you encounter UnsatisfiedLinkError or LinkageError on the build call, see App Bundle, split APKs and Multidex for solutions.

The best time to initialize ObjectBox is when your app starts. We suggest to do it in the onCreate method of your Application class:

public class ExampleApp extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ObjectBox.init(this);
    }
}

It is possible to specify various options when building a store. Notably for testing or caching, to use an in-memory database that does not create any files:

BoxStore inMemoryStore = MyObjectBox.builder()
        .androidContext(context)
        .inMemory("test-db")
        .build();

For more store configuration options: for Java see the BoxStoreBuilder and for Dart the Store documentation. (Python APIs will be published soon)

Basic Box operations

The Box class is likely the class you interact with most. A Box instance gives you access to objects of a particular type. For example, if you have User and Order entities, you need a Box object to interact with each:

Box<User> userBox = store.boxFor(User.class);
Box<Order> orderBox = store.boxFor(Order.class);

These are some of the operations offered by the Box class:

put inserts a new object or updates an existing one (with the same ID). When inserting, an ID will be assigned to the just inserted object (this will be explained below) and returned. put also supports putting multiple objects, which is more efficient.

User user = new User("Tina");
userBox.put(user);

List<User> users = getNewUsers();
userBox.put(users);

get and getAll: Given an object’s ID, get reads it from its box. To get all objects in the box use getAll .

User user = userBox.get(userId);

List<User> users = userBox.getAll();

query: Starts building a query to return objects from the box that match certain conditions. See queries for details.

Query<User> query = userBox
    .query(User_.name.equal("Tom"))
    .order(User_.name)
    .build();
List<User> results = query.find();
query.close();

remove and removeAll: Remove a previously put object from its box (deletes it). remove also supports removing multiple objects, which is more efficient. removeAll removes (deletes) all objects in a box.

boolean isRemoved = userBox.remove(userId);

userBox.remove(users);
// alternatively:
userBox.removeByIds(userIds);

userBox.removeAll();

count: Returns the number of objects stored in this box.

long userCount = userBox.count();

For a complete list of methods available in the Box class, check the API reference documentation for Java or Dart.

Asynchronous operations

ObjectBox has built-in support to run (typically multiple or larger) database operations asynchronously.

runInTxAsync and callInTxAsync: runs the given Runnable/Callable in a transaction on a background thread (the internal ObjectBox thread pool) and calls the given callback once done. In case of callInTxAsync the callback also receives the returned result.

store.callInTxAsync(() -> {
    Box<User> box = store.boxFor(User.class);
    String name = box.get(userId).name;
    box.remove(userId);
    return text;
}, (result, error) -> {
    if (error != null) {
        System.out.println("Failed to remove user with id " + userId);
    } else {
        System.out.println("Removed user with name: " + result);
    }
});

awaitCallInTx (Kotlin Coroutines only): wraps callInTxAsync in a coroutine that suspends until the transaction has completed. Likewise, on success the return value of the given callable is returned, on failure an exception is thrown.

try {
    val name = store.awaitCallInTx {
        val box = store.boxFor(User::class.java)
        val name = box.get(userId).name
        box.remove(userId)
        name
    }
    println("Removed user with name $name")
} catch (e: Exception) {
    println("Failed to remove user with id $userId")
}

Object IDs

By default IDs for new objects are assigned by ObjectBox. When a new object is put, it will be assigned the next highest available ID:

User user = new User();
// user.id == 0
box.put(user);
// user.id != 0
long id = user.id;

For example, if there is an object with ID 1 and another with ID 100 in a box, the next new object that is put will be assigned ID 101.

If you try to assign a new ID yourself and put the object, ObjectBox will throw an error.

If you need to assign IDs by yourself, have a look at how to switch to self-assigned IDs and what side effects apply.

Reserved Object IDs

Object IDs can not be:

  • 0 (zero) or null (if using java.lang.Long) As said above, when putting an object with ID zero it will be assigned an unused ID (not zero).

  • 0xFFFFFFFFFFFFFFFF (-1 in Java) Reserved for internal use.

For a detailed explanation see the page on Object IDs.

Transactions

While ObjectBox offers powerful transactions, it is sufficient for many apps to consider just some basics guidelines about transactions:

  • A put runs an implicit transaction.

  • Prefer put bulk overloads for lists (like put(entities)) when possible.

  • For a high number of DB interactions in loops, consider explicit transactions, such as using runInTx().

For more details check the separate transaction documentation.

Have an app with greenDAO? DaoCompat is for you!

DaoCompat is a compatibility layer that gives you a greenDAO like API for ObjectBox. It makes switching from greenDAO to ObjectBox simple. Have a look at the documentation and the example. Contact us if you have any questions!

Next steps

Last updated