Is possible to use multiple retrofit API - android

I am using retrofit 2. I need to use 2 different Rest API, because they have different base URL, headers and cookies.
public class RestClient {
private static IRestApi REST_CLIENT;
static {
setupRestClient();
}
public static IRestApi get() {
return REST_CLIENT;
}
private static void setupRestClient() {
Interceptor interceptor = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
//add some cookies & headers
}
};
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(GenericConstants.READ_TIMEOUT, TimeUnit.SECONDS)
.connectTimeout(GenericConstants.CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GenericConstants.BASE_ENDPOINT_INSTAGRAM)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
REST_CLIENT = retrofit.create(IRestApi.class);
}
}
I am using it like so:
Call<Obj> call = RestClient.get().myMethod(params);
I want to create 2 clases like this, because I have 2 types of requests, 1 with headers and cookies and one plain, is this possible?

you can create method of retrofit url like
public Retrofit getAdapter(String url){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
return retrofit;
}
Use this adapter wherever you want.

Related

How to "wait" for data from API

I have a problem,
How to wait for data from API?
I would write code like this:
List<User> userList = dataAPI.getAllUser();
I would have a list an use it wherever I want.
I don't want to Override any methods.
DataAPI:
public class DataAPI {
public DataAPI(){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
userAPI = retrofit.create(UserService.class);
public class DataAPI {
[...]
private UsertService userAPI;
public DataAPI(){
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
userAPI = retrofit.create(UserService.class);
}
Observable<List<User>> getAllUser() {
return userAPI.getAllUser();
}
}
UserService
#GET("/user/all")
Observable<List<User>> getAllUser();
It could be done with rxJava, for more details: read
You just need to set timeout and increase it as you need to wait for the response coming from service. (Give priority to writeTimeout)
OkHttpClient client = new OkHttpClient.Builder();
client .connectTimeout(10, TimeUnit.SECONDS);
client .writeTimeout(30, TimeUnit.SECONDS);
client .readTimeout(40, TimeUnit.SECONDS);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://api.yourapp.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
#Kubek, what you need to do is subscribe to the observable.
What you should probably do is:
userAPI.getAllUser()
.subscribeOn(Schedulers.IO)
.observeOn(AndroidSchedulers.Main)
.subscribe(
// do some stuff
)
For documentation on how to use subscribe method, refer: http://reactivex.io/documentation/operators/subscribe.html

Custom xml converter with Retrofit 2.0.2 is never called

I have to use retrofit 2.0.2 with xml api response. But my custom xml converter is never called.
Playing around with this I found out:
if I use Volley to parse the same response, the same custom xml converter IS called;
if I apply GsonConverterFactory to my RestClient and parse json response, my custom JsonAdapter (#JsonAdapter(SomeAdapter.class)) IS called.
Anyone, how make my simple xml converter to be called? Am I doing something wrong, or retrofit 2.0.2 somehow doesn't support simple xml converter.
My java class where I parse response:
import org.simpleframework.xml.Element;
import org.simpleframework.xml.convert.Convert;
public class PassengerResponse {
#Element
#Convert(value = SomeConverter.class)
private String id;
}
Custom xml converter that is never called:
import org.simpleframework.xml.convert.Converter;
import org.simpleframework.xml.stream.InputNode;
import org.simpleframework.xml.stream.OutputNode;
public class SomeConverter implements Converter<String> {
#Override
public String read(InputNode node) throws Exception {
return null;
}
#Override
public void write(OutputNode node, String value) throws Exception {
}
}
My retrofit RestClient:
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.simplexml.SimpleXmlConverterFactory;
public class RestClient2 {
private UserApiJSON userPassengerApi;
private static final int TIMEOUT = 120000;
private static RestClient2 INSTANCE;
public static RestClient2 getInstance() {
if (INSTANCE == null) {
INSTANCE = new RestClient2();
}
return INSTANCE;
}
private RestClient2() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create())
.client(okHttpClient.newBuilder().connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(loggingInterceptor)
.build())
.build();
userPassengerApi = retrofit.create(UserApiJSON.class);
}
public UserApiJSON getUserPassengerApi() {
return userPassengerApi;
}
}
Actually SimpleXmlConverterFactory has different method to create its instance.) If all you need is to make your custom Converer(s) work, do the next:
Strategy strategy = new AnnotationStrategy();
Serializer serializer = new Persister(strategy);
Retrofit retrofit = new Retrofit.Builder().baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create(serializer))
.client(okHttpClient.newBuilder().connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(loggingInterceptor).build())
.build();
Note: if you add different converters, order does metter. Why? Watch Jake Wharton presentation.
To use your custom converter you have create custom Converter.Factory. And than add it to the retrofit using method addConverterFactory(). Below working example:
public class StringConverterFactory extends Converter.Factory {
public static StringConverterFactory create() {
return new StringConverterFactory();
}
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
if (String.class.equals(type)) {
return new Converter<ResponseBody, String>() {
#Override
public String convert(ResponseBody value) throws IOException {
return value.string();
}
};
}
return null;
}
}
And than add it retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(SimpleXmlConverterFactory.create())
.addConverterFactory(StringConverterFactory.create())
.client(okHttpClient.newBuilder().connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(loggingInterceptor)
.build())
.build();
In Retrofit 2 allows multiple converters. There is video by Jake Wharton who talks about Retrofit 2 and it features like a multiple converters.
Inside Retrofit class there is a method nextRequestBodyConverter which returns converter for appropriate Type
public UsStatesApi providesApi(){
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Strategy strategy = new AnnotationStrategy();
Serializer serializer = new Persister(strategy);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.connectTimeout(2, TimeUnit.MINUTES)
.writeTimeout(2, TimeUnit.MINUTES)
.readTimeout(2, TimeUnit.MINUTES)
.build();
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create(serializer))
.baseUrl("http://www.google.com")
.client(okHttpClient)
.build();
return retrofit.create( UsStatesApi.class);
}

Retrofit2.0 gets MalformedJsonException while the json seems correct?

I am using retrofit:2.0.0-beta4 for my android app.
I tried to add a user with Retrofit, the user is correctly created in Database, however I got the following error:
03-14 06:04:27.731 30572-30600/com.lehuo.lehuoandroid D/OkHttp: CALLING POST SP_User_CreateUser....your new user_id:48
{"data":{"user_id":"48","nickname":null,"password":null,"status":null},"status":1,"msg":"OK"}
03-14 06:04:27.731 30572-30600/com.lehuo.lehuoandroid D/OkHttp: <-- END HTTP (147-byte body)
03-14 06:04:27.732 30572-30600/com.lehuo.lehuoandroid E/My Jobs: error while executing job
com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $
at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1573)
at com.google.gson.stream.JsonReader.checkLenient(JsonReader.java:1423)
at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:587)
at com.google.gson.stream.JsonReader.peek(JsonReader.java:429)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:202)
at com.google.gson.TypeAdapter.fromJson(TypeAdapter.java:260)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:32)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:23)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:213)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:177)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:87)
at com.lehuo.lehuoandroid.async.NetworkJob.callNet(NetworkJob.java:30)
at com.lehuo.lehuoandroid.async.CreateUserJob.onRun(CreateUserJob.java:34)
at com.path.android.jobqueue.BaseJob.safeRun(BaseJob.java:108)
at com.path.android.jobqueue.JobHolder.safeRun(JobHolder.java:60)
at com.path.android.jobqueue.executor.JobConsumerExecutor$JobConsumer.run(JobConsumerExecutor.java:201)
at java.lang.Thread.run(Thread.java:818)
The returned result from server is :
{"data":{"user_id":"48","nickname":null,"password":null,"status":null},"status":1,"msg":"OK"}
This is correct json format, I don't understand why I get such exception?
Here us my interface:
public class ApiResult<T> {
public T data;
public int status;
public String msg;
}
public interface ApiUsers {
#POST("/users/new")
public Call<ApiResult<User>> createUser(#Body User user);
}
public class User {
public int user_id;
public String registration;
public int registration_type;
public String avatar;
public String nickname;
public String password;
public String status;
}
public class Api {
// TODO modify the value
public static final String BASE_URL = "xxx";
private static Api instance = new Api();
public static Api getInstance() {
return instance;
}
private Api(){}
public Retrofit getRetrofit() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.retryOnConnectionFailure(true)
.connectTimeout(15, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
public <S> S createService(Class<S> serviceClass) {
return getRetrofit().create(serviceClass);
}
}
The caller code is:
ApiUsers api = Api.getInstance().createService(ApiUsers.class);
Call<ApiResult<User>> call = api.createUser(user);
CreateUserMessage message = new CreateUserMessage();
callNet(call, message);
Could anyone give any clue?
Finally I solved my problem which is not related to the json lenient mode, something wrong with my POST response (there some other non json output before the json data).
Here is the response from JakeWharton regarding how to set Gson lenient mode:
make sure that you have:compile 'com.google.code.gson:gson:2.6.1'
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
I solved the problem
Gson gson = new GsonBuilder().setLenient().create();
OkHttpClient client = new OkHttpClient();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://kafe.netai.net/")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.google.code.gson:gson:2.7'
I solved my problem by removing extra HTML text and other white spaces from my JSON file.

Logging a Response using Retrofit 2

I need to log the response my server is sending after a call, because I am receiving a MalformedJsonException, to see what is going on.
I am using this code:
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor() {
#Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
com.squareup.okhttp.Response respuesta = chain.proceed(chain.request());
Log.i("David", "Response: "+respuesta.toString());
return response;
}
});
Retrofit builder = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
.client(client);
I have done this following this tutorial. I get an error in ".client(client); line: "client() in Retrofit cannot be applied to (com.squareup.okhttp.OkHttpClient)
What I am doing wrong? What do I need to do to intercept the response from the server, to see what's wrong with the JSON?
Thank you.
client(OkHttpClient) is a method of Retrofit.Builder() not of Retrofit. Change
Retrofit builder = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()
.client(client);
with
Retrofit builder = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build() ;

