Using Single and Rxjava does not execute the retrofit request? - android

Hi i am using retrofit and rxjava to make a simple request and get the response back but it doesnt seem to be making the request itself or getting the response back?
This is my retrofit code:
public class Controller
public Single<List<ListItems>> getItems() {
return apiCall().getItems();
}
private ServiceCallsApiCall() {
OkHttpClient okHttpClient = new OkHttpClient().newBuilder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
ServiceCallsApiCall serviceCalls= retrofit.create(ServiceCallsApiCall.class);
return foodHygieneServiceCalls;
}
my ServiceCallsApiCall class
#GET("Authorities/basic")
Single<List<ListItems>> getItems();
Here is my Rxjava part of my code that subscribes and observes this
public void getItems() {
new Controller().getItems()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new SingleObserver<List<ListItems>>() {
#Override
public void onSubscribe(Disposable d) {
Log.d("","onSubscribe");
}
#Override
public void onSuccess(List<ListItems> items) {
viewPresenterCallBacks.updateView(items);
}
#Override
public void onError(Throwable e) {
Log.d("","onError" + e.getMessage());
}
});
}
None of the onSuccess or onError gets called

I had a similar problem recently. The problem is not from retrofit or rxJava, its from the deserialization of the JSON to your ListItem POJO. I believe the crux of the issue is that your JSON deserialization library is unable to translate the Json to POJO.
If you are using Jackson you can just add the #JsonIgnoreProperties(ignoreUnknown = true) to your ListItem class.
In my case I was using GSON and since i wasn't interested in all the JSON properties I just changed my initial retrofit method signature from Single<Movies> getRecentMovies(); to Single<ResponseBody> getRecentMovies(); and extracted the desired fields in my response.

Related

Read plain text response from server using Retrofit

I'm working on an application that uses Retrofit for network operations. As it stands, everything works well with GsonConverterFactory handling serialization. Here is how I setup Retrofit
Retrofit.Builder()
.baseUrl("<base url>")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
Now I need to connect to a legacy service which returns content in text/plain; charset=utf-8 format. Here is the Retrofit interface
#GET("https://<domain>/<endpoint>?Type=Query")
suspend fun callStatus(#Query("userId") id: Int): Response<String>
This will return status of a call for a valid user. For instance, if the user is valid and there is a status, it returns "Active" as plain text. If there is no valid user, it returns an error code of #1005
I could add custom converter factory like this (found on the web)
final class StringConverterFactory implements Converter.Factory {
private StringConverterFactory() {}
public static StringConverterFactory create() {
return new StringConverterFactory();
}
#Override
public Converter<String> get(Type type) {
Class<?> cls = (Class<?>) type;
if (String.class.isAssignableFrom(cls)) {
return new StringConverter();
}
return null;
}
private static class StringConverter implements Converter<String> {
private static final MediaType PLAIN_TEXT = MediaType.parse("text/plain; charset=UTF-8");
#Override
public String fromBody(ResponseBody body) throws IOException {
return new String(body.bytes());
}
#Override
public RequestBody toBody(String value) {
return RequestBody.create(PLAIN_TEXT, convertToBytes(value));
}
private static byte[] convertToBytes(String string) {
try {
return string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
}
But I didn't see it make any difference. Also, it could well disguise JSON as normal text and break all existing service. Is there a better way to handle this scenario? I thought of having separate retrofit instance for plain text, bit dirty though. Do you have any other suggestions/solutions?
Edited
Response header contains the content type as
Content-Type: text/plain; charset=utf-8
Actual response for valid user
Active
Actual response for invalid user
#1005
Update
The order in which you register the converter factories matters. ScalarsConverterFactory must come first.
it should be possible by adding ScalarsConverterFactory when building the Retrofit object.
This can be done alongside with other json converters, e.g.
Retrofit.Builder()
.baseUrl("<base url>")
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
After that, you should be able to receive plaintext responses.
You probably need to add this to your dependencies as well:
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
The following is the way that how I get response as plain text (using Java not Kotlin).
Step One
in your gradle (Module);
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
Step Two
Create an interface
public interface MyInterface {
#GET("something.php")
Call<String> getData(#Query("id") String id,
#Query("name") String name);
}
Step Three
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com")
.addConverterFactory(ScalarsConverterFactory.create())
.build();
MyInterface myInterface = retrofit.create(MyInterface.class);
Call<String> call = myInterface.getData("id","myname");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
String plain_text_response = response.body();
}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
});
You don't need to use a your custom implementation of Converter.Factory you could just use
// your coroutine context
val response = callStatus(userId)
if(response.isSuccessful){
val plainTextContent = response.body()
// handle plainText
} else {
//TODO: Handle error
}
//...
Two things to check first that function should not be suspended & your response should be in the Callback
No need to add extra implementation of scalars.
#GET
fun getJson(
#Url baseUrl: String = slab_pro
): Call<DataClass>

Why call have code 400 on response when postman doing it correct?

I want to provide clear code in accordance with the guidelines architecture and CleanCode rules.
I tried to use gson library to serialize data used in retrofit call.
I know that i can use #SerializedName in my model class but i want to learn how to use gson builder.
In MainActivity i have:
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CredentialModel credentials = new CredentialModel("User", "Password");
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(credentials);
UserApiClient userApiClient = RetrofitInstace.getRetrofitInstance().create(UserApiClient.class);
Call<String> call = userApiClient.login(json);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
toastNotify(String.valueOf(response.code()));
}
#Override
public void onFailure(Call<String> call, Throwable t) {
toastNotify("Fail");
}
});
}
});
Interface UserApiClient:
#POST("/api/AppUser/login")
Call<String> login(#Body String credentials);
RetrofitInstance class:
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient())
.build();
}
return retrofit;
}
I receive 400 error code when postman with data coppied from json variable in debug mode to body give me code 200. It isn't my serwer so i can't tell what is done on server side. Also im new in android and don't know how to check raw request in android studio yet.
You're using GsonConverterFactory.create() but you're passing String at Call<String> login(#Body String credentials); . You can't do that.
You need to pass in a POJO that is serialized by gson. Or else retrofit will pass in a null object as the body.
class MyBody {
// serialize it here
}
// You also cannot use a String at Call<String>
// for now use ResponseBody. Create a POJO class later though
Call<ResponseBody> login(#Body MyBody credentials);
What you want to do is already being done inside retrofit.
// retrofit does this for you underneat when you use GsonConverterFactory.create()
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(credentials);

How to get the request URL for a Retrofit object?

I need to log the request URL that Retrofit creates. I don't find any getter methods on Retrofit object or web interface that is generated via Retrofit. The following is my code, where I want to log the address of every request:
public void onRequestFoods() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Const.BASE_LOCAL)
.addConverterFactory(GsonConverterFactory.create())
.build();
FoodOrderInterface foodInterface = retrofit.create(FoodOrderInterface.class);
Log.d(TAG, "onRequestFoods: request url: ");
foodInterface.listFoods().enqueue(new Callback<FoodResponse>() {
#Override
public void onResponse(Call<FoodResponse> call, Response<FoodResponse> response) {
List<Food> foods = response.body().getBody().getFoods();
mPresenter.onResponse((ArrayList<Food>) foods);
}
#Override
public void onFailure(Call<FoodResponse> call, Throwable t) {
mPresenter.onRequestFailed(t.getMessage());
}
});
}
I think what you need is http logging interceptor the github repo has a straightforward example of how to get it up and running

