android kotlin: storing retrieved data from url to room database - android

method i made:
private fun saveToRoom(albums: Array<Data>) {
doAsync {
/*val currentDBPath = getDatabasePath("albums_database").absolutePath
println("DBPath is " + currentDBPath)*/
var items = ArrayList<ProductList_Data>()
for (album in albums) {
val item = ProductList_Data()
item.name = album.name
item.price = album.price
items.add(item)
}
db?.productListDao()?.insert(items)
/*val musicAlbums = db?.productListDao()?.getAll()
activityUiThread {
longToast("Data Got saved")
refreshUIWith(musicAlbums!!)
}*/
}
}
this is data class names Data
data class Data(
val _links: Links?,
val attributes: List<Attribute>?,
val average_rating: String?,
val backordered: Boolean?,
val backorders: String?,
val backorders_allowed: Boolean?,
val button_text: String?,
val catalog_visibility: String?,
val categories: List<Category>?,
val cross_sell_ids: List<Any>?,
val custom_fields: CustomFields?,
val date_created: String?,
val date_created_gmt: String?,
val date_modified: String?,
val date_modified_gmt: String?,
val date_on_sale_from: Any?,
val date_on_sale_from_gmt: Any?,
val date_on_sale_to: Any?,
val date_on_sale_to_gmt: Any?,
val default_attributes: List<Any>?,
val description: String?,
val dimensions: Dimensions?,
val download_expiry: Int?,
val download_limit: Int?,
val downloadable: Boolean?,
val downloads: List<Any>?,
val external_url: String?,
val featured: Boolean?,
val grouped_products: List<Any>?,
val id: Int?,
val images: List<Image>?,
val manage_stock: Boolean?,
val menu_order: Int?,
val meta_data: List<MetaData>?,
val name: String?,
val on_sale: Boolean?,
val parent_id: Int?,
val permalink: String?,
val price: String?,
val price_html: String?,
val purchasable: Boolean?,
val purchase_note: String?,
val rating_count: Int?,
val regular_price: String?,
val related_ids: List<Int>?,
val reviews_allowed: Boolean?,
val sale_price: String?,
val shipping_class: String?,
val shipping_class_id: Int?,
val shipping_required: Boolean?,
val shipping_taxable: Boolean?,
val short_description: String?,
val sku: String?,
val slug: String?,
val sold_individually: Boolean?,
val status: String?,
val stock_quantity: Any?,
val stock_status: String?,
val tags: List<Any>?,
val tax_class: String?,
val tax_status: String?,
val total_sales: Int?,
val type: String?,
val upsell_ids: List<Any>?,
val variations: List<Int>?,
val virtual: Boolean?,
val weight: String?
) i want to get only name and price to be stored in room database
entity class that i am using :
#Entity(tableName = "productlisttable")
data class ProductList_Data(
#PrimaryKey
val uid: Int = 0,
#ColumnInfo(name = "_name")
var name: String? = "",
#ColumnInfo(name = "_price")
var price: String? = ""
)
calling method in main activity and getting red underline error that no values passed for init and all that
saveToRoom(Array<Data>))
i think the way i am calling the method is wrong or what

Use this function to convert and save array in database
#TypeConverter
fun fromStringList(stringList: List<String?>?): String? {
if (stringList == null) return null
val type = object : TypeToken<List<String?>?>() {}.type
return Gson().toJson(stringList, type)
}

Related

how to get data from rest api using retrofit kotlin android

