When I use the static Retrofit object the application crashing with the below log
I cannot use the retrofit object without static because i am using it too often. Please let me know the workaround for the same
W/WindowAnimator: Failed to dispatch window animation state change.
android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:513)
at android.view.IWindow$Stub$Proxy.onAnimationStopped(IWindow.java:548)
at com.android.server.wm.WindowAnimator.updateWindowsLocked(WindowAnimator.java:302)
at com.android.server.wm.WindowAnimator.animateLocked(WindowAnimator.java:694)
at com.android.server.wm.WindowAnimator.access$000(WindowAnimator.java:56)
at com.android.server.wm.WindowAnimator$1.doFrame(WindowAnimator.java:128)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:894)
at android.view.Choreographer.doCallbacks(Choreographer.java:698)
at android.view.Choreographer.doFrame(Choreographer.java:630)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:882)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.android.server.ServiceThread.run(ServiceThread.java:46)
Some Time i get this error too
Fail to sendHttpRequest
java.lang.IllegalArgumentException: HTTP entity may not be null
at org.apache.http.util.EntityUtils.toString(EntityUtils.java:115)
at org.apache.http.util.EntityUtils.toString(EntityUtils.java:151)
at miui.util.ErrorReport.c(SourceFile:396)
at miui.util.ErrorReport.sendReportRequest(SourceFile:353)
at miui.util.ErrorReport$1.a(SourceFile:369)
at miui.util.ErrorReport$1.doInBackground(SourceFile:366)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
Here is the retrofit object which is working fine
public static Retrofit getAPIClient(Context context) {
return new Retrofit.Builder()
.baseUrl(context.getString(R.string.base_url))
.client(getOkHttpClient(context))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(getGson()))
.build();
}
But when I converted this to static it is crashing
if ( appApiClient == null ) {
appApiClient = new Retrofit.Builder()
.baseUrl( context.getString( R.string.base_url ) )
.client( getOkHttpClient( context)
.addCallAdapterFactory( RxJavaCallAdapterFactory.create() )
.addConverterFactory( GsonConverterFactory.create( getGson() ) )
.build();
}
return appApiClient ;
public class RetroFitServiceGenerator {
MySharedPreferences sharedPreferences;
public static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static Retrofit retrofit = builder.build();
public static HttpLoggingInterceptor logging = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
private static Context context;
private OkHttpClient.Builder httpClient =
new OkHttpClient.Builder();
public RetroFitServiceGenerator(Context context) {
this.context = context;
}
public <S> S serviceNOAuth(
Class<S> serviceClass) {
httpClient.addInterceptor(logging);
builder.client(httpClient.build());
retrofit = builder.build();
return retrofit.create(serviceClass);
}
}
Now you can modify or add Services based on your requirement like cache or authentication
and in your Class you just need to call :
RetrofitAPI service = new RetroFitServiceGenerator(context).serviceNOAuth(RetrofitAPI.class);
Related
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().
I have searched everywhere and the tutorials I've seen don't match the documentation given by Retrofit. I think this is a stupid question, as I haven't been able to find an answer for it. I'm brand new at Android programming.
I'm following Codepath's guide and am at the part where it says:
Creating the Retrofit instance
To send out network requests to an API, we need to use the [Retrofit
builder] class and specify the base URL for the service.
// Trailing slash is needed
public static final String BASE_URL = "http://api.myservice.com/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
I have no idea which class to put this in. Or do I create a new class for it?
Jonathan has given you plenty of code but I think your question is more of the entry level "How do I use it?" questions, right?
So basically the code you've posted creates a Retrofit instance. It's an object capable of creating api interface objects. One Retrofit object handles one base url.
You define api endpoints and expected responses by creating interfaces. Using examples from the website:
Endpoint interface
public interface GitHubService {
#GET("users/{user}/repos")
Call<List<Repo>> listRepos(#Path("user") String user);
}
Then, using the Retrofit instance you created, you can instantiate an implementation of this interface by calling
GitHubService service = retrofit.create(GitHubService.class);
and the simply send requests to the api by calling
Call<List<Repo>> repos = service.listRepos("octocat");
repos.enqueue(callback) //add a callback where you can handle the response
The example posted by Jonathan uses RxJava call adapter, but you should skip that part for now to make it easier for yourself.
EDIT: adding an example requested in the comments.
for this api endpoint --> https://api.textgears.com/check.php?text=I+is+an+engeneer!&key=DEMO_KEY
you need
#GET("check.php")
Call<YourResponseClass> performCheck(#Query("text") String text, #Query("key") apiKey);
This is also an interesting case as you most certainly need to add the apiKey to every request. But it's not a good practice to manually add it as a parameter every single time. There is a solution - Interceptor.
public class ApiKeyRequestInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
final HttpUrl newUrl = request.url().newBuilder()
.addQueryParameter(Constants.API.PARAM_API_KEY, BuildConfig.NEWS_API_KEY) //add your api key here
.build();
return chain.proceed(request.newBuilder()
.url(newUrl)
.build());
}
}
and tell Retrofit to use it (build an OkHttpClient)
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new ApiKeyRequestInterceptor())
.build();
Retrofit = new Retrofit.Builder()
.baseUrl(Constants.API.BASE_URL)
.client(client)
.build();
In this case you don't need an extra field for your key, and you can reduce your method to
Call<YourResponseClass> performCheck(#Query("text") String text);
You can create a Controller to handle the requests.
public class RequestController {
private final static String BASE_URL_CLUB = "url";
private static RequestApiEndpoints apiServiceAsync;
private static RequestController instance;
private static final int TIMEOUT_MILLIS = 10000;
private static final TimeUnit TIMEOUT_UNIT = TimeUnit.MILLISECONDS;
private Context context;
private RequestController(Context context) {
this.context = context;
RxJavaCallAdapterFactory rxAdapter = RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io());
Retrofit retrofitAsync = new Retrofit.Builder()
.baseUrl(BASE_URL_CLUB)
.client(createDefaultOkHttpClient())
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(rxAdapter)
.build();
apiServiceAsync = retrofitAsync.create(RequestApiEndpoints.class);
}
private OkHttpClient createDefaultOkHttpClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return new OkHttpClient().newBuilder()
.cache(new Cache(context.getCacheDir(), 10 * 1024 * 1024)) // 10 MB
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (Utils.hasInternet(context)) {
request = request.newBuilder().header("Cache-Control", "public, max-age=" + 60).build();
} else {
request = request.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + 60 * 60 * 24).build();
}
return chain.proceed(request);
}
})
.connectTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT)
.readTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT)
.writeTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT)
.addInterceptor(interceptor)
.build();
}
public static RequestController getInstance(Context context) {
if (instance == null) {
instance = new RequestController(context);
}
return instance;
}
public Observable<ResponseObject> getExampleInfo(String param) {
return apiServiceAsync.getExampleInfo(param).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
}
Then your interface:
public interface RequestApiEndpoints {
#GET("path/to/request") //without the base url
Observable<ResponseObject> getExampleInfo(#Query("param") String param);
}
Then on your Application class:
public class MyApplication extends Application {
...
public static RequestController requestController;
...
#Override
public void onCreate() {
super.onCreate();
requestController = RequestController.getInstance(this);
...
}
public static FPDApplication getInstance() {
if (instance == null) {
instance = new FPDApplication();
}
return instance;
}
}
Then to access to your RequestController just do the follow:
MyApplication.requestController.getExampleInfo(string);
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.