[Android] Best way to open/close a database in multi-threaded?

I’m having trouble opening / closing the database, read/write in multithreaded to process data on Android.
So what’s the best way to deal with it?

My class :

public class CipherManager {

    public static final String DATABASE_NAME = "encypteddb.sqlite";
    private SQLiteDatabase database;
    private final File databaseFile;

    private static CipherManager instance;

    private String key;

    private CipherManager() {
        key = getKey();
        databaseFile = ApplicationController.getInstance().getDatabasePath(DATABASE_NAME);
        database = SQLiteDatabase.openOrCreateDatabase(databaseFile, key, null);
    }

    private String getKey() {
        try {
            RSACipher cipher = new RSACipher();
            return cipher.decrypt(getPassword());
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | IOException | InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return "";
    }

    private String getPassword() {
        return "dlasdjlakdj";
    }

    public synchronized static CipherManager getInstance() {
        if (instance == null) {
            instance = new CipherManager();
        }
        return instance;
    }

    public synchronized SQLiteDatabase getDatabase() {
        if (!database.isOpen()) {
            database = SQLiteDatabase.openDatabase(databaseFile.getPath(), key, null, SQLiteDatabase.OPEN_READWRITE);
        }
        return database;
    }

    public synchronized void close(){
        if (database.isOpen()){
            database.close();
        }
    }

    public void setDatabase(SQLiteDatabase database) {
        this.database = database;
    }
}

Hi @chihung93

SQLCipher for Android is compiled with -DSQLITE_THREADSAFE, however while the wrapping Java library contains some threading primitives for certain operations, is not entirely thread safe. It is recommended that you include a synchronization mechanism to allow for coordinated access to your connection.

1 Like

Hello @developernotes

I often get “System.err: java.lang.IllegalStateException: database not open” when I run on multithread.
Do u have any suggestion for solve this problem?

Hi @chihung93

We would recommend utilizing a synchronization mechanism to coordinate access to your connection. Within this function that provides the database connection, you can guard the connection instance to verify it is not null and open before returning.

Hi @chihung93
This is not related to SQLCipher but rather to how you close your SQLiteDatabase instance. you should know that your SQLiteHelper uses the same instance if it is already open, So when you simply close one instance you are also closing all the other instances created in the lifetime of that instance.
So the process of closing you SQLiteDatabase becomes a little trickier. I would personally recommend you count the references in SQLiteHelper and only close your database when there is no more reference attached to it.