" In computing, serialization (US spelling) or serialisation (UK spelling) is the process of translating a data structure or object state into a format that can be stored (for example, in a file or memory data buffer) or transmitted (for example, across a computer network) and reconstructed later (possibly in a different computer environment). "
Two days ago the JetBrain team published a new post about serializing stuff in Kotlin
Was I intrigued ?
Of course ! and I wanted to show you a very little use of the the deserializing process while using Rx and URL from java.net.URL ( lazyness guys, lazyness). JSONs have never been easier to be parsed !
First all of implementation :
apply plugin: 'kotlinx-serialization'
apply plugin: "org.jetbrains.kotlin.plugin.serialization"
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
...
dependencies{
implementation "io.reactivex.rxjava3:rxkotlin:3.0.0"
implementation "io.reactivex.rxjava3:rxandroid:3.0.0"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
Permission to use internet in the manifest please :
<uses-permissionandroid:name="android.permission.INTERNET"/>
Once it's done, create a ViewModel and set it up like this :
class VM : ViewModel(){
var listOfRepo = MutableLiveData<List<Repo>>()
private val disposable = CompositeDisposable()
/**
* Asynchronous work to prevent us from blocking the UI while fetching and transforming the data.
* Here we update the MutableLiveData listOfRepo
*
* For learning and debugging purpose we use the fancy method subscribeBy()
*/
fun fetchListOfData(){
val observable = getStringObservable()
observable
.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread())
.subscribeBy(
onNext = {result ->listOfRepo.value = result },
onError =
{error->Log.e("VM", "fetchListOfData :${error.localizedMessage}")} )
.addTo(disposable)
}
/**
* Returns an Observable like below :
* URl => String => List<Repo> wrapped into an Observable
*/
private fun getStringObservable() :Observable<List<Repo>> {
return Observable.create {
emitter ->
emitter.onNext(
Json{ ignoreUnknownKeys = true}
.decodeFromString( URL(MainActivity.URL).readText())
)
}
}
/**
* When the view model is destroyed we get rid of all observables
*/
override fun onCleared() {
super.onCleared()
disposable.clear()
}
}
Don't forget to create an object to Serialized to the serialized the result to and to be used by the adapter .
@Serializable()
dataclass Repo ( val name : String?, val description :String?)
Return to you main activity and :
class MainActivity : AppCompatActivity() {
private var viewModel :VM? = null
private var adapter :AdapterRepo? = null
companion object {
const val URL=
"https://api.github.com/repositories?since=364"
}
/**
*
* UI update
*/
override fun onCreate ( savedInstanceState : Bundle? )
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider.AndroidViewModelFactory
.getInstance( this.application )
.create(VM::class.java)
adapter = AdapterRepo(this)
recycler.layoutManager = LinearLayoutManager(this)
viewModel?.listOfRepo?.observe(this, { list ->
adapter?.update(list)
recycler.adapter = adapter
})
viewModel?.fetchListOfData()
}
}
//Item for RecyclerView setup
class AdapterRepo ( private val context :Context) : RecyclerView.Adapter<AdapterRepo.VH>(){
private var listOfRepo = listOf<Repo>()
class VH (itemView :View) : RecyclerView.ViewHolder( itemView ){
var title : TextView? =null
var description :TextView? =null
init {
title = itemView.findViewById(R.id.title)
description = itemView.findViewById(R.id.description)
}
fun bind( titleValue :String? , descriptionValue :String?){
title?.text = titleValue
description?.text = descriptionValue
}
}
fun update (list:List<Repo>){
listOfRepo = list
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
val v = LayoutInflater.from(context)
.inflate(R.layout.repo_item,parent,false)
return VH(v)
}
override fun onBindViewHolder( holder : VH, position : Int) {
val repo = listOfRepo[position]
holder.bind(repo.name, repo.description)
}
override fun getItemCount(): Int = listOfRepo.size
}
Some tips you should know :
- If you forget to apply the plugins at the top of your gradle file @Serializable in the data class will be highlighted and the serialization will fail.
-If by any chance you'd like to change the setup and the use know that URL(MainActivity.URL).readText() has to be called asynchronously !
- If you want to use Retrofit coupled with Kotlin.serialization implement :
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0")
And in your API builder set it up as your converter.
- For best pratice matter and data usage, you should store the result into a file, just saying.
- { IgnoreUnknownKeys = true } tells the library, the object you want to create clearly doesn't need all the properties , therefore you tell it to ignore the one you don't want.
Link to the project :
Comments