I am trying to get data from rest api using retrofit on Android app.
I am trying to reach the data structured below;
sections -> items -> venue -> id (Unique id of the venue)
sections -> items -> venue -> name (Name of the venue)
sections -> items -> venue -> short_description (Description of the venue)
I can reach to the sections but not the data under the section.
data class VenueModel(
val created: Created,
val expires_in_seconds: Int,
val filtering: Filtering,
val name: String,
val page_title: String,
val sections: List<Section>,
val show_large_title: Boolean,
val show_map: Boolean,
val sorting: SortingX,
val track_id: String
)
data class Section(
val items: List<Item>,
val link: LinkX,
val name: String,
val template: String,
val title: String
)
data class Item(
val description: String,
val filtering: FilteringX,
val image: Image,
val link: Link,
val overlay: String,
val quantity: Int,
val quantity_str: String,
val sorting: Sorting,
val template: String,
val title: String,
val track_id: String,
val venue: Venue
)
data class Venue(
val address: String,
val badges: List<Badge>,
val categories: List<Any>,
val city: String,
val country: String,
val currency: String,
val delivers: Boolean,
val delivery_price: String,
val delivery_price_highlight: Boolean,
val delivery_price_int: Int,
val estimate: Int,
val estimate_range: String,
val franchise: String,
val id: String,
val location: List<Double>,
val name: String,
val online: Boolean,
val price_range: Int,
val product_line: String,
val promotions: List<Any>,
val rating: Rating,
val short_description: String,
val show_wolt_plus: Boolean,
val slug: String,
val tags: List<String>
)
this is api service interface;
interface APIService {
#GET("v1/pages/restaurants?lat=60.170187&lon=24.930599")
fun getVenues(#Query("lat") locationLatitude: String, #Query("lon") locationLongitude: String) : Call<VenueModel>
}
And this is main activity;
class MainActivity : AppCompatActivity() {
var locationLatitude = "60.170187"
var locationLongitude = "24.930599"
lateinit var venueSearchListSection: List<Section>
lateinit var venueSearchListItem: List<Item>
lateinit var venueSearchListVenue: List<Venue>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
venueSearchListSection = ArrayList<Section>()
venueSearchListItem = ArrayList()
venueSearchListVenue = ArrayList()
fetchDataFromApi()
}
private fun fetchDataFromApi(){
//venue results from api
val retrofitVenueSearch = Retrofit.Builder()
.baseUrl("https://restaurant-api.wolt.com/")
.addConverterFactory(GsonConverterFactory.create()).build()
val apiVenueSearch = retrofitVenueSearch.create(APIService::class.java)
apiVenueSearch.getVenues(locationLatitude, locationLongitude).enqueue(object :
Callback<VenueModel> {
override fun onResponse(
call: Call<VenueModel>,
response: Response<VenueModel>
) {
venueSearchListSection = response.body()?.sections ?: venueSearchListSection
//I have the problem here. I can get the data in venueSearchListSection
//arraylist but I can not reach the data inside it.
}
override fun onFailure(call: Call<VenueModel>, t: Throwable) {
t.message?.let { Log.e("venue", it) }
}
})
}
}
Thanks for your helps in advance.

Store Json (Retrofit response) in to Room Database

