I'm having these lines of code
public class RetrofitClient {
private static Retrofit retrofit=null;
public static Retrofit getClient(String baseUrl)
{
if(retrofit==null)
{
retrofit = new Retrofit().Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
and i'm getting this error...
error: constructor Retrofit in class Retrofit cannot be applied to given types;
required: okhttp3.Call.Factory,HttpUrl,List,List,Executor,boolean
found: no arguments
reason: actual and formal argument lists differ in length
If i put my cursor on the error Retrofit i can see that it says
Retrofit(okhttp3.....)is not public in 'retrofit2.retrofit'.Cannot be accessed from outside package
Any help please?
You should be correct you code as below mentioned.
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient1(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Ok my bad... I should have used Retrofit.Builder() instead of Retrofit().Builder().
Related
I am trying to show this JSON in my app using retrofit by network calls.
Sample data:
{
total: 17727,
total_pages: 1773,
results: [
{
id: "qX9Ie7ieb1E",
created_at: "2016-01-26T08:17:45-05:00",
updated_at: "2018-05-18T13:04:07-04:00",
width: 4956,
height: 3304,
color: "#101617",
description: "Neon mural of woman wearing sunglasses and pink lipstick on brick wall in England",
urls: { raw: "", regular: "", full: "", small:"", thumb:""}
},
{}, {}, ...
]
}
I have created the interface like below:
public interface ApiService {
#GET("search/photos")
Call<ImagesResponse> getImages(
#Query("client_id") String clientId,
#Query("order_by") String orderBy,
#Query("query") String query,
#Query("page") int pageIndex
);
}
and the api:
public class UnsplashImageApi {
public static Retrofit retrofit = null;
private static OkHttpClient getOkHttpClient() {
return new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
}
public static Retrofit getRetrofitClient() {
if (retrofit != null) {
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpClient())
.baseUrl(Constants.UNSPLASH_BASE_URL)
.build();
}
return retrofit;
}
}
The model class is structured based on the response like below:
public class ImagesResponse {
#Expose
#SerializedName("total")
private Integer total;
#Expose
#SerializedName("total_pages")
private Integer totalPages;
#Expose
#SerializedName("results")
private List<Results> imagesList = new ArrayList<>();
Omitted getters and setters for brevity. The Results class is shown like this:
public class Results {
#Expose
#SerializedName("id")
public String imageId;
#Expose
#SerializedName("raw")
public String rawImg;
#Expose
#SerializedName("full")
public String fullImg;
#Expose
#SerializedName("regular")
public String regularImg;
#Expose
#SerializedName("small")
public String smallImg;
#Expose
#SerializedName("thumb")
public String thumbImg;
public boolean isFavorite;
In my fragment, I have tried calling the ApiService to load first page data like below:
apiService = UnsplashImageApi.getRetrofitClient().create(ApiService.class);
loadFirstPage();
but the app crashes on this line getRetrofitClient().create() with this error log:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object retrofit2.Retrofit.create(java.lang.Class)' on a null object reference
at com.jjoey.walpy.fragments.ArtFragment.onCreateView(ArtFragment.java:70)
at android.support.v4.app.Fragment.performCreateView(Fragment.java:2346)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1428)
at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
I have omitted the code to load the first page as it's not the source of concern here. Can anyone please explain to me why it's crashing and with a possible solution? Thanks
You have written that retrofit != null within the if condition.
public static Retrofit getRetrofitClient(){
if (retrofit != null) { // Check this line
return new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpClient())
.baseUrl(Constants.UNSPLASH_BASE_URL)
.build();
}
return retrofit;
}
You have to write retrofit == null within the if condition. Otherwise, Retrofit will not get initialized.
The very first-time Retrofit is null and you have checked retrofit != null then. That's why the code within the if condition bypassed and it's creating the Null Pointer Exception as you are calling create() method from a non-initialized instance of Retrofit.
Modified code will be:
public static Retrofit getRetrofitClient(){
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpClient())
.baseUrl(Constants.UNSPLASH_BASE_URL)
.build();
}
return retrofit;
}
You have a NPE because your singleton logic is incorrect. Adjusted version below:
public static Retrofit getRetrofitClient(){
if (null == retrofit){
retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpClient())
.baseUrl(Constants.UNSPLASH_BASE_URL)
.build();
}
return retrofit;
}
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.
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);
}
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.
I'm writting a retrofit demo.
I have to use "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code" to get code.
when writing rest, I do it like this:
public interface WXService {
#GET("/access_token?grant_type=authorization_code")
Observable<AccessTokenModel> getAccessToken(#Query("appid") String appId,
#Query("secret") String secretId,
#Query("code") String code);
}
public class WXRest {
private static final String WXBaseUrl = "https://api.weixin.qq.com/sns/oauth2/";
private WXService mWXService;
public WXRest() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(WXBaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
mWXService = retrofit.create(WXService.class);
}
public void getAccessToken(String code) {
mWXService.getAccessToken(Constants.APP_ID, Constants.SECRET_ID, code)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<AccessTokenModel>() {
#Override
public void call(AccessTokenModel accessTokenModel) {
Log.e("WX", "accessToken:" + accessTokenModel.accessToken);
}
});
}
}
but I got an error:
java.lang.IllegalArgumentException: Unable to create call adapter for
rx.Observable
I think it's the way i transform the url wrong.But I don't know how to fix it.
i think you should include adapter-rxjava lib to your gradle dependencies.
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
and then add call adapter factory to your retrofit builder
public WXRest() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(WXBaseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
mWXService = retrofit.create(WXService.class);
}