I'm facing an issue with an android app while trying to retrieve some Api data using RxJava2 And Retrofit2 (in Kotlin). Once I execute the call, the screen turns black and the application just doesn't respond anymore, without any log messages.
The call URL I'm using is the following:
api/apartments?projection={"id":1,"address":1}
The Service interface for this call is this one:
#GET("api/apartments?projection={\"id\":1,\"address\":1}")
fun getAllApartments(#Header(AUTHORIZATION) auth: String): Single<List<APTLIST>>
This is the way I execute the call:
override fun getAllApartments(): Single<List<APTLIST>> = retrofit.create(ApartmentsService::class.java).getAllApartments("$BEARER$token")
And this is how I call the function:
getAllApartmentsUseCase.getAllApartments()
.subscribe(
{
apartments.clear()
apartments.addAll(it)
view.showApartments(apartments)
},
{ println(it.message) }
)
This call works on Postman and the result is the following:
[
{
"_id": "591ecaca861a528a5b4c3d90",
"id": "ROC 03"
},
{
"_id": "591a0fb2861a528a5b4c3d60"
},
{
"_id": "58be94d484c4b0a468fb93e0",
"id": "CAN 2.3",
"address": "Els Refugis"
}
]
I guess you are making web call in main thread. It is strange, that you just get something like ANR and not android.os.NetworkOnMainThreadException.
getAllApartmentsUseCase
.getAllApartments()
.subscribeOn(Schedulers.io()) //scheduler in which observable will execute
.observeOn(AndroidSchedulers.mainThread()) //scheduler in which subscriber's methods will be called
.subscribe(/*subscriber*/)
https://medium.com/upday-devs/rxjava-subscribeon-vs-observeon-9af518ded53a
Related
I am working on creating an android application for the java spring Webflux API client.
I want to use retrofit, OkHttps, and coroutines flow android.
A sample response looks like this
{
"status": "ACCEPTED",
"isFinish": false,
"metaInfo": {
"requestId": "0e442156-9211-4b21-aeae-a50ec4ac1715"
}
}
{
"status": "PROCESS",
"isFinish": false,
"metaInfo": {
"requestId": "0e442156-9211-4b21-aeae-a50ec4ac1715"
}
}
{
"status": "PROCESS",
"isFinish": false,
"metaInfo": {
"requestId": "0e442156-9211-4b21-aeae-a50ec4ac1715"
}
}
{
"status": "SUCCESS",
"isFinish": true,
"metaInfo": {
"requestId": "0e442156-9211-4b21-aeae-a50ec4ac1715"
}
}
Each of these responses comes after an unavoidable time delay and I need to be able to receive each response in time.
in a traditional poll, I can get it after the last response.
Any suggestions are important to me. Thank you
I have api that return list of workers:
{
"items": [
{
"id": "e0fceffa-cef3-45f7-97c6-6be2e3705927",
"avatarUrl": "https://cdn.fakercloud.com/avatars/marrimo_128.jpg",
"firstName": "Dee",
"lastName": "Reichert",
"userTag": "LK",
"department": "back_office",
"position": "Technician",
"birthday": "2004-08-02",
"phone": "802-623-1785"
},
{
"id": "6712da93-2b1c-4ed3-a169-c69cf74c3291",
"avatarUrl": "https://cdn.fakercloud.com/avatars/alterchuca_128.jpg",
"firstName": "Kenton",
"lastName": "Fritsch",
"userTag": "AG",
"department": "analytics",
"position": "Orchestrator",
"birthday": "1976-06-14",
"phone": "651-313-1140"
},
....
]
}
I want to filter the response so that I only get information about a worker from a specific department.
I tried to do it like this:
interface WorkersApi {
#GET("users")
suspend fun getWorkers(
#Query("department") department: String
): Workers
}
But it return the same list without any filters. How can I filter the response so that I only get information about a worker from a specific department?
*Workers is just data class that hold only one field - list of items(workers)
What you tried to do changes the request to the server. It sends the department as query parameter with the request. If the server doesn't support this parameter nothing happens. I don't know if you work together with the people controlling the backend but you could discuss with them if they could add functionality for filtered results.
If instead, you want to filter the results after getting the full list from the server simply apply a filter on the list that you got.
you could do this on your Workers object
val department = "example"
val filteredList = workersObject.items.filter {it.department == department}
I'm using Retrofit to call an API which returns a list of objects like this:
[
{
"ID": 1,
"NAME": "text",
"VALUE": 10
},
{
"ID": 2,
"NAME": "text",
"VALUE": 20
},
...
]
My Retrofit API is:
#Headers("content-type: application/json")
#GET("FAMILY_VALUES")
suspend fun getFamilyValues(): List<Family>
Everything is ok so far. Unfortunately sometimes the server sends data with null values:
[
...
{
"ID": 5,
"NAME": "text",
"VALUE": null
},
...
]
I don't know why it happens. The server is out of my control and I cannot change the received data. However this records are useless to my logics and I would like to exclude them from my output List, so that the final list doesn't contain an item with ID=5 at all.
How can I achieve this with Retrofit and GSON? My ugly workaround is to loop the list later and discard the items, I'm looking for a more performing solution that doesn't add the useless items at all.
UPDATE: another solution I've tried was to add a JsonDeserializer that skips the wrong records but it didn't work. My hope was that GSON skipped the null returned items but instead it added null values.
class FamilyDeserializer : JsonDeserializer<Family> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Family? {
json as JsonObject
return if ((json.get("VALUE") !is JsonNull)) {
Family(
json.get("ID").asInt,
json.get("NAME").asString,
json.get("VALUE").asInt
)
} else {
null
}
}
}
I'm migrating a Kotlin code from using a backend to use a new one.
I'm having an issue in the next situation:
The old backend would return a JSON response-body with next schema:
{code: "...", message: "...", data: "{"id": ..., "name": ..., ...}"}.
But the new backend returns only
If not-success: {code: "...", message: "..."}.
If success or {"id": "...", "name": "...", ...}
This should be mapped to a class ResponseBody.
data class ResponseBody<T>(
#SerializedName(value: "code") val responseCode: Int,
#SerializedName(value: "message") val message: Int,
#SerializedName(value: "data") val data: T?)
)
Which is inside a class Data Wrapper:
data class DataWrapper<T>(
val responseBody: ResponseBody<T>?,
val throwable: Throwable?)
)
I have a method execute() where data mapping should happen after receiving response from backend.
fun <T> execute(observable: Single<ResponseBody<T>>): Single<DataWrapper<T>> {
return observable
.subscribeOn(Schedulers.io())
.map {t -> DataWrapper(t, null)}
.onErrorReturn {t -> DataWrapper(null, t)}
.map {
(...)
}
}
So, my problem is that I'm not able to serialize in the case of success the response-body I get
{"id": "...", "name": "...", ...}
to the 'data' property in ResponseBody. I know that the problem is the fact that that response-body is not encapsulated in a {"data": ...} like it was in the old backend so the serialization doesn't work. Is there a dirty fix for this? Any suggestion?
I want to get, in the case of success, the response-body to be saved in the 'data' property of the ResponseBody class.
Thank you in advance!
This is my Json Data
[
{
"id": 1,
"name": "ANDY",
"Game": {
"car": "1 Item",
"plane": "1 Item"
},
"location": {
"home": 5.555,
"office": 150.316
}
}
}
Here is my calling API :
#GET("/sample.json")
Observable<Response> getAppTours(#Header("If-None-Match") String etag);
How can I access the game and get the car & plane location : home & office ?
I am using Retrofit and Ormlite. I keep getting error on Game and Location while I am adding the #DATABASEFIELD Game game;
The error is said :
Attempt to invoke interface method 'com.j256.ormlite.stmt.QueryBuilder com.j256.ormlite.dao.Dao.queryBuilder()' on a null object reference
It's simple to to get Nested objects if you use core class library to read Json. But Using retrofit you have to create another POJO (model) for game object. Have a brief look.
Copy/paste this JSON as input of this page http://www.jsonschema2pojo.org/:
[
{
"id": 1,
"name": "ANDY",
"Game": {
"car": "1 Item",
"plane": "1 Item"
},
"location": {
"home": 5.555,
"office": 150.316
}
}
]
You had a } instead of a ] to close it up, on biggies. Now change the source type to JSON and select your converter accordingly.
You can check the Retrofit's available converters in their main documentation almost at the bottom of the page http://square.github.io/retrofit/.
Make sure you add the needed line to your gradle, being that something similar to:
Gson: com.squareup.retrofit2:converter-gson
Jackson: com.squareup.retrofit2:converter-jackson
Moshi: com.squareup.retrofit2:converter-moshi
Protobuf: com.squareup.retrofit2:converter-protobuf
Wire: com.squareup.retrofit2:converter-wire
Now from jsonschema2pojo click on "Preview" or "Zip" you will then be able to download your new model. Copy those classes to your project.
Your new Retrofit interface will look something like:
public interface YourService {
#GET("your/url")
Call<Yourclass> listStuff();
}
Then, after that, you will be able to make the HTTP request with:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create()) //Converter
.build();
// Create an instance of our GitHub API interface.
YourService service = retrofit.create(YourService.class);
// Create a call instance for looking up Retrofit contributors.
Call<Yourclass> call = service.listStuff();
And get your games and locations with:
Yourclass myclass = call.execute().body();
Game game = myclass.getGame();
Location location = myclass.getLocation();
Check these if you want to get more details:
https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/SimpleService.java
http://square.github.io/retrofit/
https://github.com/joelittlejohn/jsonschema2pojo