Retrofit 2.0 beta 1 with whole URL

In retrofit 2.0 i want to use only one url .The url is same as base url as that of #GET in interface.I am facing the problem for getting the response.If Any one have better solution for using the whole url in #GET then please suggest the solution.
here is the code
public class RestClient {
private static ApiInterface apiInterface ;
private static String baseUrl = "here is my whole base url";
public static ApiInterface getClient() {
if (apiInterface == null) {
OkHttpClient okClient = new OkHttpClient();
okClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
return response;
}
});
Retrofit client = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverter(String.class, new ToStringConverter())
.client(okClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
apiInterface = client.create(ApiInterface.class);
Log.e("RETROFIT RESPONCE IS...", client.toString());
}
return ApiInterface ;
}
public interface ApiInterface {
#Headers("User-Agent: Retrofit2.0Tutorial-App")
#GET("here is my whole base url”)
Call<EventResult> getEvent();
}
}
With retrofit 2 is possible to use the #Url annotation. Let's assume your Retrofit configuration is
Retrofit builder = new Retrofit.Builder()
.baseUrl("http://wwww.example.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
Test r = builder.create(Test.class);
you declare your interface:
public interface Test {
#GET
Call<Example> getTest(#Url String url);
}
and for getTest you don't want to use the baseUrl you declared in the configuration. The #Url will ignore the baseUrl you declared and will use the one you provide as argument
I don't think it's possible since BaseURL is mandatory in Retrofit Builder and even you supply the builder with the full URL the builder will parse it and save only the BaseURL. I guess the reason why they do this is to keep it simple and consistent.
for reference you can see the source code here

Categories

Resources