How to check if an object has a certain property - android

I have two distinct classes:
internal data class ClassB(
#Json(name = "id") val id: String?,
#Json(name = "name") val name: String?,
#Json(name = "url") var contentUrl: String?,
#Json(name = "mediaImageUri") val coverUrl: String?,
#Json(name = "mediaVideoCoverImageUri") val videoCoverUrl: String?
)
internal data class ClassC(
#Json(name = "tileId") val id: String?,
#Json(name = "friendId") val friendId: String?,
#Json(name = "profilePictureUri") var profilePicture: String?,
#Json(name = "name") var name: String?
)
That inherit from the same class:
internal open class ClassA(
#Json(name ="type") var type: String?,
#Json(name ="sponsor-offer") var offer: SponsorOffer?,
#Json(name ="date") var date: Date?,
#Json(name ="weight") var priorityWeight: Int?
)
I am using an API call that returns a list of ClassA and is parsed by retrofit into a List, and need to cast each object onto one of the child classes before adding it to a local ArrayList<Any>
I am attempting to do this by iterating through the list returned and checking for the proprietary attributes of Classes B and C. then casting to object to the appropriate one before adding it to a local array. How can I check for these attributes? Is there a better way to do what I am attempting to do?
classA.javaClass.kotlin.members.any is not working

If ClassB and ClassC both extend ClassA, then you can just use the is keyword to check the type and then cast it
val thing: ClassA = getThing()
if (thing is ClassB) {
// thing should have been smart-cast to ClassB in here, or you can:
val thingB = thing as ClassB
}
or you could use a when block to check the possible types.
Or you can use the safe-cast operator as?, which evaluates to null if you can't cast to that type:
(thing as? ClassB)?.let { ... } ?: // it was null, so it's not ClassB, so...
But if you're doing this to put them into an ArrayList<Any> then there's no point casting them, that information is lost - it's a list of Anys! You'll have to recheck the type and cast each item when you take them out.
If you want to hold separate lists of ArrayList<ClassB> and ArrayList<ClassC>, then casting so you can put them in the right list (which will only accept that type) is ok - you'll know exactly what you're getting out of those

Related

How to make a post method with data class + retrofit + moshi in kotlin?

I want to fill the data class with the data received from the user and pass it to the service with retrofit. The structure I set up is the mvvm structure and how can I adapt it to this structure,
The structure I have set up is as follows.
hear is my Data model code
RegisterLoginDataModel
#JsonClass(generateAdapter = true)
data class RegisterLoginDataModel(
#Json(name = "userGender")
var userGender: String?,
#Json(name = "userGoal")
var userGoal: String?,
#Json(name = "userTargetWeight")
var userTargetWeight: String?,
#Json(name = "userCurrentWeight")
var userCurrentWeight: String?,
#Json(name = "userTargetHeight")
var userTargetHeight: String?,
#Json(name = "userCurrentHeight")
var userCurrentHeight: String?,
#Json(name = "userBirthDay")
var userBirthDay: String?,
#Json(name = "userMail")
var userMail: String?,
#Json(name = "userName")
var userName: String?,
#Json(name = "userPassword")
var userPassword: String?
)
I have a data class that I will use for post in the data package. Can I access it directly from the ui or do I need to create a separate class for the domain and ui package, how can I do this? Could you help ?
In terms of architecture, it is better to build a model in the domain layer
which ends with Request.
Then give it to your network layer library ( in here retrofit ).
The operation of creating an instance of the model you created in the domain layer is also done in a place like UseCase

Mapping database model to Ui model

