Ormlite ObjectCache returning old data - android

I'm using Ormlite on Android and with the ObjectCache enabled, I get old data back after updating the table with an UpdateBuilder and a ColumnExpression. I have read through the doc and it does not warn against using the UpdateBuilder with the cache enabled.
The settings table should have just 1-5ish rows max. The updateColumnExpression seems like an easy way to allow only one of the rows to be true.
Is this the expected behavior?
public void setActiveSetting(String id)
{
try {
UpdateBuilder<Settings, Integer> updateBuilder2 = getHelper().getSettingsDao().updateBuilder();
updateBuilder2.updateColumnExpression("active", "id = " + id );
updateBuilder2.update();
} catch (SQLException e){
e.printStackTrace();
}
}
And this is the call that returns the outdated data:
public List<Settings> getSettings()
{
List<Settings> settings = null;
try {
settings = getHelper().getSettingsDao().queryForAll();
} catch (SQLException e) {
e.printStackTrace();
}
return settings;
}
And the settings DAO:
public Dao<Settings, Integer> getSettingsDao()
{
if (null == settingsDao) {
try {
settingsDao = getDao(Settings.class);
settingsDao.setObjectCache(true);
} catch (java.sql.SQLException e) {
e.printStackTrace();
}
}
return settingsDao;
}
Disabling the ObjectCache does return the correct data, but this data is fetched quite frequently, so I'd like to keep it.
Thanks

Is this the expected behavior?
Unfortunately, yes. If you had updated the object using dao.update(...); then the cache would know that the object needed to be refreshed. By using the UpdateBuilder to make mass changes to the table, there is no way for the cache to know which objects were affected.
You will need to clear the cache after your call to the UpdateBuilder finishes.

Related

How to properly resolve conflict during azure synchronization from android?

I'm in trouble with azure synchronization, I'm able to detect the number of pending operations by mCLient.getSyncContext().getPendingOperations(); but can't resolve them. Any help or suggestion?
When working with in an offline scenario and you have pending operations, you can push them to the server by using the push() function.
It would look something like the following:
try {
MobileServiceSyncContext syncContext = mClient.getSyncContext();
syncContext.push().get();
// here you would do a pull on any table you want to grab data from
}
catch (final MobileServiceConflictException e)
{
// the server item causing the exception can be obtained by calling e.getItem()
JsonObject serverObject = e.getItem();
// on the sync context, call one of the following:
// .cancelAndDiscardItem() to cancel update and discard local item
// .cancelAndUpdateItem() to update the local item with the server's copy
// .cancelAndUpdateItem(JsonObject item) to update the server's item w/ the local
// make sure to call push() again on the sync context
}
All in all - make sure you call push() on the MobileServiceSyncContext and then handle any MobileServiceConflictException that may return.
If I catch for MobileServiceConflictException android studio tells me that the Exception is never thrown in this corresponding try block.
try {
MobileServiceSyncContext syncContext = mClient.getSyncContext();
syncContext.push().get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (MobileServiceConflictException e) {
}

Realm taking too long to copy objects to RealmObject

I'm using realm to store a list of Products in my Andorid App.
So, I receive a produtc's list with about 3k objects.
And I'm trying to store them like this:
#Override
public void saveAll(List<ProductsDomain> domainProducts) throws InstantiationException, IllegalAccessException {
Realm instance = getRealmInstance();
RealmList<ProdutcsRealm> realmProducts = new RealmList<ProdutcsRealm>();
try {
ProdutcsRealm realmProduct = getClasseEntidadePersistencia().newInstance();
for (ProductsDomain domainProduct : domainProducts) {
fromDomainToPersistence(domainProduct, realmProduct);
realmProducts.add(realmProduct);
}
instance.beginTransaction();
instance.copyToRealm(realmProducts);// taking to long, 3k items
instance.commitTransaction();
} catch (Exception e) {
e.printStackTrace();
instance.cancelTransaction();
return;
}
}
So, the realm is taking too much time, something like 20 minutes. Anybody have any idea to get better performace?
Solved:
I've found the problem! I was using the same ProductsRealm instance for all iteration. Looks like that Realm dont work well when you try to save a list of multiple references to de same object.
It will be faster if you can add the objects to your Realm in fromDomainToPersistence(). The saveAll() method could be something like:
public void saveAll(...) {
Realm instance = getRealmInstance();
try {
instance.beginTransaction();
for (ProductsDomain domainProduct : domainProducts) {
fromDomainToPersistence(instance, domainProduct);
}
instance.commitTransaction();
} catch (Exception e) {
// ...
}
}
and
public void fromDomainToPersistence(Realm r, DomainProduct domainProduct) {
ProductRealm realmProduct = r.createObject(ProductRealm.class);
// set the fields' values
}

Query for Battery capacity

I need help. I just want to make application that reads battery capacity, like read in mAh/mA. Anyone can help me please?
I've read another thread about this, but I was confused because I need an integer from battery capacity. For example, my android has a battery with capacity 2500 mAh
and I need that integer of capacity(2500) where I want to include that number in my calculation.
Thanks for the help.
This is code that I want to change, I am just confused where it must be changed.
public void getBatteryCapacity() {
Object mPowerProfile_ = null;
final String POWER_PROFILE_CLASS = "com.android.internal.os.PowerProfile";
try {
mPowerProfile_ = Class.forName(POWER_PROFILE_CLASS)
.getConstructor(Context.class).newInstance(this);
} catch (Exception e) {
e.printStackTrace();
}
try {
double batteryCapacity = (Double) Class
.forName(POWER_PROFILE_CLASS)
.getMethod("getAveragePower", java.lang.String.class)
.invoke(mPowerProfile_, "battery.capacity");
Toast.makeText(MainActivity.this, batteryCapacity + " mah",
Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
Yes, your code gives total mAh capacity. You can change that function to return the value like this:
public Double getBatteryCapacity() {
// Power profile class instance
Object mPowerProfile_ = null;
// Reset variable for battery capacity
double batteryCapacity = 0;
// Power profile class name
final String POWER_PROFILE_CLASS = "com.android.internal.os.PowerProfile";
try {
// Get power profile class and create instance. We have to do this
// dynamically because android.internal package is not part of public API
mPowerProfile_ = Class.forName(POWER_PROFILE_CLASS)
.getConstructor(Context.class).newInstance(this);
} catch (Exception e) {
// Class not found?
e.printStackTrace();
}
try {
// Invoke PowerProfile method "getAveragePower" with param "battery.capacity"
batteryCapacity = (Double) Class
.forName(POWER_PROFILE_CLASS)
.getMethod("getAveragePower", java.lang.String.class)
.invoke(mPowerProfile_, "battery.capacity");
} catch (Exception e) {
// Something went wrong
e.printStackTrace();
}
return batteryCapacity;
}
The getAveragePower function returns the average current
in mA consumed by the subsystem. In this case subsystem string is battery.capacity which returns the battery capacity.
See class code here:
https://android.googlesource.com/platform/frameworks/base.git/+/master/core/java/com/android/internal/os/PowerProfile.java
And if you really want that value as int, just change it like this:
int bc = getBatteryCapacity().intValue();

Android SQLite Transaction, two datasources

im having doubts on how to procede with database manipulation using Begin Transaction
I have 2 data source objects: ClientDataSource and MovementsDataSource
each of theres has its own SQLitedabase object which is set with the Open() method with sets its database private Object with a Writable Database.
Now, i have to send the Records from the Movements Table to a server and then ask for the updated Clients from the same server.
Inside my class i first Send the new Movements, then if sucessful, delete all clients from the SQLite, and finally retrieve the new Updated Clients from the server and insert them into the database.
each data source has a Get() method for obtainting their respective Database Object, BUT it is in fact the same database they are operating and I am not sure of how to use the BaginTransction, Endtransaction methods to ensure data consistency
this is the code from the Async Task
#Override
protected Boolean doInBackground(String... url) {
try {
clientDataSource.open();
movementDataSource.open();
} catch (SQLException e) {
//Treat SQL Exception
}
try {
if(sendMovements()) {
clientDataSource.deleteAllClients();
}
updateDatabase(url[0]);
} catch (JSONException e) {
//Treat Json Exception
} catch (IOException e) {
//Treat IOException
}
return true;
}
i have to give one example then how begintransaction works...
public static void Insert(ArrayList<Model_CategoryMaster> categoryMasters) {
SQLiteDatabase sqldb = EGLifeStyleApplication.sqLiteDatabase;
sqldb.beginTransaction();
for (Model_CategoryMaster model : categoryMasters) {
ContentValues values = new ContentValues();
values.put(CATEGORY_ID, model.Category_Id);
values.put(CATEGORYNAME, model.CategoryName);
values.put(DESCRIPTION, model.Description);
values.put(ISACTIVE, model.IsActive);
values.put(CREATEDON, model.CreatedOn);
values.put(CREATEDBY, model.CreatedBy);
values.put(UPDATEDON, model.UpdatedOn);
values.put(UPDATEDBY, model.UpdatedBy);
values.put(ISDELETED, model.IsDeleted);
values.put(DELETEDON, model.DeletedOn);
values.put(DELETEDBY, model.DeletedBy);
values.put(PK_CATEGORYMASTER, model.PK_CategoryMaster);
if (!CommonMethod.CheckIsDataAlreadyInDBorNot(Table_Name,
CATEGORY_ID, model.Category_Id)) {
sqldb.insert(Table_Name, null, values);
} else {
sqldb.update(Table_Name, values, "Category_Id=?",
new String[] { model.Category_Id });
}
}
sqldb.setTransactionSuccessful();
sqldb.endTransaction();
}// End insert method
begin transaction means data will get arraylist then db will open one time and sql.begintansaction() use to get faster database operation.because db is not open or close more times.

How to insert bulk data in android sqlite database using ormlite efficiently

I'm trying to insert 100000 records in android sqlite database at a time. I'm using following two different methods.
private void bulkInsertDataBySavePoint(final List<User> users) {
log.debug("bulkInsertDataBySavePoint()");
DatabaseConnection conn = null;
Savepoint savepoint = null;
try {
conn = userDao.startThreadConnection();
savepoint = conn.setSavePoint("bulk_insert");
for (User user : users) {
userDao.create(user);
}
} catch (SQLException e) {
log.error("Something went wrong in bulk Insert", e);
} finally {
if (conn != null) {
try {
conn.commit(savepoint);
userDao.endThreadConnection(conn);
} catch (SQLException e) {
log.error("Something went wrong in bulk Insert", e);
}
}
}
}
And
private void bulkInsertDataByCallBatchTasks(final List<User> users) {
log.debug("bulkInsertDataByCallBatchTasks()");
try {
userDao.callBatchTasks(new Callable<Void>() {
#Override
public Void call() throws Exception {
for (User user : users) {
userDao.create(user);
}
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Both methods work fine. On average they take 140 seconds and take 60-65% CPU which is not ok, I think.
The idea is, I have to consume an api which will provide json data. I have to parse that json data and then insert into sqlite database for offline usage.
I'm looking for an efficient way to solve this issue.
Any thought?
I'm trying to insert 100000 records in android sqlite database at a time... On average they take 140 seconds and take 60-65% CPU which is not ok in my opinion.
Unfortunately I don't have an easy answer for you. You may have to do this sort of insert directly using raw SQL to achieve faster performance on the limited Android CPU. Once you have the data inserted then you can turn to ORMLite to query or manipulate the data faster.
I've had the same problem, and found a reasonable workaround. This took insert time from 2 seconds to 150ms:
final OrmLiteSqliteOpenHelper myDbHelper = ...;
final SQLiteDatabase db = myDbHelper.getWritableDatabase();
db.beginTransaction();
try{
// do ormlite stuff as usual, no callBatchTasks() needed
db.setTransactionSuccessful();
}
finally {
db.endTransaction();
}
Hrm. Good idea #FarrukhNajmi. I've just added it to trunk. It will be in version 4.49.
#Gray Is it still unstable? when can we see it in maven?
And if com.j256.ormlite.dao.ForeignCollection#addAll make only one request it would be nice too.

Categories

Resources