Retrofit is not making api call

I'm using retrofit 2 to make api call to my server but it get stucked when trying to make api call. This is my code
public interface GOTApi {
#GET("characters.json")
Call<GOTCharacterResponse> getCharacters();
}
Intermediate class to get the data
public class GOTCharacterResponse {
List<GOTCharacter> characters;
}
My class to make api call
public class GOTService {
public static final String BASE_URL = "https://project-8424324399725905479.firebaseio.com/";
public static GOTApi getGOTApi(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(GOTApi.class);
}
public static void getCharacters(){
getGOTApi().getCharacters().enqueue(new Callback<GOTCharacterResponse>() {
#Override
public void onResponse(Call<GOTCharacterResponse> call, Response<GOTCharacterResponse> response) {
if(response.isSuccessful()){
}
}
#Override
public void onFailure(Call<GOTCharacterResponse> call, Throwable t) {
int a = 0;
}
});
}
}
These are the libraries I'm using
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.okhttp3:okhttp:3.3.1'
It always get stucked in the getCharacters() method. Of course I have internet permission set in Mainfest.
You may try using Retrofit2 with RxJava, it is more convenient.
public Retrofit providedRetrofit(OkHttpClient okHttpClient){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit;
}
Your API interface will look like
public interface Api {
#GET("api/service/schedule/{filial}")
Observable<Response<GOTCharacter>> getSchedule(#Path("some_param") String param);
}
You also need to parse response from JSON. You didn't provided
GOTCharacter class, but you can create code from json response by using
http://www.jsonschema2pojo.org/ service
I think you are implementing wrong onResponse() OR Callback(), because I am using Retrofit 2 too, in which onResponse() looks like this:
#Override
public void onResponse(Response<ListJsonResponseRestaurant> response, Retrofit retrofit) {
...
...
}

How to convert data getting json object and string as well using retrofit?

From git There was a such a suggestion
but I don't know how to use it,where to call ,any tip could be useful
retrofit lets to convert json,xml ,but I need to have as a object,converted data and string as well
#GET("whatever")
Call<Pair<User, String>> whatever();
Type firstType = //reflection
Converter<ResponseBody, Object> delegate = retrofit.nextResponseBodyConverter(firstType, annotations);
return new Converter<ResponseBody, Pair<Object, String>>() {
#Override public Pair<Object, String> convert(ResponseBody body) {
String string = body.string();
Object object = delegate.convert(ResponseBody.create(null, string));
return new Pair<>(object, string);
}
};
Please, checkout the Retrofit documentation first. It's useful.
You can also go through this tutorial. It's a little bit long, but it is good enough.
All in all you need four things:
POJO (Plain Old Java Object) a.k.a Student, Car, User etc.
REST client - check out the tutorial
Interface where to describe each part of the API - check out the tutorial
Wait for the callback from retrofit when you make a call to the API and do whatever you want with the info - check out the tutorial
If your #GET request is receiving something like that:
{
"user": {
"id": 1,
"name": "John"
},
"str": "Hello World"
}
Interface:
public interface MyInterface {
#GET("/api/user/1")
Call<ResponseBody> getMyObject();
}
Make the request:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://server.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
MyInterface service = retrofit.create(MyInterface.class);
service.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {
String raw = response.body().string();
MyObject object = new Gson().fromJson(raw, MyObject.class);
}
#Override
public void onFailure(Throwable t) {
}
});

Categories

Resources