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.
Related
I am a beginning computer science student. For school I have to make an app that can display data from an API. I use this API: http://openlibrary.org/search.json?q= The user of my app has to enter a booktitle or author, so they can find a book. I add the search value to the url. For example, if I want to search "The hobbit", the url would look like this: http://openlibrary.org/search.json?q=the%hobbit". However, the data does not get displayed. I don't have any errors either. Is there anyone that can help me?
Thanks in advance!
My API service class
private const val BASE_URL = "http://openlibrary.org/"
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.build()
interface BoekenAPIService {
#GET("search.json")
suspend fun getBooksByTitle(#Query("q")search: String) : Base_BookTitle
}
object BookAPI {
val retrofitService : BoekenAPIService by lazy { retrofit.create(BoekenAPIService::class.java) }
}
My Base_BookTitle class
data class Base_BookTitle (
val numFound : Int,
val start : Int,
val numFoundExact : Boolean,
val docs : List<Q>,
val num_found : Int,
val book : String,
val offset : String
)
My Q class
#Parcelize
data class Q (
val key : String,
val type : String,
val seed : List<String>,
val title : String,
val title_suggest : String,
val has_fulltext : Boolean,
val edition_count : Int,
val edition_edition_key : List<String>,
val publish_date : List<String>,
val publish_year : List<Int>,
val first_publish_year : Int,
val number_of_pages_median : Int,
val lccn : List<Int>,
val publish_place : List<String>,
val oclc : List<Int>,
val contributor : List<String>,
val lcc : List<String>,
val ddc : List<Double>,
val isbn : List<Int>,
val last_modified_i : Int,
val ebook_count_i : Int,
val ia : List<String>,
val public_scan_b : Boolean,
val ia_collection_s : String,
val lending_edition_s : String,
val lending_identifier_s : String,
val printdisabled_s : String,
val cover_edition_cover_edition_key : String,
val cover_i : Int,
val publisher : List<String>,
val language : List<String>,
val author_author_key : List<String>,
val author_name : List<String>,
val author_alternative_name : List<String>,
val person : List<String>,
val place : List<String>,
val subject : List<String>,
val time : List<String>,
val id_alibris_id : List<Int>,
val id_amazon : List<String>,
val id_canadian_national_library_archive : List<Int>,
val id_depĆ³sito_legal : List<String>,
val id_goodreads : List<Int>,
val id_google : List<String>,
val id_librarything : List<Int>,
val id_overdrive : List<String>,
val id_paperback_swap : List<Int>,
val id_wikidata : List<String>,
val ia_loaded_id : List<String>,
val ia_box_id : List<String>,
val publisher_facet : List<String>,
val person_person_key : List<String>,
val place_place_key : List<String>,
val time_facet : List<String>,
val person_facet : List<String>,
val subject_facet : List<String>,
val _version_ : Int,
val place_facet : List<String>,
val lcc_sort : String,
val author_facet : List<String>,
val subject_subject_key : List<String>,
val ddc_sort : Double,
val time_time_key : List<String>
): Parcelable
I got the Base_Booktitle and Q class from a json to kotlin converter.
The ViewModel in which i call the method to display the data
class SearchViewModel(__user: User) : ViewModel() {
var _user = MutableLiveData<User>()
val user:LiveData<User>
get() {
return _user
}
var _baseBookTitle = MutableLiveData<Base_BookTitle?>()
val baseBooktitle : LiveData<Base_BookTitle?>
get() {
return _baseBookTitle
}
var search = MutableLiveData<String>()
var _error = MutableLiveData<String>()
val error : LiveData<String>
get() {
return _error
}
var _response = MutableLiveData<Q?>()
val response: LiveData<Q?>
get(){
return _response
}
init {
_user.value = __user
_error.value = null
}
fun searchBtnClicked(){
viewModelScope.launch {
try{
_baseBookTitle.value = BookAPI.retrofitService.getBooksByTitle(search.value!!)
}
catch (e: Exception){
_error.value = e.localizedMessage
}
}
}
fun onBookClicked(book: Q){
_response.value = book
}
fun navigateToBookFinished(){
_response.value = null
}
}
Thanks to a comment, I am now able to use a LoggingIntercepter
This is what I see in the logcat when I click the search button
2022-01-07 11:24:50.035 18171-18233/be.nienke.eindopdracht D/OkHttp: --> GET http://openlibrary.org/search.json?q=hobbit
2022-01-07 11:24:50.035 18171-18233/be.nienke.eindopdracht D/OkHttp: --> END GET
2022-01-07 11:24:50.055 18171-18215/be.nienke.eindopdracht I/OpenGLRenderer: Davey! duration=1591ms; Flags=0, IntendedVsync=183638171307131, Vsync=183639721307069, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=183639736870720, AnimationStart=183639736926020, PerformTraversalsStart=183639737189320, DrawStart=183639737431620, SyncQueued=183639738395720, SyncStart=183639738576620, IssueDrawCommandsStart=183639739072520, SwapBuffers=183639760591820, FrameCompleted=183639762891920, DequeueBufferDuration=250000, QueueBufferDuration=644000,
2022-01-07 11:24:50.237 18171-18233/be.nienke.eindopdracht D/OkHttp: <-- HTTP FAILED: java.net.UnknownServiceException: CLEARTEXT communication to openlibrary.org not permitted by network security policy
To solve the UnknownServiceException, I added this line to the AndroidManifest file:
android:usesCleartextTraffic="true"
Now the logcat shows the data from my API, but it doesn't display it on screen. Anyone that can help?
data class NewsResponse(
val articles: List<Article>,
val status: String,
val totalResults: Int
)
data class Source(
val id: String,
val name: String
)
data class Article(
val author: String,
val content: String,
val description: String,
val publishedAt: String,
val source: Source,
val title: String,
val url: String,
val urlToImage: String
)
object RetrofitHelper {
fun getInstances():Retrofit{
return Retrofit.Builder()
.baseUrl("https://newsapi.org/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
}
interface NewsService {
#GET("v2/everything?")
suspend fun getNews(#Query("country")country:String,#Query("page")page:Int,#Query("apiKey")apiKey:String):Response<NewsResponse>
}
This below code is written on MainActivity
val newsservice=RetrofitHelper.getInstances().create(NewsService::class.java)
GlobalScope.launch(Dispatchers.IO) {
val result=newsservice.getNews(country,page, apiKey)
if(result.isSuccessful){
Toast.makeText(this#MainActivity,"HEllo World",Toast.LENGTH_LONG).show()
val list=result.body()!!.articles
list.forEach {
Log.d(debug,it.source.id)
}
}
}
I corrected my mistake #Query("country") this was wrong i have to use #Query("q") thats my result giving null list
I'm trying to create a request using Retrofit2 in Kotlin and my Json data looks like this:
{
"actionRights": [
{
"hasArticlePriceChangeRights": false,
"hasStockLevelViewRights": false
}
],
"stats": {
"errors": 12,
"warnings": 21,
"outOfOrder": 58,
"running": 42
},
"markers": []
}
I need to get the "stats" data from my response.
How is my model class look like? I tried something but I get this error.
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
EDIT: I created this ModelClass and I'm still getting this error:
Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 2 path $
data class StatsModel(
#SerializedName("actionRights") val actionRights : List<ActionRights>,
#SerializedName("stats") val stats : Stats,
#SerializedName("markers") val markers : List<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
)
}
And I'm processing the response like this:
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) {
Log.i("TEST", "ITEM " + response.headers().toString())
statusData = response.body()!!.stats
Log.i("TEST", "ITEM $statusData")
statusCallbacks.onSuccess(statusData)
}
}
})
}
data class ActionRight(
val hasArticlePriceChangeRights: Boolean?=null,
val hasStockLevelViewRights: Boolean?=null
)
this is for state
data class Stats(
val errors:Int? = null,
val warnings? = null,
val outOfOrder? = null,
val running? = null
)
call this model into your retrofit you got only your state
data class StatsModel(
val actionRights: ArrrayList<ActionRight>?=null,
val markers: ArrrayList<Any>?=null,
val stats: Stats? = null)
Your main model:
data class MyModel(
val actionRights: List<ActionRight?>?,
val markers: List<Marker?>?,
val stats: Stats?
)
Your Sub Models:
data class ActionRight(
val hasArticlePriceChangeRights: Boolean?,
val hasStockLevelViewRights: Boolean?
)
data class Marker(
val test1: Int?,
val test2: String?
)
data class Stats(
val errors: Int?,
val outOfOrder: Int?,
val running: Int?,
val warnings: Int?
)
I create a fake Marker class because I don't know your full json data.
You should modelling Marker class for according your json data. You can call MyModel class from retrofit.
Edit Response (Only parse Stats class)
This class represent parse only Stats class, you can call from retrofit. #JsonIgnoreProperties should ignore other data.
#JsonIgnoreProperties(ignoreUnknown = true)
data class MyModel(
#JsonProperty("stats")
val stats: Stats?
)
#JsonIgnoreProperties(ignoreUnknown = true)
data class Stats(
#JsonProperty("errors")
val errors: Int?,
#JsonProperty("outOfOrder")
val outOfOrder: Int?,
#JsonProperty("running")
val running: Int?,
#JsonProperty("warnings")
val warnings: Int?
)
Note: The code use Jackson library.
implementation 'com.squareup.retrofit2:converter-jackson:2.5.0'
I'm trying to join three object list in one object with kotlin. But I don't know how to do it...
Some help will be appreciate.
This is my data class:
data class User(
val address: Address,
val company: Company,
val email: String,
val id: Int,
val name: String,
val phone: String,
val username: String,
val website: String
)
data class Post(
val body: String,
val id: Int,
val title: String,
val userId: Int
)
data class Comment(
val body: String,
val email: String,
val id: Int,
val name: String,
val postId: Int
)
That I want to do is get one object like this if possible:
data class PostJoin(body: String, id: Int, title; String, user: User, comments: List<Comment>)
This is that I'm trying to do it, only can mix two objects but no how I want.
val postUsers = post.joinBy(users) { (post,user) -> post.userId == user.id }
.map { PostViewModel(post = it.first, user = it.second) }
private inline fun <T : Any, U : Any> List<T>.joinBy(collection: List<U>, filter: (Pair<T, U>) -> Boolean): List<Pair<T, List<U>>> = map { t ->
val filtered = collection.filter { filter(Pair(t, it)) }
Pair(t, filtered)
}
Something like this might work:
val posts: List<Post>
val users: List<User>
val comments: List<Comment>
// initialize lists
...
val joinedPosts = posts.fold(ArrayList<PostJoin>()) { joinedPosts, post ->
val postComments = comments.filter { it.postId == post.id }
val user = users.first { it.id == post.userId }
joinedPosts.add(PostJoin(post.body, post.id, post.title, user, postComments))
joinedPosts
}
Seems to work for me: Try it online!. Though I did give a pretty lazy input.
I have a class category and i pass into the extra, the category clicked.
this worked in 6 screens but in the last one I'm receiving null
the activity where i put the extra
adapter.setOnItemClickListener { item, view ->
val categories = item as Categories
val intent = Intent(view.context, LearningFirstLibras::class.java)
intent.putExtra(CATEGORY_KEY, categories.category)
startActivity(intent)
}
the category
#Parcelize
class Category(
val name: String,
val imageURL: String,
val real_name: String,
val object_1_screen_libras_image: String,
val object_1_screen_libras_text: String,
val object_2_screen_libras_text: String,
val object_2_screen_libras_image: String,
val object_3_screen_libras_text: String,
val object_3_screen_libras_image: String,
val object_1_screen_asl_text: String,
val object_1_screen_asl_image: String,
val object_2_screen_asl_text: String,
val object_2_screen_asl_image: String,
val object_3_screen_asl_text: String,
val object_3_screen_asl_image: String,
val question: String,
val answer: String,
val alternative_1: String,
val alternative_2: String,
val alternative_3: String,
val alternative_4: String
) : Parcelable {
constructor() : this("", "", "", "", "",
"","","","",
"","","","",
"","","","","","",
"","")
}
the activity where i got null
class Quiz : AppCompatActivity() {
var categoryF:Category = Category()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quiz)
categoryF = intent.getParcelableExtra(NewWordsActivity.CATEGORY_KEY)
Try it
Sending the Parcelable Using Bundle
val intent = Intent(this, ProfilePage::class.java)
var bundle = Bundle()
bundle.putParcelable(CATEGORY_KEY, categories.category)
intent.putExtra("myBundle",bundle)
startActivity(intent)
Recovering Parcelable
val bundle = intent.getBundleExtra("myBundle")
var categoryF = bundle.getParcelable<Category>(NewWordsActivity.CATEGORY_KEY) as Category