I try to make the project based on clean architecture so that each layer could have its own data model.
I have a database that contains 2 Entities: "movie" and "details".
#Entity(tableName = "movie")
data class MovieDbModel(
var page: Int,
#PrimaryKey(autoGenerate = false)
var id: Int,
var poster_path: String,
var overview: String,
var original_title: String)
#Entity(tableName = "details")
data class DetailsDbModel (
#PrimaryKey(autoGenerate = false)
val id: Int,
val genres: Genres,
val runtime: Int,
)
I want to map those 2 entities to 1 UI model "MovieAndDetailsUi " and convert it to MutableList that I will use for liveData.
data class MovieAndDetailsUi (
val page: Int,
val id: Int,
val poster_path: String,
val overview: String,
val original_title: String,
val genres: List<GenreUi>,
val runtime: Int,
)
But I have problems with that. Could you please show me the best way to do that? Thank you.
If you want to map those two you could create a companion object on the MoviesAndDetailsUi class that takes both entities and combines them, for example
data class MovieAndDetailsUi (
val page: Int,
val id: Int,
val poster_path: String,
val overview: String,
val original_title: String,
val genres: List<GenreUi>,
val runtime: Int,
) {
companion object {
fun fromDatabaseEntities(movie: MovieDbModel, details: DetailsDbModel) {
return MovieAndDetailsUI(
page = movie.page,
id = movie.id,
poster_path = movie.poster_path,
overview = movie.overview,
original_title = movie.original_title,
genres = details.genres,
runtime = details.runtime
)
}
}
}
That way on your view model you could just get the data from the DB and map it to the UI class, for example:
fun getMovies(): MutableList<MovieAndDetailsUi>() =
viewModelScope.launch() {
withContext(Dispatches.IO) {
val movies: List<MovieDbModel> = ... // Access the DB and get the movies
val details: List<DetailsDbModel = ... // Access the DB and get the details
val zipData = movies.zip(details) {movie, detail -> Pair(movie, detail)}
val mappedData = zipData.map { pair -> MovieAndDetailsUi.fromDatabaseEntities(pair.first, pair.second) }.toMutableList()
liveData.postValue(mappedData)
}
}
I also agree that in this case you should go with the flat structure on the entities as you can skip the mapping and also avoid having multiple classes with the same attributes basically, but in case you want to go this way here's how. Also, I don't know how you are associating the details and movie table and how you query the tables, you might have a problem there too as there's no foreing key on movies referencing to details or vice versa. I added the zip function just for the example but you should have a proper way to associate the movies and the details objects

Merge two different data class lists in to the the third one Kotlin

I want to add additional field to my new data class from the old one which has an extra field of balance value. I have created data class list with the ID and the Values (balance), which I want to merge first data class list with the second to make 3rd list - similarly like union in sql.
first data class
data class Coin(
val id: String,
val price_usd: Double,
val name: String,
val rank: Int,
val symbol: String
)
second data class
data class CurrencyBalance(
val id: String,
val quantity: String
)
The aim is to create this type of data class list
data class CoinData(
val id: String,
val price_usd: Double,
val name: String,
val rank: Int,
val symbol: String,
val quantity: String
)
Is something like this what you are looking for?
fun convert(currencyBalances: List<CurrencyBalance>, coins: List<Coin>): List<CoinData> =
currencyBalances.map { currencyBalance ->
coins.firstOrNull { coin -> coin.id == currencyBalance.id }
?.let { coin -> CoinData(coin.id, coin.price_usd, coin.name, coin.rank, coin.symbol, currencyBalance.value) }
}.filterNotNull()
I assumed here that the fields in a CurrencyBalance are called id and value

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
)

Is this expression to get a nested array possible with Retrofit?

In a previous question some users commented as a response to access a nested array that this is possible:
fun getMovies(): Single<Response<List<Result>>>
But every time that I try to implement it it gives me the Error message:
No type arguments expected for class Response
This is my Model Class:
data class Response(
val page: Int?,
val total_results: Int?,
val total_pages: Int?,
val results: List<Result>
) {
//#Entity
data class Result(
val popularity: Double?,
val vote_count: Int?,
val video: Boolean?,
val poster_path: String?,
val id: Int?,
val adult: Boolean?,
val backdrop_path: String?,
val original_language: String?,
val original_title: String?,
val genre_ids: List<Int>?,
val title: String?,
val vote_average: Double?,
val overview: String?,
val release_date: String?
)
}
My Api Interface
package com.example.moviesapplication.model
import io.reactivex.Single
import retrofit2.http.GET
interface MoviesApi {
#GET("/3/discover/movie?api_key=${apiKey}&language=en-US&sort_by=popularity.desc&include_adult=false&include_video=false&page=1")
fun getMovies(): Single<List<Response.Result>>
}
So if anyone know if the expression stated is possible or something similar, please let me know.
Your Response class doesn't have any generic parameters, and that's what the error is pointing out.
You can return Single<Response> and the array will always be a List of Result, it doesn't have any dynamic types.
I think you import wrong package, maybe you import Response of Okhttp instead of your Response data class since Response of OkHttp doesn't want type argument.
At the same time your Response is a bit strange, Your Response class does not want type argument. Your response should be something like
fun getMovies(): Single<Response>
instead of
fun getMovies(): Single<Response<List<Result>>>
I think it become like this because you confuse between Response of Retrofit that need type argument [Response<T>] and your Response data class that does not need type argument.
Recommend
I thinks it will be better if your Response class is some think like
data class Response<T>(
val page: Int?,
val total_results: Int?,
val total_pages: Int?,
val results: List<T> // or val results: T
)
Because if you have lots pf responses that have Base like Response class but, its result have different model or list (something likeList<ResultMovie> or List<...>). You only need to pass T to your Base model like Response<Result>. You not need to repeat to declare Response every time you have Base model like this, and it also easier to manage or fixes later.

Categories

Resources