agrosner / DBFlow

A blazing fast, powerful, and very simple ORM android database library that writes database code for you.
MIT License
4.87k stars 598 forks source link

Releasing statement in a finalizer #1496

Closed WonderCsabo closed 6 years ago

WonderCsabo commented 6 years ago

We are using DBFlow 4.2.1 and SQLCipher 3.5.7.

When we are saving model objects, these warning messages pop up.

Releasing statement in a finalizer. Please ensure that you explicitly call close() on your cursor: UPDATE <redacted>
net.sqlcipher.database.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
    at net.sqlcipher.database.SQLiteCompiledSql.<init>(SQLiteCompiledSql.java:62)
    at net.sqlcipher.database.SQLiteProgram.<init>(SQLiteProgram.java:109)
    at net.sqlcipher.database.SQLiteStatement.<init>(SQLiteStatement.java:39)
    at net.sqlcipher.database.SQLiteDatabase.compileStatement(SQLiteDatabase.java:1589)
    at com.raizlabs.android.dbflow.sqlcipher.SQLCipherDatabase.compileStatement(SQLCipherDatabase.java:56)
    at com.raizlabs.android.dbflow.structure.ModelAdapter.getUpdateStatement(ModelAdapter.java:129)
    at com.raizlabs.android.dbflow.sql.saveable.ModelSaver.save(ModelSaver.java:36)
    at com.raizlabs.android.dbflow.structure.ModelAdapter.save(ModelAdapter.java:190)
    <redacted>

We are passing the databaseWrapper to the save() method.

agrosner commented 6 years ago

its because it gets the statements when the parameters are less, thus not closing them. makes sense. for now you can patch this with:


public class ModelSaverFix<TModel> extends ModelSaver<TModel> {

    @Override
    public synchronized boolean save(@NonNull TModel model, @NonNull DatabaseWrapper wrapper) {
        boolean exists = getModelAdapter().exists(model, wrapper);

        if (exists) {
            exists = update(model, wrapper);
        }

        if (!exists) {
            exists = insert(model, wrapper) > INSERT_FAILED;
        }

        if (exists) {
            NotifyDistributor.get().notifyModelChanged(model, getModelAdapter(), BaseModel.Action.SAVE);
        }

        // return successful store into db.
        return exists;
    }
}

then in TableConfig.Builder specify it as the modelAdapterModelSaver() parameter.

agrosner commented 6 years ago

in develop, try it out with commit 7d0d039f1a instead of version 4.2.2 until 4.2.3 is released.

WonderCsabo commented 6 years ago

Thanks for the quick fix and for offering a workaround! I look forward to the new release. 🙂

On Dec 19, 2017 21:08, "Andrew Grosner" notifications@github.com wrote:

its because it gets the statements when the parameters are less, thus not closing them. makes sense. for now you can patch this with:

public class ModelSaverFix extends ModelSaver {

@Override
public synchronized boolean save(@NonNull TModel model, @NonNull DatabaseWrapper wrapper) {
    boolean exists = getModelAdapter().exists(model, wrapper);

    if (exists) {
        exists = update(model, wrapper, getModelAdapter().getUpdateStatement(wrapper));
    }

    if (!exists) {
        exists = insert(model, getModelAdapter().getInsertStatement(wrapper), wrapper) > INSERT_FAILED;
    }

    if (exists) {
        NotifyDistributor.get().notifyModelChanged(model, getModelAdapter(), BaseModel.Action.SAVE);
    }

    // return successful store into db.
    return exists;
}

}

then in TableConfig specify it as the modelSaver() parameter.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/Raizlabs/DBFlow/issues/1496#issuecomment-352871958, or mute the thread https://github.com/notifications/unsubscribe-auth/AAdU5Sm7zA5tVikOeUveB7YhVND8YVE6ks5tCBengaJpZM4RG5iW .