I'm new to Room database, I have JSON response from MSGraph API, which is List of Calendar events.
I want to store this response in Room database .
Sample response from the retrofit
data
{
"#odata.context":"",
"value":[
{
"#odata.etag":"W/\"arcvR4W/==\"",
"id":"AAvR4W-QUGEzDhwKmVNegAAFPBq3AAAEA==",
"createdDateTime":"2020-05-28T11:15:19.3397025Z",
"lastModifiedDateTime":"2020-09-08T15:57:16.2356808Z",
"changeKey":"arcvR4W/==",
"categories":[
],
"transactionId":null,
"originalStartTimeZone":"UTC",
"originalEndTimeZone":"UTC",
"iCalUId":"040000008200E00074C5B7101A82E831",
"reminderMinutesBeforeStart":15,
"isReminderOn":true,
"hasAttachments":false,
"subject":"Canceled: discussion",
"bodyPreview":"time didnt set correctly, so cancelling the call",
"importance":"high",
"sensitivity":"normal",
"isAllDay":true,
"isCancelled":true,
"isOrganizer":false,
"responseRequested":true,
"seriesMasterId":"AAMkADU3MAAAAENAABqty9Hhb9BQYTMOHAqZU16AAAU8GrcAAA=",
"showAs":"free",
"type":"occurrence",
"webLink":"https://outlook.office365.com/",
"onlineMeetingUrl":null,
"isOnlineMeeting":true,
"onlineMeetingProvider":"teams",
"allowNewTimeProposals":true,
"isDraft":false,
"hideAttendees":false,
"responseStatus":{
"response":"accepted",
"time":"2020-05-28T11:15:00Z"
},
"body":{
"contentType":"html",
"content":"<html>\r\n<head>\r\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\r\n<meta content=\"text/html; charset=us-ascii\">\r\n</head>\r\n<body>\r\n<div>time didnt set correctly, so cancelling the call</div>\r\n</body>\r\n</html>\r\n"
},
"start":{
"dateTime":"2021-03-11T00:00:00.0000000",
"timeZone":"UTC"
},
"end":{
"dateTime":"2021-03-12T00:00:00.0000000",
"timeZone":"UTC"
},
"location":{
"displayName":"",
"locationType":"default",
"uniqueIdType":"unknown",
"address":{
},
"coordinates":{
}
},
"locations":[
],
"recurrence":null,
"attendees":[
{
"type":"required",
"status":{
"response":"none",
"time":"0001-01-01T00:00:00Z"
},
"emailAddress":{
"name":"abc",
"address":"abc#mail.com"
}
},
{
"type":"required",
"status":{
"response":"none",
"time":"0001-01-01T00:00:00Z"
},
"emailAddress":{
"name":"xyz",
"address":"xyz#mail.com"
}
}
],
"organizer":{
"emailAddress":{
"name":"abc",
"address":"abc#mail.com"
}
},
"onlineMeeting":{
"joinUrl":""
}
},
more elements from list
]
}
I searched the forum but did not get any right solution.
I want to store this response in Room database. Can someone help me the correct approach to follow.
Thanks
you should create "CalendarEvent" object and make response of retrofit be like this Call
after that you need to create entities from your models and create dao (contain methods to insert,get,update and delete the data from db)
and in your repository when you receive the data map it to your db entity
with your mapper (you can use extension to map your own data)
I convert that json to kotlin data classes and you can create db entites inspired from those models
data class Address()
data class Attendees(val type: String?, val status: Status?, val emailAddress: EmailAddress?)
data class CalendarEvent(val id: String?, val createdDateTime: String?, val lastModifiedDateTime: String?, val changeKey: String?, val categories: List<Any>?, val transactionId: Any?, val originalStartTimeZone: String?, val originalEndTimeZone: String?, val iCalUId: String?, val reminderMinutesBeforeStart: Number?, val isReminderOn: Boolean?, val hasAttachments: Boolean?, val subject: String?, val bodyPreview: String?, val importance: String?, val sensitivity: String?, val isAllDay: Boolean?, val isCancelled: Boolean?, val isOrganizer: Boolean?, val responseRequested: Boolean?, val seriesMasterId: String?, val showAs: String?, val type: String?, val webLink: String?, val onlineMeetingUrl: Any?, val isOnlineMeeting: Boolean?, val onlineMeetingProvider: String?, val allowNewTimeProposals: Boolean?, val isDraft: Boolean?, val hideAttendees: Boolean?, val responseStatus: ResponseStatus?, val body: Body?, val start: Start?, val end: End?, val location: Location?, val locations: List<Any>?, val recurrence: Any?, val attendees: List<Attendees>?, val organizer: Organizer?, val onlineMeeting: OnlineMeeting?)
data class Body(val contentType: String?, val content: String?)
data class Coordinates()
data class EmailAddress(val name: String?, val address: String?)
data class End(val dateTime: String?, val timeZone: String?)
data class Location(val displayName: String?, val locationType: String?, val uniqueIdType: String?, val address: Address?, val coordinates: Coordinates?)
data class OnlineMeeting(val joinUrl: String?)
data class Organizer(val emailAddress: EmailAddress?)
data class ResponseStatus(val response: String?, val time: String?)
data class Start(val dateTime: String?, val timeZone: String?)
data class Status(val response: String?, val time: String?)

