Implementing ObjectBox in Flutter: A Practical Guide

Haris Bin Nasir Avatar

·

·

ObjectBox is a high-performance NoSQL database for mobile applications that is designed to be fast, efficient, and easy to use. It fits perfectly into Flutter projects, helping developers persist data locally with minimal boilerplate. Whether you’re building an offline-first app or just need local data storage, ObjectBox provides a powerful, reactive solution. In this guide, we will walk through how to set up ObjectBox in Flutter, explain how it works, and include code examples for you to follow.

What is ObjectBox, and Why Should You Use It?

ObjectBox is a database that works with objects, which means you don’t need to write SQL queries to interact with your data. It supports high-speed reads and writes and is optimized for mobile, making it a popular choice for developers building mobile apps that require offline capabilities or need to manage large amounts of local data.

ObjectBox’s key advantages include:

  • Speed: ObjectBox is up to 10x faster than SQLite.
  • Ease of Use: It works directly with Dart objects, reducing the need for complex data transformations.
  • Scalability: ObjectBox is designed to scale as your app grows, capable of handling large datasets.
  • Reactive Streams: It has built-in support for reactive data streams, which is perfect for Flutter apps that require real-time updates.

Let’s start by setting up ObjectBox in your Flutter project.

How to Set Up ObjectBox in a Flutter Project

To begin, you’ll need to add ObjectBox to your Flutter project. Here are the steps to get it up and running:

1. Add Dependencies

First, add the ObjectBox dependencies to your pubspec.yaml file:

  1. objectbox_flutter_libs:
    Provides the necessary ObjectBox libraries for Flutter, enabling high-performance local data storage on mobile devices. To get the dependency click here.
  2. objectbox:
    The core ObjectBox package that offers NoSQL database features, including efficient object persistence and database operations. To get the dependency click here.
  3. objectbox_generator:
    A code generation tool that automatically generates ObjectBox binding code from your Dart model classes with annotations like @Entity. To get the dependency click here.
  4. build_runner:
    A command-line tool used for generating code in Flutter projects, such as running the ObjectBox code generator for model classes. To get the dependency click here.
dependencies:
  objectbox_flutter_libs: ^4.0.3
  objectbox: ^4.0.3
  objectbox_generator: ^4.0.3
  build_runner: ^2.4.13

Run flutter pub get to install the packages.

flutter pub get

2. Set Up ObjectBox Model Classes

ObjectBox works with Dart objects, so you need to define the classes that will be stored in the database. Use annotations to define your entities.

import 'package:objectbox/objectbox.dart';

// Define an entity
@Entity()
class Task {
  int id = 0;  // 'id' will be automatically set by ObjectBox
  String title;
  bool isCompleted;

  Task({required this.title, this.isCompleted = false});
}

In the example above, @Entity() defines the Task class as a database entity. The id field is automatically set by ObjectBox, and the other fields represent the data attributes.

3. Generate ObjectBox Code

Once you’ve defined your entities, you need to generate the ObjectBox binding code. Use the following command to generate it:

flutter pub run build_runner build

This command generates all the necessary ObjectBox-related code in the background.

4. Initialize ObjectBox

Next, initialize ObjectBox in your app. Typically, this is done when the app starts.

import 'package:flutter/material.dart';
import 'objectbox.g.dart'; // Automatically generated file

late Store store; // The Store manages the ObjectBox database

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize ObjectBox
  store = await openStore();

  runApp(MyApp());
}

In this example, openStore() initializes the database and prepares it for use. The store variable represents the connection to the ObjectBox database and should be accessible throughout your app.

How to Perform CRUD Operations in ObjectBox

Now that ObjectBox is set up, let’s explore how to perform basic CRUD (Create, Read, Update, Delete) operations.

1. Creating Data (Inserting)

To insert data into the database, use the put() function. Here’s how to add a new Task:

void addTask(String title) {
  final taskBox = store.box<Task>();  // Access the Task box
  final newTask = Task(title: title);
  taskBox.put(newTask);  // Insert the task into ObjectBox
  print('Task added: ${newTask.title}');
}

In this example, box<Task>() is used to access the Task box (a box is like a table in SQL databases). The put() method inserts the task into the database.

2. Reading Data (Querying)

You can retrieve data from ObjectBox using the get() function or by querying the database. Here’s how to retrieve all tasks:

List<Task> getAllTasks() {
  final taskBox = store.box<Task>();
  return taskBox.getAll();  // Get all tasks from the database
}

This function returns a list of all Task objects stored in the database.

3. Updating Data

To update a record, you modify the object and use put() again. ObjectBox will automatically update the record if the id matches an existing record.

void updateTask(int id, bool isCompleted) {
  final taskBox = store.box<Task>();
  final task = taskBox.get(id);

  if (task != null) {
    task.isCompleted = isCompleted;
    taskBox.put(task);  // Update the task
    print('Task updated: ${task.title}');
  }
}

4. Deleting Data

To delete a task, use the remove() function and pass the id of the object you want to delete:

void deleteTask(int id) {
  final taskBox = store.box<Task>();
  taskBox.remove(id);  // Remove task from the database
  print('Task deleted with id: $id');
}

This deletes the task with the specified id from the database.

Using Reactive Queries in ObjectBox

One of the most powerful features of ObjectBox is its reactive query support. This allows you to listen for changes in the data and automatically update your UI. In Flutter, you can use StreamBuilder for this.

Here’s an example of how to use reactive queries with ObjectBox:

Stream<List<Task>> getTasksStream() {
  final taskBox = store.box<Task>();
  final query = taskBox.query().watch(triggerImmediately: true);

  return query.map((query) => query.find());
}

You can then use StreamBuilder in your UI to reactively display the tasks:

StreamBuilder<List<Task>>(
  stream: getTasksStream(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }

    final tasks = snapshot.data ?? [];

    return ListView.builder(
      itemCount: tasks.length,
      itemBuilder: (context, index) {
        final task = tasks[index];
        return ListTile(
          title: Text(task.title),
          trailing: Icon(
            task.isCompleted ? Icons.check_box : Icons.check_box_outline_blank,
          ),
        );
      },
    );
  },
)

In this example, whenever the data in the Task box changes, the StreamBuilder will rebuild the widget, ensuring that the UI is always in sync with the data.

Conclusion

ObjectBox provides a powerful and efficient way to handle local data storage in Flutter. From its ease of use to the high performance it offers, it’s a great option for developers building apps that require data persistence. In this guide, we’ve covered how to set up ObjectBox, create data models, and perform CRUD operations. With reactive streams, you can keep your UI up to date automatically, making it a perfect fit for Flutter’s reactive architecture.

Happy Coding…!!!

Leave a Reply

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