Kotlin .add переопределяет все элементы списка в MutableList

У меня есть объект, который содержит изменяемый список

object TrackingEventsList {
    var EventDate: String = ""
    var EventDescription: String = ""
}

object Waybill {
    var WaybillNumber: String = ""
    var OriginHub: String = ""
    var TrackingEvents: MutableList<TrackingEventsList> = ArrayList()
}

Когда я пытаюсь добавить Waybill.TrackingEvents, все предыдущие экземпляры перезаписываются и дублируют последнее добавленное TrackingEvent.

private fun fillTracking(events: NodeList) {
    var list = TrackingEventsList
    for (x: Int in 0 until events.length) {
        var tName = (events.item(x) as Element).tagName
        var event = (events.item(x).firstChild as Text).wholeText
        if (tName == "EventDate") {
            list.EventDate = event
        }
        if (tName == "EventDescription") {
            list.EventDescription = event
        }
    }
    Waybill.TrackingEvents.plus(list)
}

Результат после вызова fillTracking 3 раза:

Waybill.TrackingEvents[0].EventDescription = "Event3"
Waybill.TrackingEvents[1].EventDescription = "Event3"
Waybill.TrackingEvents[2].EventDescription = "Event3"

2 ответа

Решение

object в Kotlin есть singleton, что означает, что вы не можете его инициализировать, и он имеет только один экземпляр в глобальном масштабе. Поэтому, когда вы изменяете элементы одного экземпляра, вы переопределяете предыдущие данные.

Вы должны изменить их обоих (или, по крайней мере, TrackingEventsList) на class вместо. Если WaybillПеременные чувствительны к экземпляру, это тоже должен быть класс. Но в коде, который вы добавили, я не смог найти ничего, что говорило бы, что вы используете его как синглтон, поэтому я оставил его как единое целое.

class TrackingEventsList (
        var eventDate: String = "",
        var eventDescription: String = "")

/**
 * Also want to point out that this is still a singleton. If the data inside is instance-specific, you need to change it 
 * to a class. 
 */
object Waybill {
    var waybillNumber: String = ""
    var originHum: String = ""
    var trackingEvents: MutableList<TrackingEventsList> = ArrayList()
}

private fun fillTracking(events: NodeList) {
    val item = TrackingEventsList()
    for (x: Int in 0 until events.length) {
        var tName = (events.item(x) as Element).tagName
        var event = (events.item(x).firstChild as Text).wholeText

        if (tName == "EventDate") {
            item.eventDate = event
        }
        if (tName == "EventDescription") {
            item.eventDescription = event
        }
    }

    Waybill.trackingEvents.add(item)
}

И вы должны посмотреть на соглашения об именах для Kotlin; поля никогда не начинаются с заглавной буквы, если только это не статическая константа (в этом случае она полностью верхняя)

Поскольку TrackingEventsList это объект, это означает, что это одиночный объект (или только один экземпляр). Когда вы проходите цикл, вы всегда обновляете один и тот же экземпляр вашего TrackingEventsList объект.

+ Изменить TrackingEventsList быть этим:

data class TrackingEventsList(var eventDate: String, var eventDescription: String)

Создавайте новый экземпляр каждый раз, когда вы проходите цикл, а затем добавляете его в список:

private fun fillTracking(events: NodeList) {
    var eventDate: String = ""
    var eventDescription: String = ""
    for (x: Int in 0 until events.length) {
        val tName = (events.item(x) as Element).tagName
        val event = (events.item(x).firstChild as Text).wholeText
        if (tName == "EventDate") {
            eventDate = event
        }
        if (tName == "EventDescription") {
            eventDescription = event
        }
    }
    Waybill.TrackingEvents.plus(TrackingEventsList(eventDate, eventDescription))
}
Другие вопросы по тегам