android kotlin - Coroutines with ViewModel LiveData






MainActivity.kt



package com.example.coroutine

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.activity_main.*


class MainActivity : AppCompatActivity() {

private lateinit var model: TimeViewModel

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// initialize the time view model
model = ViewModelProvider(this).get(TimeViewModel::class.java)


// observe the api time live data
model.apiTime.observe(this, Observer {
textView.text = ""
it?.apply {
textView.append(zone)
textView.append("\n" + date)
textView.append("\n\n" + time)
}
})


// fetch api json data
button.setOnClickListener {
model.fetchJson()
}
}
}





activity_main.xml



<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E5AA70"
tools:context=".MainActivity">

<com.google.android.material.button.MaterialButton
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:backgroundTint="#6C541E"
android:text="Fetch API"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/textView"
style="@style/TextAppearance.MaterialComponents.Headline4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:padding="8dp"
android:gravity="center_horizontal"
android:textStyle="bold"
android:fontFamily="monospace"
android:textColor="#563C5C"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
tools:text="TextView" />

</androidx.constraintlayout.widget.ConstraintLayout>





TimeViewModel.kt



package com.example.coroutine

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStream
import java.io.InputStreamReader
import java.net.URL
import java.text.SimpleDateFormat
import java.util.*


class TimeViewModel(application:Application): AndroidViewModel(application){
// live data instance
val apiTime = MutableLiveData<APITime>()

// initialize the view model
init {
fetchJson()
}

// function to fetch json data from api
fun fetchJson() {
viewModelScope.launch(Dispatchers.IO) {
URL("https://worldtimeapi.org/api/timezone/Europe/London")
.openStream()
?.getString()?.apply {
apiTime.postValue(parseJson(this))
}
}
}
}


// extension function to convert input stream to string
fun InputStream.getString(): String? {
return try {
val r = BufferedReader(InputStreamReader(this))
val result = StringBuilder()
var line: String?
while (r.readLine().also { line = it } != null) {
result.append(line).appendln()
}
result.toString()
}catch (e:IOException){
e.toString()
}
}


// data class for api time
data class APITime(
val zone:String,
val date:String,
val time:String
)


// parse json data
fun parseJson(data:String):APITime{
val obj = JSONObject(data)
val timeZone = obj.getString("timezone")
val unixTime = obj.getLong("unixtime")

val date = Date(unixTime * 1000L)

val sdf = SimpleDateFormat("dd-MMM-yyyy")
sdf.timeZone = TimeZone.getTimeZone(timeZone)
val formattedDate = sdf.format(date)

val timeFormat = SimpleDateFormat("h:mm:ss a")
timeFormat.timeZone = TimeZone.getTimeZone(timeZone)
val time: String = timeFormat.format(date)

return APITime(timeZone, formattedDate, time)
}





build.gradle (app) [code to add]



dependencies {
// kotlin coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.7'

// life cycle
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
}










More android kotlin tutorials