So, I have ActorModel class that includes arraylist of MovieModel. I was trying to encode it and send it in a bundle to the next activity. However, it is saying:
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the object '{', but had 'EOF' instead at path: $
JSON input: kotlinx.serialization
Here is my ActorModel Class:
package com.sanjarbek.flixster2
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.Serializable
@Serializable
data class ActorModel(
val name: String,
val popularity: String,
val profile_path: String, ) {
var movieModelArrayList: ArrayList<MovieModel> = ArrayList<MovieModel>()
set(value) {field = value}
get() = field
fun mainMovie(): String {
val json = Json.encodeToString<ArrayList<MovieModel>>(movieModelArrayList)
return json
}
fun main(): String {
val json = Json.encodeToString(ActorModel(name, popularity, profile_path))
return json
}
}
followed by MovieModel class:
package com.sanjarbek.flixster2
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.Serializable
@Serializable
data class MovieModel (
private val original_title: String="",
private val poster_path: String="",
private val overview: String=""
) {
fun get_title(): String{
return original_title
}
fun get_image(): String{
return poster_path
}
fun get_description(): String{
return overview
}
}
Here's the code where I tried sending it with bundle:
holder.image.setOnClickListener {
val intent = Intent(context, ActorInfoActivity::class.java)
intent.putExtra("image", image_url)
intent.putExtra("name", model.name)
intent.putExtra("model", model.main())
context.startActivity(intent)
}
And where I receive and decode it:
val actor = Json.decodeFromString<ActorModel>("kotlinx.serialization")
val movies = Json.decodeFromString<ArrayList<MovieModel>>("kotlinx.serialization")
Log.d("TAG", "onCreate: $actor"
Log.d("TAG", "onCreate: $movies")
CodePudding user response:
If your question is how to pass the objects described above to another activity, then this does not require a JSON object. Android gives us the tools to do this out of the box. I rewrote your classes a bit:
ActorModel
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
data class ActorModel (
val name: String,
val popularity: String,
val profilePath: String,
var movieModelArrayList: MutableList<MovieModel> = mutableListOf()): Parcelable {
override fun toString(): String {
return "ActorModel(name=$name, popularity=$popularity, profilePath=$profilePath)\n"
"movieModelArrayList=$movieModelArrayList"
}
}
MovieModel
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize
@Parcelize
data class MovieModel (
val original_title: String = "TestTitle",
val poster_path: String = "./Test",
val overview: String = "Test"
): Parcelable
I draw your attention to the @Parcelize
annotation and interface Parcelable
- this is the most important change to your code. Parcelable
process is much faster than Serializable
. One of the reasons for this is that we are being explicit about the serialization process instead of using reflection to infer it. In fact, we must manually implement the methods of the Parcelable
interface. But the creators of Kotlin took care of us and added the @Parcelize
annotation, which does all the dirty work for us. By default, it is not available, how to enable it is described in detail in the answer.
Sending data
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class TestActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val actor = ActorModel("Alex", "10", "./profiles")
actor.movieModelArrayList.add(MovieModel())
val intent = Intent(this, MainActivity::class.java)
val bundle = Bundle()
bundle.putParcelable("actor", actor)
intent.putExtras(bundle)
startActivity(intent)
}
}
Getting data
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val actor = intent.extras?.get("actor") as ActorModel
Log.i("Test", actor)
}
}
A small digression
In the
MovieModel
class, you do not need getters, since you have already declared the fields as val - they are no longer mutable and read-only. So, the private modifier also makes no sense. It's not Java anymore, relax and enjoy Kotlin :)