ERROR: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $

I'm trying to create a POST Request using Retrofit2 and I created the next classes:
My JSON Data: https://jsonblob.com/d7b06b4c-2e4b-11eb-967c-5704a225d894
Model Class
data class StatsModel(
#SerializedName("actionRights")
val actionRights : MutableList<ActionRights>?,
#SerializedName("stats")
val stats : Stats?,
#SerializedName("markers")
val markers : MutableList<Markers>?
) {
data class ActionRights (
#SerializedName("hasArticlePriceChangeRights") val hasArticlePriceChangeRights : Boolean?,
#SerializedName("hasStockLevelViewRights") val hasStockLevelViewRights : Boolean?
)
data class Stats (
#SerializedName("errors") val errors : Int?,
#SerializedName("warnings") val warnings : Int?,
#SerializedName("outOfOrder") val outOfOrder : Int?,
#SerializedName("running") val running : Int?
)
data class Markers (
#SerializedName("deviceGuid") val deviceGuid : String?,
#SerializedName("lat") val lat : Double?,
#SerializedName("lng") val lng : Double?,
#SerializedName("title") val title : Int?,
#SerializedName("city") val city : String?,
#SerializedName("street") val street : Int?,
#SerializedName("serialNumber") val serialNumber : Int?,
#SerializedName("LastStatusMessageDateTime") val lastStatusMessageDateTime : String?,
#SerializedName("LastStatusMessageBitSet_0_63") val lastStatusMessageBitSet_0_63 : Int?,
#SerializedName("LastStatusMessageBitSet_64_127") val lastStatusMessageBitSet_64_127 : Int?,
#SerializedName("ActionsStatus") val actionsStatus : Int?,
#SerializedName("SpareColumn1") val spareColumn1 : String?,
#SerializedName("SpareColumn2") val spareColumn2 : String?,
#SerializedName("SpareColumn3") val spareColumn3 : String?,
#SerializedName("SpareColumn4") val spareColumn4 : String?,
#SerializedName("SpareColumn5") val spareColumn5 : String?,
#SerializedName("SpareColumn6") val spareColumn6 : String?,
#SerializedName("SpareColumn7") val spareColumn7 : String?,
#SerializedName("SpareColumn8") val spareColumn8 : String?,
#SerializedName("SpareColumn9") val spareColumn9 : String?,
#SerializedName("SpareColumn10") val spareColumn10 : String?,
#SerializedName("EstimatedDeliveryDateTime") val estimatedDeliveryDateTime : String?,
#SerializedName("IpAddress") val ipAddress : String?,
#SerializedName("Active") val active : Int?,
#SerializedName("ParentAreaGuid") val parentAreaGuid : String?,
#SerializedName("AreaGuid") val areaGuid : String?,
#SerializedName("TariffGroupGuid") val tariffGroupGuid : String?,
#SerializedName("DeviceType") val deviceType : String?,
#SerializedName("EstimateArticleName") val estimateArticleName : String?,
#SerializedName("EstimateArticleGuid") val estimateArticleGuid : String?,
#SerializedName("lastCoinboxExchange") val lastCoinboxExchange : String?,
#SerializedName("lastStatusUpdateTime") val lastStatusUpdateTime : String?,
#SerializedName("reportDateTime") val reportDateTime : String?,
#SerializedName("hasFinancialInfo") val hasFinancialInfo : Boolean?,
#SerializedName("ticketsSold") val ticketsSold : Int?,
#SerializedName("cash") val cash : Int?,
#SerializedName("cashless") val cashless : Int?,
#SerializedName("hasStockLevel") val hasStockLevel : Boolean?,
#SerializedName("hasArticlePrices") val hasArticlePrices : Boolean?,
#SerializedName("EstDeliveryDays") val estDeliveryDays : String?,
#SerializedName("hasOther") val hasOther : Boolean?,
#SerializedName("hasOutOfOrder") val hasOutOfOrder : Boolean?,
#SerializedName("hasWarning") val hasWarning : Boolean?,
#SerializedName("hasError") val hasError : Boolean?,
#SerializedName("flags") val flags : List<Flags>?,
#SerializedName("actionState") val actionState : String?,
#SerializedName("spareColumns") val spareColumns : List<SpareColumns>?
)
data class Flags (
#SerializedName("ErrorLevel") val errorLevel : Int?,
#SerializedName("ErrorFlag") val errorFlag : Int?,
#SerializedName("Translation") val translation : String?,
#SerializedName("BitPosition") val bitPosition : Int?
)
data class SpareColumns (
#SerializedName("key") val key : String?,
#SerializedName("value") val value : String?
)
RequestService Interface:
#GET(NetworkUtils.JSON_SERVICE_URL)
fun getStatus(#Header("guid") guid: String) : Call<StatsModel>
Method which process the response:
fun getStatusService(mandatorGuid: String, #Nullable statusCallbacks: ChartsCallbacks.StatsCallbacks) {
val mandatorItem = MandatorItem(mandatorGuid)
val guid: MutableMap<String, String> = HashMap()
guid["guid"] = mandatorItem.guid
var statusData: StatsModel.Stats?
val call: Call<StatsModel> = createAPI().getStatus(mandatorItem.guid)
call.enqueue(object : Callback<StatsModel> {
override fun onFailure(call: Call<StatsModel>, t: Throwable) {
Log.i("TEST", "Status failure: $t")
}
override fun onResponse(call: Call<StatsModel>, response: Response<StatsModel>) {
if (response.isSuccessful) {
statusData = response.body()!!.stats
Log.i("TEST", "ITEM $statusData")
statusCallbacks.onSuccess(statusData)
}
}
})
}
I only need the Stats data from the response!
But everytime I'm trying to do the request I'm getting this ERROR:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
I know there are many posts on this subject but I couldn't find a solution to my problem. Any help would be appreciated!

Moshi expected BEGIN_OBJECT but was BEGIN_ARRAY at path $

This is not retrofit but manual parsing in a Firebase message handler service. I am using KotlinJsonAdapterFactory() when building my Moshi instance.
For some reason it thinks one of the nodes is an array when I am asking for it to be parsed as an object. Here is the JSON:
[
{
"$": {
"updateOrigin": "CIS",
"requestSource": "at20",
"requestID": "0000000000004144"
},
"TS": [{
"$": {
"rid": "202008207681819",
"uid": "L81819",
"ssd": "2020-08-20"
},
"Location": [{
"$": {
"tpl": "PADTON",
"wtd": "17:28",
"ptd": "17:28"
},
"dep": [{
"$": {
"et": "17:28",
"src": "Darwin"
}
}
],
"plat": [{
"_": "2",
"$": {
"platsup": "true",
"cisPlatsup": "true",
"platsrc": "M"
}
}
]
}
]
}
]
}
]
And here are my Data classes:
package com.cniekirk.traintimes.model
import com.squareup.moshi.Json
data class PushPortMessage(
val pushPortMessageItems: List<PushPortMessageItem>?
)
data class PushPortMessageItem(
#Json(name = "TS")
val tS: List<TS>?,
#Json(name = "$")
val messageAttrs: MessageAttrs?
)
data class TS(
#Json(name = "LateReason")
val lateReason: List<String>?,
#Json(name = "Location")
val location: List<Location>?,
#Json(name = "$")
val tsAttrs: TSAttrs?
)
data class MessageAttrs(
#Json(name = "updateOrigin")
val updateOrigin: String?
)
data class Location(
#Json(name = "arr")
val arr: List<Arr>?,
#Json(name = "dep")
val dep: List<Dep>?,
#Json(name = "pass")
val pass: List<Pass>?,
#Json(name = "plat")
val plat: List<Plat>?,
#Json(name = "$")
val stationAttrs: StationAttrs?
)
data class TSAttrs(
#Json(name = "rid")
val rid: String?,
#Json(name = "ssd")
val ssd: String?,
#Json(name = "uid")
val uid: String?
)
data class Arr(
#Json(name = "$")
val arrPassAttrs: List<ArrPassAttrs>?
)
data class Dep(
#Json(name = "$")
var depAttrs: DepAttrs?
)
data class Pass(
#Json(name = "$")
val arrPassAttrs: ArrPassAttrs?
)
data class Plat(
#Json(name = "_")
val platform: Int?,
#Json(name = "$")
val platAttrs: PlatAttrs?
)
data class PlatAttrs(
#Json(name = "platsup")
val platsup: Boolean?,
#Json(name = "cisPlatsup")
val cisPlatsup: Boolean?
)
data class StationAttrs(
#Json(name = "pta")
val pta: String?,
#Json(name = "ptd")
val ptd: String?,
#Json(name = "tpl")
val tpl: String?,
#Json(name = "wta")
val wta: String?,
#Json(name = "wtd")
val wtd: String?,
#Json(name = "wtp")
val wtp: String?
)
data class ArrPassAttrs(
#Json(name = "delayed")
val delayed: String?,
#Json(name = "et")
val et: String?,
#Json(name = "src")
val src: String?
)
data class DepAttrs(
#Json(name = "delayed")
val delayed: String?,
#Json(name = "et")
val et: String?,
#Json(name = "etUnknown")
val etUnknown: String?,
#Json(name = "etmin")
val etmin: String?,
#Json(name = "src")
val src: String?
)
I may just be being stupid but I can't find the issue. Here is how I'm parsing the JSON:
val pushPortMessage = data["body"]
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val pushPortAdapter = moshi.adapter(PushPortMessage::class.java)
pushPortMessage?.let {
val msg = pushPortAdapter.fromJson(pushPortMessage)
println(msg)
}
you are parsing a list of objects not object so the parsing should be something like this
val pushPortMessage = data["body"]
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
val listType = Types.newParameterizedType(List::class.java, PushPortMessageItem::class.java)
val adapter: JsonAdapter<List<PushPortMessageItem>> = moshi.adapter(listType)
val pushPortMessageList = adapter.fromJson(pushPortMessage )

Objectbox ToOne object is null

Issue Basics
ObjectBox version 2.5.1
Reproducibility: [always]
Hi, I am getting this error everytime I want to load my Object even though on saving I checked in the debugger and see that the relation target is not null and everything is saved correctly.
I am having those trhee entity classes
#Entity
data class NetflixCache (
val results: List<NetflixSearchResult>,
#Id var objectBoxId: Long?
) {
var searchParams: ToOne<SearchParams> = ToOne<SearchParams>(this, NetflixCache_.searchParams)
}
#Entity
data class SearchParams(val genrelist: String,
val type: String,
val imdbRatingMin: String,
val countryId: String,
val startYear: Int,
val endYear: Int,
val offset: Int? = 0,
val timeStamp: Long,
#Id var id: Long? = null)
#Entity
data class NetflixSearchResult (
val vtype: String?,
val img: String?,
val nfid: Long?,
val imdbid: String?,
val title: String?,
val clist: String?,
val poster: String?,
val imdbrating: Double?,
val synopsis: String?,
val titledate: Date?,
val year: Int?,
var id: Long,
#Id var objectBoxId: Long?
)
Using this code to save:
val cacheBox = LetsFlixApplication.boxStore.boxFor(NetflixCache::class.java)
val netflixCache = NetflixCache(searchResults, null)
netflixCache.searchParams.target = searchParams
cacheBox.put(netflixCache)
And this code to load:
val cachedResult = cacheBox.all //<-Exception is thrown here
As you can see in debugger when saving, ToOne Object is NOT null:
https://ibb.co/s3tdhqP
This is the exact exception message I am getting:
ToOne object is null inside com.haenles.letsflix.domain.NetflixCache
Issue for me was that data class was missing default values as recommended in the doc:
#Entity
data class User(
#Id var id: Long = 0,
var name: String? = null
)

Categories

Resources