Skip to content
This repository has been archived by the owner on May 1, 2020. It is now read-only.

Changes in SquiDB 3.0

Sam Bosley edited this page Jun 23, 2016 · 4 revisions

SquiDB 3.0 brings one major change -- support for iOS using Google's j2objc translation tool. In other words, SquiDB can now be used as a SQLite database layer in a cross-platform Java library on Android or iOS when using j2objc. Write your database code and business logic in Java once, and the behavior across both platforms will be consistent.

What is different in SquiDB 3.0?

Conceptually, little has changed in the public API of SquiDB 3.0. The changes center mostly around the fact that all Android-specific dependencies have been removed from the SquiDB core, and some classes and interfaces have been renamed to more accurately reflect their uses in a cross-platform world.

New dependencies

The SquiDB core module is now a standalone Java project that does not contain any low-level SQLite access code. In order to connect your SquidDatabase to SQLite, you will need to add a dependency on the squidb-android module for Android projects or the squidb-ios module for iOS projects. Upgrading won't increase your method count -- the squidb-android module merely extracts the Android-specific components from SquiDB 2.0.

On Android:

dependencies {
    // ... other squidb modules still declared here
    compile 'com.yahoo.squidb:squidb-android:3.0.0'
}

When running on iOS, you will need to compile SquiDB and the squidb-ios module using j2objc. Note that j2objc requires building from sources, so you will just have to point your build script to the cloned sources in the squidb-ios directory. See this wiki page for more details about building SquiDB in a cross-platform library.

The code generator also receives some updates to facilitate generating model objects that will work on either platform. By default, the code generator will now generate model objects with no Android-specific features (they will not implement Parcelable, work with ContentValues, etc.). If you don't care about these Android-specific features, you can use the code generator as-is with no additional configuration. If on the other hand you want to generate models that use these features for Android platforms, you can specify an option in your build.gradle's apt configuration:

apt {
    arguments {
        squidbOptions 'androidModels'
    }
}

Interface changes

Classes and interfaces introduced in SquiDB 2.0 for binding to a custom SQLite build have been renamed and adjusted in SquiDB 3.0 to reflect their more general purposes as the interfaces to all low-level SQLite APIs. SQLiteDatabaseWrapper has been renamed to ISQLiteDatabase. Similarly, SQLiteOpenHelperWrapper has been renamed to ISQLiteOpenHelper. For example:

This:

public class MyDatabase extends SquidDatabase {
    // ...
    @Override
    protected boolean onUpgrade(SQLiteDatabaseWrapper db, int oldVersion, int newVersion) {
        // Do upgrade
        return true;
    }
    // ...
}

Becomes this:

public class MyDatabase extends SquidDatabase {
    // ...
    @Override
    protected boolean onUpgrade(ISQLiteDatabase db, int oldVersion, int newVersion) {
        // Do upgrade
        return true;
    }
    // ...
}

Default implementations of these interfaces are provided for both platforms as well as custom SQLite builds on Android, so you should not ever have to implement these interfaces yourself.

SquidDatabase changes

A required abstract method has been added to SquidDatabase: ISQLiteOpenHelper createOpenHelper(String databaseName, OpenHelperDelegate delegate, int version). This method is responsible for creating the component that binds to the low-level SQLite APIs.

If you are only using the library on Android (i.e. not using SquiDB for cross-platform development), you can simply return an instance of AndroidOpenHelper from the squidb-android module, and you're done. (Or a SQLiteBindingsOpenHelper from squidb-sqlite-bindings if connecting to a custom SQLite build on Android):

public class MyDatabase extends SquidDatabase {
    // ...
    @Override
    protected ISQLiteOpenHelper createOpenHelper(String databaseName, OpenHelperDelegate delegate, int version) {
        Context context = // get a Context object somehow, either via dependency injection or by passing it to the SquidDatabase constructor
        return new AndroidOpenHelper(context, databaseName, delegate, version);
        // or return new SQLiteBindingsOpenHelper(context, databaseName, delegate, version); if connecting to a custom sqlite build
    }
    // ...
}

