1

I have a data class in Kotlin:

data class myDataClass(
    var a: ArrayList<Long> = ArrayList(),
    var b: ArrayList<Long> = ArrayList(),
    var c: ArrayList<Long> = ArrayList(),
    ...
)

private val myDataClassVal: myDataClass = myDataClass()

I use this data class to store data acquired over BLE that will, when each ArrayList is at a certain length, POST to a REST API. After this POST the data within myDataClass is .clear()ed and the process will repeat.

The BLE portion of the application is time sensitive and each POST is taking approximately 1 second; my solution to this is to run my POST function asynchronously; as opposed to running on the same thread as the BLE code. I do this in the following way:

GlobalScope.async { 
    uploadData(myDataClassVal) 
}

myDataClassVal.a.clear()
myDataClassVal.b.clear()
myDataClassVal.c.clear()

Unfortunately, where I am clearing the data in myDataClass immediately after the async function call the data is actually cleared from the data class before it is serialised and POSTed.

In an attempt to solve this problem I created a duplicate of myDataClass right before uploading and pass this into the async upload function. The duplicate is created using the .copy() function as described here:

uploadBuffer = myDataClassVal.copy()
GlobalScope.async {
    uploadData(uploadBuffer)
}
myDataClassVal.a.clear()
....

However, uploadBuffer is still completely empty. If I create a copy of myDataClass in the same way and POST on the same thread:

uploadBuffer = myDataClassVal.copy()
uploadData(uploadBuffer)
myDataClassVal.a.clear()
....

Then it works just fine.

So, I think my issue is that uploadBuffer is just a pointer to myDataClass. If this is the case, how do I create a new object that is a duplicate of myDataClass to use in my async POST?

Thanks, Adam

amitchone
  • 1,630
  • 3
  • 21
  • 45
  • 1
    you wouldn't have these problems if you just used immutable data. And no, it's not creating a deep copy so changing on object1 will also change on the copy – s1m0nw1 Nov 07 '18 at 15:36
  • @s1m0nw1 Could you elaborate? – amitchone Nov 07 '18 at 15:37
  • Well, make your properties `var a: List` and don't expose the mutable version of List. This way you can make sure that once you got a list from the class it won't change afterward. instead of adding to your list you will reassign the list; instead of clearing you will reassign to an empty list etc – s1m0nw1 Nov 07 '18 at 15:42
  • When a data class has several layers of object as properties the copy function creates a shallow copy with reference to children properties. Making your properties immutable looks like the best option but you can also force create deep copies of data classes. [guide](https://www.baeldung.com/kotlin/deep-copy-data-class) – vlecoq-v Dec 15 '22 at 09:59

2 Answers2

2

Why not just create a new instance for every new run. You won't need the copy function, just create a new instance after launching:

GlobalScope.launch {
    uploadData(uploadBuffer)
}
uploadBuffer = new myDataClassVal()

BTW: You should start your classes with an upper case letter, e.g. MyDataClassVal. See Naming Conventions: https://kotlinlang.org/docs/reference/coding-conventions.html#naming-rulesan

You should use launch instead of async, because you don't need the result, see Kotlin Async vs Launch

Rene
  • 5,730
  • 17
  • 20
1

If you want to clear the data only after the async task has finished, you can try using await.

 uploadBuffer = myDataClassVal.copy()
 GlobalScope.async {
     uploadData(uploadBuffer)
 }.await()
 myDataClassVal.a.clear() //this will execute after async returns
 ...
deluxe1
  • 737
  • 4
  • 15