I have an issue trying to use Okhttp with retrofit. I seem not to understand what I am doing wrong.
It gives showing up error: 'Anonymous class derived from Callback' must either be declared abstract or implement abstract method 'onResponse(Response<T>, Retrofit)' in 'Callback'
In my MainActivity I have this:
OkHttpClient httpClient = new OkHttpClient();
httpClient.interceptors().add(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("User-Agent", "Your-App-Name")
.header("Content-Type", "application/json")
.header("Authorization","authorization_code")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient)
.build();
TestInterface service = retrofit.create(TestInterface.class);
Call<TestData> call = service.getPost();
/* It keeps pointing at this line below:
'Callback' must either be declared abstract" */
call.enqueue(new Callback<TestData>() {
#Override
public void onResponse(Response<TestData> response, Retrofit retrofit) {
// Get result Repo from response.body()
// response.isSuccess() is true if the response code is 2xx
int statusCode = response.code();
if (response.isSuccess()) {
System.out.println("Success: ");
} else {
}
}
#Override
public void onFailure(Throwable t) {
System.out.println("failed: "+t);
}
});
In my TestData Interface,I have this
public interface TestInterface {
#POST("/paths_to_web_directory")
Call<TestData>
getPost();
}
This is the way i see it done in other examples, So maybe i'm implementing it the wrong way. Kindly correct me. Thanks
The retrofit github project has a sample with a different method signature. Try this:
call.enqueue(new Callback<TestData>() {
#Override public void onResponse(Call<TestData> call, Response<TestData> response) {
}
#Override public void onFailure(Call<TestData> call, Throwable t) {
}
});
Related
I'm using retrofit to connect APIs. It is working fine when fetching data from https API but getting response "Null" and error body response "okhttp3.ResponseBody$1#174390c" when fetching data from http API.
Here is the Retrofit client class:
public static Retrofit getSClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(ScalarsConverterFactory.create())
.build();
}
return retrofit;
}
Here is the Apiservice Class:
#GET("Mobile/OperatorFetch?")
Call<String>getOperatorDetails(#Query("apimember_id")String apiMemberId,
#Query("api_password")String apiPassword,
#Query("Mobileno")String mobileNumber);
Here is the ApiUtils Class:
public static ApiService getSApiService(){
return RetrofitClient.getSClient(PLAN_URL).create(ApiService.class);
}
Here is my network request method from Repository class:
private void fetchOperator(String apiId, String apiPassword, String mobile) {
ApiService apiService = ApiUtills.getSApiService();
apiService.getOperatorDetails(apiId, apiPassword, mobile)
.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful() && response.body() != null){
Log.e(TAG,"Operator fetch successful: " + response.body().toString());
}else {
Log.e(TAG,"Operator fetch failed: " + response.errorBody().toString());
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.e(TAG,"Fetch operator failed" + t.getMessage());
}
});
}
Getting response from Post Man
I have the following situation: my program downloads data from server and after adds it to ArrayList.
static List<Film> generateFilms(){
Log.i(Tag, "In generate films");
List <Film> films = new ArrayList<>();
String BaseUrl = "http://www.omdbapi.com/";
Retrofit.Builder builder = new Retrofit.Builder().baseUrl(BaseUrl)
.addConverterFactory(GsonConverterFactory.create());
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS);
httpClient.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "auth-value");
Request request = requestBuilder.build();
return chain.proceed(request);
});
Retrofit retrofit = builder.build();
APIService apiService = retrofit.create(APIService.class);
final Call<Film> filmsCall = apiService.getFilms();
filmsCall.enqueue(new Callback<Film>() {
#Override
public void onResponse(#NonNull Call<Film> call, #NonNull Response<Film> response) {
if (response.isSuccessful()){
Film film = response.body();
films.add(film);
Log.i(Tag, "Response: "+Objects.requireNonNull(response.body()).getTitle());
}
else {
Log.i(Tag, "Response code: "+response.code());
}
}
#Override
public void onFailure(#NonNull Call<Film> call, #NonNull Throwable t) {
Log.i(getClass().getSimpleName(), "Error: "+t);
}
});
Log.i(Tag, "Size = "+films.size());
return films;
}
But it does it in a strange manner: it firstly returns an array and then gets the data (as I see from logs). Here's the logs:
2019-04-01 22:00:06.766 4974-4974/asus.example.com.exercise5 I/DataUtil: In generate films
2019-04-01 22:00:06.889 4974-4974/asus.example.com.exercise5 I/DataUtil: Size = 0
2019-04-01 22:00:07.367 4974-4974/asus.example.com.exercise5 I/DataUtil: Response: Batman
So, how can I solve this problem, as I need to get data firstly and then return the array?
Call<T>.enqueu() acts in asynchronous way, so you can't return data from generateFilms method itself but only make all required actions in onResponse or create custom callback.
Sample:
interface OnLoaded {
void onLoaded(Film film);
}
void generateFilms(OnLoaded callback) {
...
filmsCall.enqueue(new Callback<Film>() {
#Override
public void onResponse(#NonNull Call<Film> call, #NonNull Response<Film> response) {
if (response.isSuccessful()){
Film film = response.body();
mFilms.add(film);
Log.i(Tag, "Response: "+Objects.requireNonNull(response.body()).getTitle());
callback.onLoaded(film);
}
else {
Log.i(Tag, "Response code: "+response.code());
}
}
And use it:
private List<Film> mFilms = new ArrayList<Film>(); // class-level field
generateFilms(new OnLoaded() {
#Override
public void onLoaded(Film film) {
mFilms.add(film);
// do actions with film or mFilms if you need
}
}
In my application, I connect to a server and have to get a successful response to my further working, after such type of response, in general, I get two tokens ( access+refresh). For my further actions, I have to use my access token because I won't be able to get data. This token, in general, expires in 30 minutes. I can't understand how I can get a new token from the server without fails of my application. I had seen some questions and this Refreshing OAuth token using Retrofit without modifying all calls one was the best I think. But I can't understand the way of using it for me.
Right now I am using such an interface:
public interface APIService {
#Headers("Content-type: application/json")
#POST("/v1/login")
Call<Post> auth(#Body Post body);
#Headers({"Content-type: application/json",
"Authorization: Bearer access_token"})
#GET("/v1/message/list")
Call<Message> getInMess(#Query("type") int type, #Query("offset") int offset);
}
there I have to insert my access token by hands.
And then in my MainActivity Class I initialize my interface:
public void sendPost()
{
final EditText titleEt = findViewById(R.id.login);
final EditText bodyEt = findViewById(R.id.password);
final String a = titleEt.getText().toString().trim();
final String b = bodyEt.getText().toString().trim();
saveData();
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://server/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
APIService mAPIService = retrofit.create(APIService.class);
//retrofit.create(APIService.class);
mAPIService.auth(new Post(a, b)).enqueue(new Callback<Post>() {
#Override
public void onResponse(#NonNull Call<Post> call, #NonNull Response<Post> response) {
if (response.isSuccessful()) {
Toast.makeText(LoginActivity.this, "Post submitted to API.", Toast.LENGTH_LONG).show();
Intent intent = new Intent(LoginActivity.this, SecondScreen.class);
findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#1cd000"), PorterDuff.Mode.MULTIPLY);
startActivity(intent);
} else {
Toast.makeText(LoginActivity.this, "Unable to submit post to API.Error!!!", Toast.LENGTH_LONG).show();
findViewById(R.id.btn_submit).getBackground().setColorFilter(Color.parseColor("#FF0000"), PorterDuff.Mode.MULTIPLY);
}
}
#Override
public void onFailure(#NonNull Call<Post> call, #NonNull Throwable t) {
Toast.makeText(LoginActivity.this, "Unable to submit post to API.", Toast.LENGTH_LONG).show();
}
});
}
Please help me to understand the strategy of my further development because I can't solve my problem.
P.S. Sorry for my bad English))
You need to intercept the request and add the header in your interceptor. I use this in my applications :
public class AuthenticationInterceptor implements Interceptor {
public AuthenticationInterceptor(Context context) {
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if(!YOUR_TOKEN.isEmpty()) {
Request authenticatedRequest = request.newBuilder().header("Authorization", "Bearer:" + YOUR_TOKEN).build();
return chain.proceed(authenticatedRequest);
}
return chain.proceed(request);
}
}
I have this Interface:
public interface InterfazAguaHttp {
#FormUrlEncoded
#POST("/")
Call<String> saveContador(#Field("contador") Long contador, Callback<String> callBack);
}
The rest of the code is this:
Retrofit builder = new Retrofit.Builder()
.baseUrl(ValoresGlobales.urlServlet)
.addConverterFactory(GsonConverterFactory.create())
.build();
InterfazAguaHttp interfaz = builder.create(InterfazAguaHttp.class);
Call<String> respuesta = interfaz.saveContador(93847597L, new Callback<String>() {
#Override
public void onResponse(Response<String> response, Retrofit retrofit) {
//Some logging
}
#Override
public void onFailure(Throwable t) {
//Some logging
}
});
This is all inside a try-catch block. In the catch, I am receiving this error:
Error: No Retrofit annotation found. (parameter #2) for method InterfazAguaHttp.saveContador
How could I get rid of this error, and still have my callback?
Thank you.
change your interface method to this
public interface InterfazAguaHttp {
#FormUrlEncoded
#POST("/")
Call<String> saveContador(#Field("contador") Long contador);
}
and the rest of the code like this
Retrofit builder = new Retrofit.Builder()
.baseUrl(ValoresGlobales.urlServlet)
.addConverterFactory(GsonConverterFactory.create())
.build();
InterfazAguaHttp interfaz = builder.create(InterfazAguaHttp.class);
Call<String> respuesta = interfaz.saveContador(93847597L);
respuesta.enqueue(new Callback<String>() {
#Override
public void onResponse(Response<String> response, Retrofit retrofit) {
//Some logging
}
#Override
public void onFailure(Throwable t) {
//Some logging
}
});
Link for reference
I am not able to get success response status code from response like 200,201.. etc. As we can easily get error codes from RetrofitError class like error.isNetworkError() and error.getResponse().getStatus(). Is there any workaround for getting status codes?
As per Retrofit 2.0.2, the call is now
#Override
public void onResponse(Call<YourModel> call, Response<YourModel> response) {
if (response.code() == 200) {
// Do awesome stuff
} else {
// Handle other response codes
}
}
Hope it helps someone :-)
EDIT: Many apps could also benefit from just checking for success (response code 200-300) in one clause, and then handling errors in other clauses, as 201 (Created) and 202 (Accepted) would probably lead to the same app logic as 200 in most cases.
#Override
public void onResponse(Call<YourModel> call, Response<YourModel> response) {
if (response.isSuccessful()) {
// Do awesome stuff
} else if (response.code() == 401) {
// Handle unauthorized
} else {
// Handle other responses
}
}
You can get the status code in success() just like you do it in failure()
#Override
public void success(Object object, Response response) {
response.getStatus() // returns status code integer
}
Since you have a Response object in success callback as response.getStatus()
EDIT
I assume you are using okhttp with retrofit.
okhttp has a powerful tool called Interceptor
You can catch the response before retrofits Callback and get status code from the response:
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor(){
#Override
public Response intercept(Chain chain) throws IOException{
Request request = chain.request();
Response response = chain.proceed(request);
response.code()//status code
return response;
});
// then add it to you Restclient like this:
restAdapter = new RestAdapter.Builder()
.setEndpoint(URL_SERVER_ROOT)
.setClient(new OkClient(client)) //plus your configurations
.build();
To learn more about interceptors visit here.
i achieved it by following codes:
public abstract class BaseCallBack<T> {
public abstract void onSuccess(Response<T> response);
public abstract void onFailure(Response<T> response);
}
public abstract class SuccessCallback<T> extends BaseCallBack<T> implements Callback<T>{
#Override
public void onResponse(Call<T> call, Response<T> response) {
if(response.code()>= 400 && response.code() < 599){
onFailure(response);
}
else {
onSuccess(response);
}
}
#Override
public void onFailure(Call<T> call, Throwable t){
}
#Override
public void onSuccess(Response<T> response) {
}
#Override
public void onFailure(Response<T> response) {
}
}
When the rest api returns 400 etc then the onFailure method will be call by default. If you wanna do something onsuccess:(when returns 200 etc)
ServiceConnector.api.getHomePage().enqueue(new SuccessCallback<Void>() {
#Override
public void onSuccess(Response<Void> response) {
super.onSuccess(response);
}
});
you should get exception code iin onError response
HttpException httpException =((HttpException) e).code();