0

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.

ADO
  • 35
  • 8
  • "if there is something different that should be done with Kotlin" - no. The problem and the solutions are the same. – OrangeDog Nov 04 '20 at 20:39
  • @OrangeDog Surely you understand why I might ask this, considering things like nullability are handled a little differently in Kotlin. Kotlin streamlines some things; that's why I specified it. – ADO Nov 04 '20 at 20:40
  • @OrangeDog Yes, actually. I hadn't found this one even though I was going through the similar questions on the question creation page - maybe I missed it. Thanks. – ADO Nov 04 '20 at 20:41

0 Answers0