Android can't serialize Kotlin lambda - android

we can read lambda function are serialize by default (https://discuss.kotlinlang.org/t/are-closures-serializable/1620),
but I getting error:
java.lang.RuntimeException: Parcelable encountered IOException writing serializable object (name = com.example.dialogfragment.Arguments)
my class Arguments:
class Arguments(val function: ()-> Unit) : Serializable
What is wrong with my lambda ?
(I got this error when Android need to kill my fragment because low of memory :) )

If you want to serialize or parcel something you need to ensure every field is serializable or parcelable.
In your case you are trying to serialize val function: ()-> Unit which is not serializable. Unfortunately, you can't make function serializable. You should rethink this argument class and pass something different. Probably you can get some parameter which leads to making a decision and then invoking a function in your fragment.

Related

How to general skip a bad element when its optional with moshi

iam using retrofit 2 with moshi and i have a problem when the optional nested class is broken.
Lets take this as a simple example:
class ClassA(val anyString: String, classB: ClassB?)
class ClassB(val firstString: String, val secondString: String)
I have a class A that has an optional Value from class B.
The Json that is gonna be parsed looks like this:
{
"anystring":"HelloWorld",
"classB":{
"firstString":"IamAFirstString"
//SECOND STRING IS MISSING OR IS NULL
}
}
When i try to parse this json ill get an exception:
com.squareup.moshi.JsonDataException: Non-null value 'secondString' was null at $.classB.secondString
What i want to archive is that i get the ClassA with an null value at classB because that value is optional so its okay when its null. I know that can archive this when i build an adapter and catch the exception but i want to know if theres a general way to archive this behaviour without creating an adapter for every json that i have to parse.

#Parcelize and Superclass, doubling data because of constructor requirement

I have a Result parcelable class that is supposed to serve as a container for a key and a parcelable data. This is how I define it:
#Parcelize
open class Result<out T : Parcelable>(val key: String, val data: T?) : Parcelable
The problem is that when defining the child class, in order for #Parcelize to work, I need to add val to the object in the constructor, essentially making the data being written twice to the parcel twice. Here is an example:
#Parcelize
class LessonFinishedResult(private val lessonActivityData: LessonActivityData) :
Result<LessonActivityData>(LessonActivityData.LESSON_KEY, lessonActivityData), Parcelable
I would like to have this:
#Parcelize
class LessonFinishedResult(lessonActivityData: LessonActivityData) :
Result<LessonActivityData>(LessonActivityData.LESSON_KEY, lessonActivityData), Parcelable
But it is not allowed. Is there a smart way I can get around this? And another thing, is there a way I can avoid having to manually use Result<LessonActivityData> and have the type be inferred automatically from the object being passed?
Thanks!
essentially making the data being written twice to the parcel twice
It isn't; the code generated by #Parcelize doesn't care about the superclass at all. It can even not be Parcelizable. Only the primary constructor parameters (in this case val lessonActivityData) are written/read, and when reading it's enough to pass the correct parameters to the superclass constructor.

What does putExtraData do in Kotlin Intent?

I am trying to send an object (via intent ) of data class type and came across this method
putExtraData in Kotlin. ( Could not find a similar method in Java).
What does it do ? Can i send an object of this type using that method? I was wondering because i may avoid having to use Parcelable and Serializable if this is possible.
data class Properties(val actionBarColor : Int){
}

what does "::" mean in kotlin?

I'm new to Kotlin
I used this code for opening another activity:
startActivity(Intent(this,IntroAndLang::class.java))
current activity and target activity are written in Kotlin
I can't understand why there is not single : instead of :: at IntroAndLang::class.java
:: is used for Reflection in kotlin
Class Reference val myClass = MyClass::class
Function Reference this::isEmpty
Property Reference ::someVal.isInitialized
Constructor Reference ::MyClass
For detailed reading Official Documentation
:: converts a Kotlin function into a lambda.
Let's say you have a function that looks like this:
fun printSquare(a: Int) = println(a * 2)
And you have a class that takes a lambda as a 2nd argument:
class MyClass(var someOtherVar: Any, var printSquare: (Int) -> Unit) {
fun doTheSquare(i: Int) {
printSquare(i)
}
}
How do you pass the printSquare function into MyClass? If you try the following, it wont work:
MyClass("someObject", printSquare) //printSquare is not a LAMBDA, it's a function so it gives compile error of wrong argument
So how do we CONVERT printSquare into a lambda so we can pass it around? Use the :: notation.
MyClass("someObject",::printSquare) //now compiler does not complain since it's expecting a lambda and we have indeed converted the `printSquare` FUNCTION into a LAMBDA.
Also, please note that this is implied... meaning this::printSquare is the same as ::printSquare. So if the printSquare function was in another class, like a Presenter, then you could convert it to lambda like this:
Presenter::printSquare
UPDATE:
Also this works with constructors. If you want to create the constructor of a class and then convert it to a lambda, it is done like this:
(x, y) -> MyClass::new
this translates to MyClass(x, y) in Kotlin.
As stated in the docs this is a class reference:
Class References:
The most basic reflection feature is getting the runtime reference to a Kotlin class. To obtain the reference to a statically known Kotlin class, you can use the class literal syntax:
val c = MyClass::class
//The reference is a value of type KClass.
Note that a Kotlin class reference is not the same as a Java class reference. To obtain a Java class reference, use the .java property on a KClass instance.
It’s also the syntax for method references as in this simple example:
list.forEach(::println)
It refers to println defined in Kotlin Standard library.
Since kotlin 1.1, in addition to class, function, property and constructor references as stated above, '::' can also be used to obtain the bound references to all of the above.
For instance, using '::class' could be used to get the exact class of a particular object despite the type of the receiver as below...
val widget: Widget = ...
assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" }
widget::class returns the exact class of the object 'widget' as either 'GoodWidget' or 'BadWidget' despite the type of the receiver expression (i.e 'Widget' as declared initially)
More info at https://kotlinlang.org/docs/reference/reflection.html

Implementing both Serializable and Parcelable interfaces from an object in Android - conflict

I have an object that i must save to file for reuse. The class of this object already implements Parcelable for use in intents. My knowledge of saving an object to file says to implement Serializable, but when i do, i get an error in the class that contains this object at the putExtra method of an intent because both Serializable and Parcelable have this method.
Is there a way to avoid this, or just a way that i can save my object state and reload it easily?
I have looked at a few articles and i feel no more informed about how i should be saving my object.
Thanks in advance
I believe that Parcelable and Serializable both reaches the same goal in different ways and with different performances. Given that, if some class in your object hierarchy alread implements the Parcelable interface, you can override its writeToParcel method, call the super for it (so the members of the super classes will be written to the parcel if they were implement that way) and then, you should write your attributes to the parcel, always keeping in mind that the order you use to save them is the order you will use to retrieve them latter (FILO data structure)
EDIT
Just cast your object where it complains and tells about the conflict to the class you want to use as described here: https://stackoverflow.com/a/13880819/2068693
I don't know that you can implement both Serializable and Parcelable together but for convert a class from Serializable to Parcelable you can use this plugin:
Android Parcelable Code generator.
First remove implement Serializable then with ALT + Insert and click on Parcelable you can generate your class.
You have options other than Serializable, but that may meet other requirements such as avoiding library dependencies. You can write objects to file using JSON or XML, which has the advantage of being readable. You may also need to consider versioning - what happens when you have files that need to be read by a class that contains a new field. Persistence brings with it some issues you probably don't have passing Bundles/Intents back and forth.
If you choose Serializable I'd recommend structuring your objects so they can be written to and read from a Bundle. Using a static MyObject.make(Bundle) method and an instance Bundle save() method keeps all the constants and read/write in a single location.

Categories

Resources