If you are building a cross-platform library, you will need to write logic that returns an AndroidOpenHelper when on Android or an IOSOpenHelper when on iOS. Because the shared library can't depend on platform-specific components, you will probably need to inject or otherwise supply some kind of provider to your SquidDatabase subclass for creating the correct component. There are many ways to accomplish this, but here is one simple example:

public interface SQLiteOpenHelperProvider {
    ISQLiteOpenHelper createOpenHelper(String databaseName, delegate, version);
}

public class MyDatabase extends SquidDatabase {

    public static SQLiteOpenHelperProvider sSQLiteOpenHelperProvider;
    // ...
    @Override
    protected ISQLiteOpenHelper createOpenHelper(String databaseName, OpenHelperDelegate delegate, int version) {
        return sSQLiteOpenHelperProvider.createOpenHelper(databaseName, delegate, version);
    }
    // ...

}

// At runtime on Android:
MyDatabase.sSQLiteOpenHelperProvider = new SQLiteOpenHelperProvider() {
    @Override
    public ISQLiteOpenHelper createOpenHelper(String databaseName, delegate, version) {
        return new AndroidOpenHelper(getApplicationContext(), databaseName, delegate, version);
    }
}

// At runtime on iOS:
// (note that you will need to build a full file path from the db name for IOSOpenHelper)
MyDatabase.sSQLiteOpenHelperProvider = new SQLiteOpenHelperProvider() {
    @Override
    public ISQLiteOpenHelper createOpenHelper(String databaseName, delegate, version) {
        String pathToDb = getPath(databaseName);
        return new IOSOpenHelper(pathToDb, delegate, version);
    }
}

The squidb-tests and SquiDB sample projects both contain variations on this kind of pattern if you want to look at some real-world examples.

Note that createOpenHelper replaces the old (optional) getOpenHelper method that was used to connect to custom SQLite builds.

Finally, all methods with Android dependencies (e.g. those using ContentValues) have been removed from the interface. These methods were deprecated in recent releases of SquiDB 2.0.x, and are not essential to any core SquiDB features, so it's unlikely this change will have much impact on the majority of users. The constructor for SquidDatabase now takes no arguments (instead of a Context argument). The disableDefaultContentValues option in the code generator has been renamed to disableDefaultValues.

SquidCursor changes

SquidCursor is no longer an instance of android.database.Cursor. Instead, it implements SquiDB's new ICursor interface, which is just a redeclaration of the majority of the Android Cursor interface in the SquiDB namespace. All of the core methods for interacting with the cursor are still there, so you will probably be able to continue using SquidCursor as you have been with no changes necessary. The one exception: if you are running on Android, and you need to get an instance of an Android Cursor from a SquidCursor (e.g. if you are implementing a ContentProvider), you can do this:

SquidCursor<?> squidCursor = db.query(...);
Cursor androidCursor = (Cursor) squidCursor.getCursor();
// SquidCursor always wraps an Android Cursor under the hood on Android, so this cast is safe

Why support j2objc?

In the developer's words, "J2ObjC is an open-source command-line tool from Google that translates Java source code to Objective-C for the iOS (iPhone/iPad) platform". They explain all the capabilities of the tool much better than we could, so we highly recommend you check out their site and documentation for full details, but the gist is that it facilitates writing platform-independent business logic in a single Java library, which can then be run on both Android and iOS platforms. The philosophy is that business logic and data models should be shared/cross-platform, while UI code should be implemented separately on each platform using native frameworks.

When writing a cross-platform library, finding a good, robust mechanism for data storage can be daunting. The Android SQLite APIs depend heavily on Android OS features, and so the j2objc tool does not translate them.

SquiDB 3.0 introduces a new module, squidb-ios. This module includes a fork of the Android SQLite APIs that removes all OS-level dependencies but preserves the structure and behavior of those APIs -- and this fork CAN be translated by j2objc. Because this module is a direct port of the Android code, consistent database behavior across platforms is guaranteed. Transaction nesting, locking, connection pooling, etc. -- it all behaves the same regardless of whether you're running on Android or iOS. Write your database code once in Java, and run it on both platforms.


See also: