X-Git-Url: https://git.ktnx.net/?a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fasync%2FRetrieveTransactionsTask.java;h=5d634d2f1ab1e8d0632eac6848a7ef627d135f27;hb=99c3bfb3451ebb1fc55d728d8d1741849cf789db;hp=f9297f0089e28542ba8c60c2f29feba6da6ed57f;hpb=3d6624b7751fa97edf71b7b1398867357aedb90d;p=mobile-ledger.git diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index f9297f00..5d634d2f 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -164,7 +164,7 @@ public class RetrieveTransactionsTask // state of the database db.setTransactionSuccessful(); db.endTransaction(); - Data.accounts.set(accountList); + Data.accounts.setList(accountList); db.beginTransaction(); continue; } @@ -390,6 +390,8 @@ public class RetrieveTransactionsTask } publishProgress(progress); SQLiteDatabase db = MLDB.getDatabase(); + ArrayList accountList = new ArrayList<>(); + boolean listFilledOK = false; try (InputStream resp = http.getInputStream()) { if (http.getResponseCode() != 200) throw new IOException(String.format("HTTP error %d", http.getResponseCode())); @@ -399,7 +401,6 @@ public class RetrieveTransactionsTask profile.markAccountsAsNotPresent(db); AccountListParser parser = new AccountListParser(resp); - ArrayList accountList = new ArrayList<>(); LedgerAccount prevAccount = null; @@ -413,9 +414,26 @@ public class RetrieveTransactionsTask else acc.removeAmounts(); profile.storeAccount(db, acc); - for (ParsedBalance b : parsedAccount.getAebalance()) { - profile.storeAccountValue(db, acc.getName(), b.getAcommodity(), - b.getAquantity().asFloat()); + String lastCurrency = null; + float lastCurrencyAmount = 0; + for (ParsedBalance b : parsedAccount.getAibalance()) { + final String currency = b.getAcommodity(); + final float amount = b.getAquantity().asFloat(); + if (currency.equals(lastCurrency)) lastCurrencyAmount += amount; + else { + if (lastCurrency != null) { + profile.storeAccountValue(db, acc.getName(), lastCurrency, + lastCurrencyAmount); + acc.addAmount(lastCurrencyAmount, lastCurrency); + } + lastCurrency = currency; + lastCurrencyAmount = amount; + } + } + if (lastCurrency != null) { + profile.storeAccountValue(db, acc.getName(), lastCurrency, + lastCurrencyAmount); + acc.addAmount(lastCurrencyAmount, lastCurrency); } if (acc.isVisible(accountList)) accountList.add(acc); @@ -432,12 +450,16 @@ public class RetrieveTransactionsTask profile.deleteNotPresentAccounts(db); throwIfCancelled(); db.setTransactionSuccessful(); - Data.accounts.set(accountList); + listFilledOK = true; } finally { db.endTransaction(); } } + // should not be set in the DB transaction, because of a possible deadlock + // with the main and DbOpQueueRunner threads + if (listFilledOK) Data.accounts.setList(accountList); + return true; } private boolean retrieveTransactionList(MobileLedgerProfile profile) @@ -456,67 +478,96 @@ public class RetrieveTransactionsTask default: throw new HTTPException(http.getResponseCode(), http.getResponseMessage()); } - try (SQLiteDatabase db = MLDB.getDatabase()) { - try (InputStream resp = http.getInputStream()) { - if (http.getResponseCode() != 200) - throw new IOException(String.format("HTTP error %d", http.getResponseCode())); - throwIfCancelled(); - db.beginTransaction(); - try { - profile.markTransactionsAsNotPresent(db); + SQLiteDatabase db = MLDB.getDatabase(); + try (InputStream resp = http.getInputStream()) { + if (http.getResponseCode() != 200) + throw new IOException(String.format("HTTP error %d", http.getResponseCode())); + throwIfCancelled(); + db.beginTransaction(); + try { + profile.markTransactionsAsNotPresent(db); - int matchedTransactionsCount = 0; - TransactionListParser parser = new TransactionListParser(resp); + int matchedTransactionsCount = 0; + TransactionListParser parser = new TransactionListParser(resp); - int processedTransactionCount = 0; + int processedTransactionCount = 0; - while (true) { - throwIfCancelled(); - ParsedLedgerTransaction parsedTransaction = parser.nextTransaction(); - throwIfCancelled(); - if (parsedTransaction == null) break; - LedgerTransaction transaction = parsedTransaction.asLedgerTransaction(); - if (transaction.existsInDb(db)) { - profile.markTransactionAsPresent(db, transaction); - matchedTransactionsCount++; - - if (matchedTransactionsCount == MATCHING_TRANSACTIONS_LIMIT) { - profile.markTransactionsBeforeTransactionAsPresent(db, transaction); - progress.setTotal(progress.getProgress()); - publishProgress(progress); - db.setTransactionSuccessful(); - profile.setLastUpdateStamp(); - return true; - } + DetectedTransactionOrder transactionOrder = DetectedTransactionOrder.UNKNOWN; + int orderAccumulator = 0; + int lastTransactionId = 0; + + while (true) { + throwIfCancelled(); + ParsedLedgerTransaction parsedTransaction = parser.nextTransaction(); + throwIfCancelled(); + if (parsedTransaction == null) break; + + LedgerTransaction transaction = parsedTransaction.asLedgerTransaction(); + if (transaction.getId() > lastTransactionId) orderAccumulator++; + else orderAccumulator--; + lastTransactionId = transaction.getId(); + if (transactionOrder == DetectedTransactionOrder.UNKNOWN) { + if (orderAccumulator > 30) { + transactionOrder = DetectedTransactionOrder.FILE; + Log.d("rtt", String.format( + "Detected native file order after %d transactions (factor %d)", + processedTransactionCount, orderAccumulator)); + progress.setTotal(Data.transactions.size()); } - else { - profile.storeTransaction(db, transaction); - matchedTransactionsCount = 0; - progress.setTotal(maxTransactionId); + else if (orderAccumulator < -30) { + transactionOrder = DetectedTransactionOrder.REVERSE_CHRONOLOGICAL; + Log.d("rtt", String.format( + "Detected reverse chronological order after %d transactions (factor %d)", + processedTransactionCount, orderAccumulator)); } + } - if ((progress.getTotal() == Progress.INDETERMINATE) || - (progress.getTotal() < transaction.getId())) - progress.setTotal(transaction.getId()); - - progress.setProgress(++processedTransactionCount); - publishProgress(progress); + if (transaction.existsInDb(db)) { + profile.markTransactionAsPresent(db, transaction); + matchedTransactionsCount++; + + if ((transactionOrder == DetectedTransactionOrder.REVERSE_CHRONOLOGICAL) && + (matchedTransactionsCount == MATCHING_TRANSACTIONS_LIMIT)) + { + profile.markTransactionsBeforeTransactionAsPresent(db, transaction); + progress.setTotal(progress.getProgress()); + publishProgress(progress); + db.setTransactionSuccessful(); + profile.setLastUpdateStamp(); + return true; + } + } + else { + profile.storeTransaction(db, transaction); + matchedTransactionsCount = 0; + progress.setTotal(maxTransactionId); } - throwIfCancelled(); - profile.deleteNotPresentTransactions(db); - throwIfCancelled(); - db.setTransactionSuccessful(); - profile.setLastUpdateStamp(); - } - finally { - db.endTransaction(); + + if ((transactionOrder != DetectedTransactionOrder.UNKNOWN) && + ((progress.getTotal() == Progress.INDETERMINATE) || + (progress.getTotal() < transaction.getId()))) + progress.setTotal(transaction.getId()); + + progress.setProgress(++processedTransactionCount); + publishProgress(progress); } + + throwIfCancelled(); + profile.deleteNotPresentTransactions(db); + throwIfCancelled(); + db.setTransactionSuccessful(); + profile.setLastUpdateStamp(); + } + finally { + db.endTransaction(); } } return true; } + + ; @SuppressLint("DefaultLocale") @Override protected String doInBackground(Void... params) { @@ -557,6 +608,7 @@ public class RetrieveTransactionsTask private void throwIfCancelled() { if (isCancelled()) throw new OperationCanceledException(null); } + enum DetectedTransactionOrder {UNKNOWN, REVERSE_CHRONOLOGICAL, FILE} private enum ParserState { EXPECTING_ACCOUNT, EXPECTING_ACCOUNT_AMOUNT, EXPECTING_JOURNAL, EXPECTING_TRANSACTION,