Fix crash in TransfersLoader when changing between night and day mode.
This commit is contained in:
parent
c7138c5e22
commit
eaa661ba5d
1 changed files with 49 additions and 71 deletions
|
@ -24,10 +24,10 @@ import cy.agorise.graphenej.models.OperationHistory
|
||||||
import cy.agorise.graphenej.operations.TransferOperation
|
import cy.agorise.graphenej.operations.TransferOperation
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.functions.Consumer
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import org.bitcoinj.core.DumpedPrivateKey
|
import org.bitcoinj.core.DumpedPrivateKey
|
||||||
import org.bitcoinj.core.ECKey
|
import org.bitcoinj.core.ECKey
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.crypto.AEADBadTagException
|
import javax.crypto.AEADBadTagException
|
||||||
|
|
||||||
|
@ -35,27 +35,22 @@ import javax.crypto.AEADBadTagException
|
||||||
* This class is responsible for loading the local database with all past transfer operations of the
|
* This class is responsible for loading the local database with all past transfer operations of the
|
||||||
* currently selected account.
|
* currently selected account.
|
||||||
*
|
*
|
||||||
* The procedure used to load the database in 3 steps:
|
|
||||||
*
|
|
||||||
* 1- Load all transfer operations
|
|
||||||
* 2- Load all missing times
|
|
||||||
* 3- Load all missing equivalent times
|
|
||||||
*
|
|
||||||
* Since the 'get_relative_account_history' will not provide either timestamps nor equivalent values
|
* Since the 'get_relative_account_history' will not provide either timestamps nor equivalent values
|
||||||
* for every transfer, we must first load all historical transfer operations, and then proceed to
|
* for every transfer, that has to be handled in other part.
|
||||||
* handle those missing columns.
|
|
||||||
*/
|
*/
|
||||||
class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
class TransfersLoader(private var mContext: Context?) {
|
||||||
|
|
||||||
private val TAG = this.javaClass.simpleName
|
companion object {
|
||||||
|
private const val TAG = "TransfersLoader"
|
||||||
|
|
||||||
/** Constant that specifies if we are on debug mode */
|
/** Constant that specifies if we are on debug mode */
|
||||||
private val DEBUG = false
|
private const val DEBUG = false
|
||||||
|
|
||||||
/* Constant used to fix the number of historical transfers to fetch from the network in one batch */
|
/* Constant used to fix the number of historical transfers to fetch from the network in one batch */
|
||||||
private val HISTORICAL_TRANSFER_BATCH_SIZE = 100
|
private const val HISTORICAL_TRANSFER_BATCH_SIZE = 100
|
||||||
|
|
||||||
private val RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY = 0
|
private const val RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY = 1
|
||||||
|
}
|
||||||
|
|
||||||
private var mDisposables = CompositeDisposable()
|
private var mDisposables = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -77,28 +72,26 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
/* Counter used to keep track of the transfer history batch count */
|
/* Counter used to keep track of the transfer history batch count */
|
||||||
private var historicalTransferCount = 0
|
private var historicalTransferCount = 0
|
||||||
|
|
||||||
// Used to keep track of the current state TODO this may not be needed
|
/** Flag used to keep track of the NetworkService binding state */
|
||||||
private var mState = State.IDLE
|
private var mBound: Boolean = false
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag used to keep track of the NetworkService binding state
|
|
||||||
*/
|
|
||||||
private var mShouldUnbindNetwork: Boolean = false
|
|
||||||
|
|
||||||
private var lastId: Long = 0
|
|
||||||
|
|
||||||
// Map used to keep track of request and response id pairs
|
// Map used to keep track of request and response id pairs
|
||||||
private val responseMap = HashMap<Long, Int>()
|
private val responseMap = HashMap<Long, Int>()
|
||||||
|
|
||||||
/**
|
private val mConnection = object : ServiceConnection {
|
||||||
* Enum class used to keep track of the current state of the loader
|
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||||
*/
|
// We've bound to LocalService, cast the IBinder and get LocalService instance
|
||||||
private enum class State {
|
val binder = service as NetworkService.LocalBinder
|
||||||
IDLE,
|
mNetworkService = binder.service
|
||||||
LOADING_MISSING_TIMES,
|
mBound = true
|
||||||
LOADING_EQ_VALUES,
|
|
||||||
CANCELLED,
|
// Start the transfers update
|
||||||
FINISHED
|
startTransfersUpdateProcedure()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onServiceDisconnected(name: ComponentName?) {
|
||||||
|
mBound = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -106,10 +99,11 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
authorityRepository = AuthorityRepository(mContext!!)
|
authorityRepository = AuthorityRepository(mContext!!)
|
||||||
|
|
||||||
val pref = PreferenceManager.getDefaultSharedPreferences(mContext)
|
val pref = PreferenceManager.getDefaultSharedPreferences(mContext)
|
||||||
val userId = pref.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "")
|
val userId = pref.getString(Constants.KEY_CURRENT_ACCOUNT_ID, "") ?: ""
|
||||||
if (userId != "") {
|
if (userId != "") {
|
||||||
mCurrentAccount = UserAccount(userId)
|
mCurrentAccount = UserAccount(userId)
|
||||||
mDisposables.add(authorityRepository!!.getWIF(userId!!, AuthorityType.MEMO.ordinal)
|
mDisposables.add(
|
||||||
|
authorityRepository!!.getWIF(userId, AuthorityType.MEMO.ordinal)
|
||||||
.subscribeOn(Schedulers.computation())
|
.subscribeOn(Schedulers.computation())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe { encryptedWIF ->
|
.subscribe { encryptedWIF ->
|
||||||
|
@ -124,8 +118,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
mDisposables.add(RxBus.getBusInstance()
|
mDisposables.add(RxBus.getBusInstance()
|
||||||
.asFlowable()
|
.asFlowable()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(Consumer { message ->
|
.subscribe { message ->
|
||||||
if (mState == State.FINISHED) return@Consumer
|
|
||||||
if (message is JsonRpcResponse<*>) {
|
if (message is JsonRpcResponse<*>) {
|
||||||
if (message.result is List<*>) {
|
if (message.result is List<*>) {
|
||||||
if (responseMap.containsKey(message.id)) {
|
if (responseMap.containsKey(message.id)) {
|
||||||
|
@ -143,37 +136,17 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
responseMap.clear()
|
responseMap.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
// If there is no current user, we should not do anything
|
|
||||||
mState = State.CANCELLED
|
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onStart()
|
onStart()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceDisconnected(name: ComponentName?) {
|
|
||||||
mShouldUnbindNetwork = false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
|
||||||
// We've bound to LocalService, cast the IBinder and get LocalService instance
|
|
||||||
val binder = service as NetworkService.LocalBinder
|
|
||||||
mNetworkService = binder.service
|
|
||||||
|
|
||||||
// Start the transfers update
|
|
||||||
startTransfersUpdateProcedure()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onStart() {
|
private fun onStart() {
|
||||||
if (mState != State.CANCELLED) {
|
// Bind to LocalService
|
||||||
val intent = Intent(mContext, NetworkService::class.java)
|
Intent(mContext, NetworkService::class.java).also { intent ->
|
||||||
if (mContext!!.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
|
mContext?.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
|
||||||
mShouldUnbindNetwork = true
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Binding to the network service failed.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +156,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
private fun startTransfersUpdateProcedure() {
|
private fun startTransfersUpdateProcedure() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
// If we are in debug mode, we first erase all entries in the 'transfer' table
|
// If we are in debug mode, we first erase all entries in the 'transfer' table
|
||||||
transferRepository!!.deleteAll()
|
transferRepository?.deleteAll()
|
||||||
}
|
}
|
||||||
mDisposables.add(
|
mDisposables.add(
|
||||||
transferRepository!!.getCount()
|
transferRepository!!.getCount()
|
||||||
|
@ -213,7 +186,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
private fun handleOperationList(operationHistoryList: List<OperationHistory>) {
|
private fun handleOperationList(operationHistoryList: List<OperationHistory>) {
|
||||||
historicalTransferCount++
|
historicalTransferCount++
|
||||||
|
|
||||||
val insertedCount = transferRepository!!.insertAll(processOperationList(operationHistoryList))
|
val insertedCount = transferRepository?.insertAll(processOperationList(operationHistoryList))
|
||||||
// TODO return number of inserted rows
|
// TODO return number of inserted rows
|
||||||
// Log.d(TAG, String.format("Inserted count: %d, list size: %d", insertedCount, operationHistoryList.size))
|
// Log.d(TAG, String.format("Inserted count: %d, list size: %d", insertedCount, operationHistoryList.size))
|
||||||
if (/* insertedCount == 0 && */ operationHistoryList.isEmpty()) {
|
if (/* insertedCount == 0 && */ operationHistoryList.isEmpty()) {
|
||||||
|
@ -234,7 +207,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
private fun loadNextOperationsBatch() {
|
private fun loadNextOperationsBatch() {
|
||||||
val stop = historicalTransferCount * HISTORICAL_TRANSFER_BATCH_SIZE
|
val stop = historicalTransferCount * HISTORICAL_TRANSFER_BATCH_SIZE
|
||||||
val start = stop + HISTORICAL_TRANSFER_BATCH_SIZE
|
val start = stop + HISTORICAL_TRANSFER_BATCH_SIZE
|
||||||
lastId = mNetworkService!!.sendMessage(
|
val id = mNetworkService?.sendMessage(
|
||||||
GetRelativeAccountHistory(
|
GetRelativeAccountHistory(
|
||||||
mCurrentAccount,
|
mCurrentAccount,
|
||||||
stop,
|
stop,
|
||||||
|
@ -242,7 +215,7 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
start
|
start
|
||||||
), GetRelativeAccountHistory.REQUIRED_API
|
), GetRelativeAccountHistory.REQUIRED_API
|
||||||
)
|
)
|
||||||
responseMap[lastId] = RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY
|
if (id != null) responseMap[id] = RESPONSE_GET_RELATIVE_ACCOUNT_HISTORY
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -321,10 +294,15 @@ class TransfersLoader(private var mContext: Context?): ServiceConnection {
|
||||||
private fun onDestroy() {
|
private fun onDestroy() {
|
||||||
Log.d(TAG, "Destroying TransfersLoader")
|
Log.d(TAG, "Destroying TransfersLoader")
|
||||||
if (!mDisposables.isDisposed) mDisposables.dispose()
|
if (!mDisposables.isDisposed) mDisposables.dispose()
|
||||||
if (mShouldUnbindNetwork) {
|
|
||||||
mContext!!.unbindService(this)
|
try {
|
||||||
mShouldUnbindNetwork = false
|
if (mBound && mNetworkService != null)
|
||||||
|
mContext?.unbindService(mConnection)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.d(TAG, "Avoid crash related to Service not registered: ${e.message}")
|
||||||
}
|
}
|
||||||
|
mBound = false
|
||||||
mContext = null
|
mContext = null
|
||||||
|
mNetworkService = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue