I have an application that iterates through a list of locations and determines whether or not the user is within a perimeter around each of those locations. When I was using SharedPreferences to store the data I didn't have this issue, but now that I've switched to an SQLite database, I've been getting java.util.ConcurrentModificationException
on the following loop. The stack trace points to the first line of the loop.
loop@ for (i in locationList) {
val distance = getLocationFromReminder(locationList[iterator], currentLocation).toDouble()
// If the user distance is within the radius distance...
if (distance <= locationList[iterator].radius) {
when (locationList[iterator].inside) {
null -> { // WHEN DISTANCE <= RADIUS AND LOCATION IS SET TO NEITHER INSIDE NOR OUTSIDE
locationList[iterator].inside = true // Set inside to true
locationList[iterator].entered = getTransitionTime() // Set entered to the entrance time
addToTransitionArray(iterator, locationList[iterator].entered, true) // Add entrance time to entrance time array
// db.addLocationTransition(locationList[iterator], getTransitionTime())
sendNotification(this@MapsActivity, "Fence created around current location.", reminder.latLng)
val logMessage = "[${getDate()}] Fence created around current location (${locationList[iterator].message}) at ${getTimeStamp()}."
logMessage(logMessage)
refreshLocationList()
}
false -> { // ...and reminder.inside == false...
locationList[iterator].inside = true
locationList[iterator].entered = getTransitionTime()
addToTransitionArray(iterator, locationList[iterator].entered, true)
// db.addLocationTransition(locationList[iterator], getTransitionTime())
locationList[iterator].entranceNoteArray.add(locationList[iterator].entranceNoteArray.size, "-")
val logMessage = "[${getDate()}] Entered ${locationList[iterator].message} at ${getTimeStamp()}"
logMessage(logMessage)
// Send notification
sendNotification(this@MapsActivity, "Now entering ${locationList[iterator].message}!", locationList[iterator].latLng)
sendSnackbar("Transition logged at ${locationList[iterator].entered}.")
refreshLocationList()
}
} // Otherwise, if the user's distance from the Reminder is farther than its radius...
} else if (distance > locationList[iterator].radius) {
when (locationList[iterator].inside) {
null -> { locationList[iterator].inside = false }
true -> { // ...and reminder.inside == true...
// Notify user that they are exiting perimeter
sendNotification(this@MapsActivity, "Now exiting ${locationList[iterator].message}!", reminder.latLng)
locationList[iterator].exitNoteArray.add(locationList[iterator].exitNoteArray.size, "-")
// Get transition time for most recent exited
locationList[iterator].exited = getTransitionTime()
locationList[iterator].inside = false
addToTransitionArray(iterator, getTransitionTime(), false)
addToTimeInsideArray(iterator, getTimeInside(locationList[iterator]))
val logMessage = "[${getDate()}] Exited ${locationList[iterator].message} at ${getTimeStamp()}"
logMessage(logMessage)
sendSnackbar("Transition logged at ${getTimeStamp()}.")
refreshLocationList()
}
}
}
iterator++
continue@loop
}
Here's the Reminder class that the locationList MutableList is populated with, for some context:
class Reminder : Serializable {
@SerializedName("address") var address: String = ""
@SerializedName("city") var city: String = ""
@SerializedName("state") var state: String = ""
@SerializedName("zip") var zip: String = ""
@SerializedName("latLng") var latLng: LatLng = LatLng(0.0, 0.0)
@SerializedName("radius") var radius: Double = 0.0
@SerializedName("message") var message: String = ""
@SerializedName("inside") var inside: Boolean? = null
@SerializedName("tableList") var tableList: MutableList<String> = mutableListOf("")
@SerializedName("tableName") var tableName: String = "LOCATIONS${message}"
@SerializedName("entered") var entered: String = "00:00"
@SerializedName("exited") var exited: String = "00:00"
@SerializedName("timeinside") var timeInside: String = ""
@SerializedName("allentrances") var allEntrances: MutableList<String> = mutableListOf("")
@SerializedName("allexits") var allExits: MutableList<String> = mutableListOf("")
@SerializedName("timeinsidearray") var timeInsideArray: MutableList<String> = mutableListOf("")
@SerializedName("entrancenotearray") var entranceNoteArray: MutableList<String> = mutableListOf("")
@SerializedName("exitnotearray") var exitNoteArray: MutableList<String> = mutableListOf("")
@SerializedName("id") var id: Int = 0 // NEW
}
I understand that I probably shouldn't be using an integer to iterate through this MutableList, and I understand that the issue is caused by this loop,
I know there are similar questions to this, but they all answer the question in the context of Java, and I want to know if there is something different that should be done with Kotlin, or, otherwise, what the best approach is. I see people talking about using iterators, but I'm having a hard time wrapping my head around what the exact cause of this issue is or how to fix it.
If there's some documentation on the Kotlinlang site that I haven't found that would help me with this, I would appreciate it. Thanks.