I'm using realm for persistence in my app.
At the moment, I have a list of items in a simple pagination fashion.
Make a server request
Get items back
Update the UI
Save list to realm
User scrolls to the end of the list, get the next set of elements and repeat
above
Realm code:
try {
mDbManager.beginTransaction();
mDbManager.copyToRealm(list);
mDbManager.commitTransaction();
Logger.v("Realm ", "Copied list to realm");
} catch (Exception e) {
Logger.e("Realm Something went wrong ", e);
}
I get the error because of this pagination loop:
java.lang.IllegalStateException: Nested transactions are not allowed. Use commitTransaction() after each beginTransaction().
I also tried closing the database after each commit but that didn't help.
How can I achieve this storage and resolve the nested transactions?
Or can anyone suggest a better design structure for this?
Thanks
Just make sure that while you catch the exception , you closes the transaction by mDbManager.closetransaction
You can use Realm.isInTransaction() to check if you have an open transaction.
Try to aviod this :
beginTransaction
beginTransaction
commitTransaction
commitTransaction
you should do something like this :
beginTransaction
commitTransaction
beginTransaction
commitTransaction
I think there're beginTransaction() before your code try to close it.
Related
I am currently using objectbox via koin dependency injection within my android app. It works fine however i need to re-initialise my DI and so i need to destroy the boxStore before. This is because i initialise the box via DI and if i do not destroy the current BoxStore I cannot create a new one.
I've found a similar post How to close Objectbox Store and delete data files however it hasn't solved my issue.
I have tried calling deleteAllFiles however i am getting an error.
BoxStore.deleteAllFiles(context, (BoxStoreBuilder.DEFAULT_NAME))
BoxStore.deleteAllFiles(context, null)
I am getting the error message:
java.lang.IllegalStateException: Cannot delete files: store is still open
this is on the line of code mentioned above. Any suggestions would be very helpful
solution:
i had to access each of my boxes individually and delete them one at a time.
fun clearAll(){
firstBox.box.removeAll()
secondBox.box.removeAll()
.......
}
fun closeAll(){
firstBox.box.close()
secondBox.box.close()
.......
}
You can just close the boxStore and then delete all files:
boxStore.close();
boxStore.deleteAllFiles();
There's also a static method for deleting all the files ( if you want to delete all files before you open boxStore )
It's the most efficient way.
Ref: https://github.com/objectbox/objectbox-java/issues/317
I can suggest a solution. You can get all entity classes and get each box and clear them.
boxStore.getAllEntityClasses().forEach( entityClass ->
boxStore.boxFor(entityClass
).removeAll());
I want to clear whole database when a user press logout button and loads a new data when another user login.I tried many solutions like
try {
Realm.deleteRealm(realmConfiguration);
} catch (Exception ex){
throw ex;
}
Also
try {
Realm.deleteRealmFile(getActivity());
//Realm file has been deleted.
} catch (Exception ex){
ex.printStackTrace();
//No Realm file to remove.
}
But neither of the code works.
Thanks in advance.
When you call Realm.deleteRealm(), you have to make sure all the Realm instances are closed, otherwise an exception will be thrown without deleting anything. By calling this method, all Realm files are deleted, which means all objects & schemas are gone. Catching all exceptions is a bad practise for any general cases.
Or you can call Realm.delelteAll() in a transaction block. This doesn't require all Realm instances closed. It will just delete all the objects in the Realm without clearing the schemas. And again, don't catch all exceptions.
If you are sure there are not any other databases you want to save, you can delete all the other data also. you can follow this answer
Clear Application's Data Programmatically
Why does this code endlessly execute it's .subscribe(..) part? I assumed that event will be fired only once, when matching Content object will be found. But it starts over and over again.
realm.where(Content.class)
.equalTo("keyID", id)
.findFirst()
.<Content>asObservable()
.map(this::getPostFromContent)
.subscribe(post -> {
loadComments(post.getId());
});
And if I change to .findFirstAsync() it throws an exception:
"Can't access a row that hasn't been loaded, make sure the instance is loaded by calling RealmObject.isLoaded()"
I am using latest version of realm.
UPDATE
I was able to make this work by using:
realm.where(RealmWrappedContent.class)
.equalTo("keyID", id)
.findFirstAsync()
.<RealmWrappedContent>asObservable()
.filter(post -> post.isLoaded())
.first()
.map(this::getPostFromContent)
.subscribe(post -> {
loadComments(post.getId());
});
But that's way too many thing you need to write just to use realm objects as observables. Is there any better way?
The default behaviour is submitting each time there is an update. In that case you need to use filter/first to only get 1 item as you found out.
If you want to change that behaviour in your entire app, you can also provide your own RxObservableFactory implementation as described here: https://realm.io/docs/java/latest/#rxjava.
The default factory is called RealmObservableFactory and it should be fairly easy to either wrap that or provide your own implementation that does what your want for all observables.
I'm using GreenDao to store a lot of data, coming from a REST service.
A lot of my entities are connected with relations.
Everything works great, but tomorrow I have to implement a rocksolid workflow.
When I load my data I have to check if an error occurs.
If so, I have to make sure nothing is stored in the SQLite DB.
Normally I would work with transactions and rollback in case of an exception,
otherwise commit to the db.
For now I just use insertordelete to save an entity, everytime I created an object.
What would be the way to implement this?
On inserts and updates Greendao checks if there is a ongoing transaction. If that is the case greendao will not start a new transaction.
So the only thing to do is to start a transaction on your database and commit/rollback after your work is done or you notice an error. All inserts and updates will be in the same transaction which has benefits concerning data consistency and also on performance, since greendao will start new transactions with commit/rollback for every insert and update operation.
Summarized you can use code like this:
SQLiteDatabase db = dao.getDatabase();
db.beginTransaction();
try {
// do all your inserts and so on here.
db.setTransactionSuccessful();
} catch (Exception ex) {
} finally {
db.endTransaction();
}
I also tweaked my greendao a bit so that it doesn't cache inserted objects to get further performance and memoryusage benefits (since I insert a lot of data once and I only use very few data during runtime depending on user input). See this post.
I use sqlite transaction in Android:
SQLiteDatabase database = sqlite_helper.getWritableDatabase();
database.beginTransaction();
...
database.setTransactionSuccessful();
database.endTransaction();
My questions are :
1. Should I place endTransaction() in finally code block like this:
try {
database.beginTransaction();
...
database.setTransactionSuccessful();
}
finally {
database.endTransaction();
}
If there are exepctions during database operations, will the database be rolled back automatically without using "finally"?
When the transaction is not ended, can other threads read or write the same database? I hear sqlite in Android is threading safe, but I are not sure with it. I guess there will be some problems during transaction. Is there an error raised if another thread writes the same database with the same connection?
I ever found this error in my app, but I don't know whether it's related to the threading safe problem:
android.database.sqlite.SQLiteMisuseException: library routine called out of sequence:
, while compiling
Does anyone help me to answer these questions? Thanks a lot!
1.you should always place endTransaction in finally block
2.transaction in SQLite is thread safe,see the doc http://www.sqlite.org/atomiccommit.html
You should always put endTransaction() into a finally block (also see the docs).
Otherwise, the database would not be able to notice than an exception has happened.
The only other way to end a transaction would be to close the connection, in which case SQLite automatically rolls back any active transaction.
As long as one connection writes to the database (which means that a transaction is active), no other connections can read or write. Therefore, you should take care not to forget to end transactions.
You should never write from multiple threads; what would happen if one threads ends the transaction while the other one is still writing?
Your SQLiteMisuseException might be related, or not; that's impossible to say without seeing the code.
Yes, you should use the finally block. Here is a simple, THREAD SAFE method I use:
/**
* Call for multiple DB insertion transactions. It is thread safe and fast!
*/
private synchronized void writeTransaction(Runnable task) {
try {
db.beginTransaction();
task.run();
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}
}
the synchronized keyword locks the method with its containing object, thus making it thread safe...