Retrofit2 response body is null - android

I built a Retrofit2 to get a request from https, I have also built a log interceptor with OKHttpClient, the log show the correct result from http get, but response.body() from retrofit is empty, how should I to solve the problem?
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String message) {
//打印retrofit日志
Log.i("RetrofitLog","retrofitBack = "+message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(loggingInterceptor)
.build();
Retrofit retrofit = new Retrofit.Builder().client(client).baseUrl(Constant.baseURL).addConverterFactory(GsonConverterFactory.create()).build();
BannerService bannerService = retrofit.create(BannerService.class);
Call<JSONObject> bannerResult = bannerService.getBannerList(5);
bannerResult.enqueue(new Callback<JSONObject>()
{
#Override
public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {
if (response.isSuccessful()) {
System.out.println("----------------------\t"+response.body());
} else {
// error response, no access to resource?
}
}
#Override
public void onFailure(Call<JSONObject> call, Throwable t) {
}
});
the final interceptor log result is as following:
>
I/RetrofitLog: retrofitBack = Content-Type: application/json;charset=UTF-8
I/RetrofitLog: retrofitBack = Content-Length: 1515
retrofitBack = Connection: keep-alive
retrofitBack = Cache-Control: must-revalidate, no-store
retrofitBack = Last-Modified: Fri, 15 Jun 2018 03:00:00 GMT
retrofitBack = Pragma: no-cache
retrofitBack = X-XSS-Protection: 1; mode=block
retrofitBack = X-Frame-Options: DENY
retrofitBack = X-Content-Type-Options: nosniff
retrofitBack = X-Daa-Tunnel: hop_count=2
retrofitBack = X-NWS-LOG-UUID: 0756741f-5bc5-44ba-9b3e-82dd08ae6f95
retrofitBack = X-Cache-Lookup: Hit From Upstream
........
>
> ----------------//here is the correct out------------------
>
>
> I/RetrofitLog: retrofitBack = {"resultModel":[{"banner_id":3,"banner_title":"拾光cafe","banner_description":"合肥工业大学校内的咖啡厅,方便实惠","banner_image_name":"84c61eca-ac3c-4fa3-8146-43cce52aebc3.jpg","banner_create_time":"2018-05-31 12:54:47","banner_creater_id":1000000,"banner_href":"1000000807","enabled":1},{"banner_id":100003,"banner_title":"合肥悦方IDMall · 永辉超市","banner_description":"一个永远都有试吃的超市","banner_image_name":"fe154125-3752-4842-907d-203e45ae51ad.jpg","banner_create_time":"2018-03-26 16:33:45","banner_creater_id":100000000,"banner_href":"http","enabled":1},{"banner_id":100002,"banner_title":"斛兵塘","banner_description":"距今已有一千七百多年历史的一个水塘","banner_image_name":"b4f1281c-e43d-4a69-903f-5e1eb3505938.jpg","banner_create_time":"2018-03-26 16:13:13","banner_creater_id":100000000,"banner_href":"http","enabled":1},{"banner_id":100001,"banner_title":"合肥天鹅湖","banner_description":"一个形状神似天鹅的人工湖","banner_image_name":"1c796d8d-b868-4590-ae0e-d0599ad462cf.jpg","banner_create_time":"2018-03-26 16:10:32","banner_creater_id":100000000,"banner_href":"http","enabled":1},{"banner_id":100000,"banner_title":"合肥工业大学","banner_description":"一个食堂上央视的高校","banner_image_name":"92361818-2daf-45db-9294-d36241fd243b.jpg","banner_create_time":"2018-03-22 10:05:21","banner_creater_id":1000000,"banner_href":"1000000241","enabled":1}],"resultCode":200,"resultMessage":"请求成功"}
>
>
>> ----------------//here is the correct out------------------
>
>
> .........
>
>
>
I/System.out: ---------------------- {} //here is my system.out is empty
>
>
>
> I/Choreographer: Skipped 253 frames! The application may be doing too much work on its main thread.

Your are mixing up concepts. First you are passing a GsonConverter:
Retrofit retrofit = new Retrofit.Builder().client(client).baseUrl(Constant.baseURL).addConverterFactory(GsonConverterFactory.create()).build();
But then your are expecting a JSONObject:
Call<JSONObject> bannerResult = bannerService.getBannerList(5);
When passing a GsonConverter Retrofit is converting into Gson and not JSONObject. That means you should declare your own Java pojo with the proper Gson annotations. Example:
import com.google.gson.annotations.Expose;
public class Banner {
#Expose
public String oneField
#Expose
public String otherField;
}
As you are expecting a List you sould change your BannerService:
public interface BannerService {
#GET("/your/path/to/get/banner/list")
Call<List<Banner>> getBannerList(#Path("id") int id);
}
And finally change your line to receive the List...
Call<List<Banner>> bannerResult = bannerService.getBannerList(5);
and replace your Callback instantiation and methods to receive the List where you where expecting a JSONObject.

Related

Retrofit - Download csv file from server in android

I am trying to download a file from server using retrofit. Using HttpLoggingInterceptor I tried logging what is happening. I can find the file name. But the response body is empty.
I am new to using retrofit. can some one point me out in the right direction on where I am going wrong
Retrofit Client Interface:
public interface DownloadTransactions {
#Streaming
#GET("common/frontend/member/download.aspx")
Call<Void> getBalancesAndTransactions(#Header("Cookie") String header);
}
Java call:
void downloadData() {
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS);
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
client.addInterceptor(logging);
}
Retrofit.Builder builder = new Retrofit.Builder();
Retrofit retrofit = builder.client(client.build())
.baseUrl("https://" + getString(R.string.root_url))
.addConverterFactory(ScalarsConverterFactory.create())
.build();
DownloadTransactions downloadTransactions = retrofit.create(DownloadTransactions.class);
Call<Void> call = downloadTransactions.getBalancesAndTransactions(CommsManager.getInstance().getASPSessionId());
call.enqueue(new Callback<Void>() {
#Override
public void onResponse(Call<Void> call, retrofit2.Response<Void> response) {
Log.v(TAG, "success transactions: --------" + response);
}
#Override
public void onFailure(Call<Void> call, Throwable t) {
Log.v(TAG, "failure transactions: --------");
}
});
}
Response in log:
<-- 200 OK https://xxxxx.com/common/xxx/member/download.aspx (387ms)
D/OkHttp: Cache-Control: private
D/OkHttp: Content-Type: text/csv; charset=utf-16
D/OkHttp: Server: Microsoft-IIS/8.5
D/OkHttp: Content-Disposition: attachment; filename=Account_Summary_8978_04062018_142921.csv
D/OkHttp: X-AspNet-Version: 4.0.30319
D/OkHttp: X-Powered-By: ASP.NET
D/OkHttp: Date: Mon, 04 Jun 2018 13:29:21 GMT
D/OkHttp: Connection: keep-alive
D/OkHttp: Content-Length: 446900
D/OkHttp: Set-Cookie: xxx; path=/; Httponly; Secure
D/OkHttp: <-- END HTTP (binary 446900-byte body omitted)
D/Accounts Overview: success transactions: --------
Response{protocol=http/1.1, code=200, message=OK, url=xxx}
But the response body is empty.
Retrofit determines the type of response with the return type of the methods defined in your API interface.
The return type of getBalancesAndTransactionsis Void which means nothing.
Solution : Define your customise POJO class and replace Void with `POJO
or Just for testing purpose, you can use Object which can handle any type of response but you will have to use casting for specific operation
e.g
#Streaming
#GET("common/frontend/member/download.aspx")
Call<Object> getBalancesAndTransactions(#Header("Cookie") String header);
References :
How can we handle different response type with Retrofit 2?
Using Retrofit in Android

Retrofit Bearer token

I try to receive token via POST json {"email":"test#example.com","password":"test"}. In postman it works:
Postman request.
I try do the same in Android Studio.
I create class Token:
public class Token {
#SerializedName("token")
#Expose
public String token;
}
And class APIclient
class APIClient {
private static Retrofit retrofit = null;
static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("http://mybaseurl.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
and interface APIInterface:
interface APIInterface {
#POST("/authenticate")
Call<Token> getLoginResponse(#Body AuthenticationRequest request);
}
and class AuthenticationRequest:
public class AuthenticationRequest {
String email;
String password;
}
In onCreate in MainActivity:
apiInterface = APIClient.getClient().create(APIInterface.class);
authenticationRequest.email="test#example.com";
authenticationRequest.password="test";
getTokenResponse();
And here is my getTokenResponse method:
private void getTokenResponse() {
Call<Token> call2 = apiInterface.getLoginResponse(authenticationRequest);
call2.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
Token token = response.body();
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
call.cancel();
}
});
}
And this is what I see in Logcat:
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: --> POST http://mybaseurl.com/authenticate http/1.1
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: Content-Type: application/json; charset=UTF-8
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: Content-Length: 46
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: {"email":"test#example.com","password":"test"}
03-15 10:53:56.579 20734-20756/com.retrofi2test D/OkHttp: --> END POST (46-byte body)
Could you tell me what I'm doing wrong? I need to give token every time when I'd like to get information from server via GET method.
How can I receive and save token in Android code?
Try this
interface APIInterface {
#POST("/authenticate")
Call<Token> getLoginResponse(#Header("Authorization") String token, #Body AuthenticationRequest request);
}
token is the Bearer token
you should add application/json to header
interface APIInterface {
#Headers({"Content-Type: application/json", "Accept: application/json"})
#POST("/authenticate")
Call<Token> getLoginResponse(#Body AuthenticationRequest request);
}
To get access token from you need to get header from response and read values from headers.
Callback<User> user = new Callback<User>() {
#Override
public void success(User user, Response response) {
List<Header> headerList = response.getHeaders();
//iterating list of header and printing key/value.
for(Header header : headerList) {
Log.d(TAG, header.getName() + " " + header.getValue());
}
}
}
After you get the value you need from header i.e. AccessToken, you can store that value in Storage. e.g. SharedPreference
So next time when you need that value you can directly get that from Storage. e.g. SharedPreference
Now when you pass request for any webservice either that is GET or POST or any other method. You have to pass that into header requests.
#GET("/tasks")
Call<List<Task>> getTasks(#Header("Content-Range") String contentRange);
Or If you need to pass it every time, you can directly pass that from your Retrofit class.
Request request = original.newBuilder()
.header("User-Agent", "Your-App-Name")
.header("Accept", "application/vnd.yourapi.v1.full+json")
.method(original.method(), original.body())
.build();

Retrofit gets 400 Bad request but works with postman

My api base url is:
https://locodealapi.herokuapp.com/api/deals
In postman pass following in header and it works fine.
x-access-token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VyX25hbWUiOiJkZWFsQWRtaW4iLCJ1c2VyX3Bhc3N3b3JkIjoiY2U5MDZkNDkzMWY3NmFhZWFmZTViNjM0YTg3Y2RkYzQ4YjMzNmUzYmVlZDU1N2ZhZTI0YzMxZTY3YmQyN2NhZDg4NDJmNzJlNTJlNGUyODc5ZWVkODY1MDljYzY5ODJlNDYwMjU0Mzk4ODQzMTljMTQxMGMwOTcxNGU0Y2MxMDNiMDQwYjkwOTQ1OTMyMjYwMGI1MjgwMmRkOTc2YTE4OGE5MTZiMWU4ZmU1YmY1ZWZiNTlkYjc2NDhmMjQxOTg0ODdiMWE5OGVhMjg2ZWZjZDI1M2Y5ZWUxNTQ0OTI3ODZiYjY3NzNmZTZjNGY3ODhmNzJjMzQ0NTEwMzg2NjkyNzIzMjNiMjZmYjFhMmUzYjE0ZTQ0Nzc0NzljMTExMzNkZjIwMmE3ODY2OGIxZjdiY2NlZjQ5NTM0YTJhYzk5N2Y0MTc0NzU2OTkwOTg5NjQ1YzljNWQxYTZkYmUyZTI1ZjFlNDE3YjdhYWI1N2QyZGJhNmVmOWEwNzk5N2Q5ZDcyNTgxMzUyYzc4Y2IxY2RiMDRmNDFkZjMwNzdjYzAxMGM2YmYzYWMzOTQ5OTJjN2Y3ZGVmYmE3YzllZWMxMzI5ODhlODBiM2RmYWE5NTVhMzE3NTgxNThiZjYxYjYyN2U4Y2UzOTg2NmRkODk2YzBlZDkzNDJlMzhiMzhkM2Q0ZTY0YWIzZWIwNGU4YmU5MGQwNmM2NTg2OWYyNzZkMzgyOTU3MTFkODgyNjI4NGIxMjkzYzQ0ZGNjMWM3ZjU2YmE4OGM5MTkyNDMzZWY0YTcwZGE2NTkzMzAwZmUzMGMxYjkwOWY5YmJjMDhmY2M5Zjk3NjUwYmJkOTVhNzExNWVlOGY3MjI5N2Q4ZGY4MjZiMTk0MTBlZjQ0OWZkMTQ1NTg3Nzc2NjUxZDI5OGMyYzMwMTZiMDMxMGEwZjRlMWQ4NzgwZTExYmVkOTZhYzg3MDU2YzIwYWU4ODZiYjI3NGZkNGVhZGMzMjQ0ZjlmMmZkMGIyMGMzZTAyZjI1NGQ3OWYzYzhiM2FmZGJiM2UzYTM1YTA2MjNjMTQwY2JmNzMxZWMxYjE2Y2VmNmIwY2RhMjQ1YjkzZmY4NzQ1MGRjNWFhZDE2MzdkNTQ5ZjM5ZDkwZjk5MWFiNWMxNTcwNWExYWJjYWQxYzQyYjNmMTViN2Y5N2I0YTc1ZDA2YTgwYjkwOWI0ZDJlZjRiNWE0NzdhMTMzYWI0ODkwMmIyNWFiM2VmYTMzNDdjMDcxODQ4NmMwYmU2NGQxYzUxMjA1ZTMwYjU5NjY3Yjk5ZTVlYTdkZWNiMWE4MWRkNjcyYzEwMzU5YmM2NGNlZWI3ZTEyOWJlYjZjYWUzYTM0ZjM0M2NiYjk4NyIsImNyZWF0ZXRpbWUiOm51bGwsImZpcnN0X25hbWUiOm51bGwsImxhc3RfbmFtZSI6bnVsbCwiYWdlIjpudWxsLCJzZXgiOm51bGwsImRvYiI6bnVsbCwic3RhdHVzIjpudWxsLCJpdGVyYXRpb24iOjEwMDAwLCJ1c2VyX3R5cGUiOiIwIiwidXNlcl9pbWFnZSI6bnVsbCwic2FsdCI6Ikh1dm9VQ3FRak81Mi9BbkJIdmp2MldEMERod2JmM0R4ZXV6ZWJMSlFYK3hZTUptMmRJSUw3VFYvcnFVVXFVNUpmRlY0dHhkMHNCcXhLbnVNakU2YlNzVnpaQ0dWVXg3YmY4MGNubTR5WnB5OElEUWowY1crTXhCUXdvMFNja2UzT0FnVk4zd2pnNmlxSVk3VnJwRmw1WTNLRzFwY1NMelZjREJiME9XdXdjcz0iLCJpYXQiOjE1MTAxMjY1OTUsImV4cCI6MTUxODc2NjU5NX0.5XFJnJqTsfID9uqOwkNf46oraj9jDxic7qNSqBdunD0
In retrofit Interface I have following but get 400 Bad request
#POST("api/deals")
Call<ResponseBody> deals(#Header("x-access-token") String x_access_token)
Calling code:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://locodealapi.herokuapp.com")
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build())
.build();
AppRestAPI client = retrofit.create(AppRestAPI.class);
Call<ResponseBody> call1 = client.deals(
token
);
call1.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
Log.i(TAG, "The response is " + response.message());
Log.i(TAG, "The response is " + response.body());
try {
Log.i(TAG, "The response is " + response.errorBody().string());
if (response.code() == 400) {
Log.v("Error code 400",response.errorBody().string());
}
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e(TAG, "onFailure: Failed", t);
}
});
OKHTTP Log interceptor
11-21 21:14:30.939 3253-3342/? D/OkHttp: --> POST https://locodealapi.herokuapp.com/api/deals
11-21 21:14:30.939 3253-3342/? D/OkHttp: Content-Length: 0
11-21 21:14:30.940 3253-3342/? D/OkHttp: x-access-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyNSwidXNlcl9uYW1lIj....
11-21 21:14:30.942 3253-3342/? D/OkHttp: --> END POST (0-byte body)
11-21 21:14:34.188 3253-3342/? D/OkHttp: <-- 400 Bad Request https://locodealapi.herokuapp.com/api/deals (3246ms)
11-21 21:14:34.189 3253-3342/? D/OkHttp: Connection: close
11-21 21:14:34.189 3253-3342/? D/OkHttp: Server: Cowboy
11-21 21:14:34.189 3253-3342/? D/OkHttp: Date: Tue, 21 Nov 2017 15:29:33 GMT
11-21 21:14:34.190 3253-3342/? D/OkHttp: Content-Length: 0
11-21 21:14:34.191 3253-3342/? D/OkHttp: <-- END HTTP (0-byte body)
11-21 21:14:34.196 3253-3253/? I/BaseDrawerActivity: The response is Bad Request
11-21 21:14:34.196 3253-3253/? I/BaseDrawerActivity: The response is null
11-21 21:14:34.196 3253-3253/? I/BaseDrawerActivity: The response is
Note:
The same code works fine in local nodejs server (http only)
1.Frist thing your api is a GET Method so use #GET instead #POST
Second try to change url base url in retrofit
.baseUrl("https://locodealapi.herokuapp.com")
to .baseUrl("https://locodealapi.herokuapp.com/")
this will work. or leave your problem in comment
2.this is sample code
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(
new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException{
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder =original.newBuilder().
method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
})
.addInterceptor(interceptor).connectTimeout(60,TimeUnit.SECONDS).readTimeout(60, TimeUnit.SECONDS).build();
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://locodealapi.herokuapp.com/")
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient).build();
UserApi userApi = retrofit.create(UserApi.class);
Call<ResponseBody> call = userApi.deals("your token");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call,retrofit2.Response<ResponseBody> response) {
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {}
});
}
#GET("api/deals")
Call deals(#Header("x-access-token") String x_access_token);
Greeting of the day!
Try this:
#FormUrlEncoded
#POST("/api/deals")
Call<ResponseBody> deals(#Header("x-access-token") String x_access_token, #Field("<parameter_name>") String parameter);
Call api as below:
Call<ResponseBody> call = client.deals(token,"<parameter>");
Here, i am assuming that the API has a parameter which can be passed as 2nd argument in the method deals(). You can pass multiple parameters as the arguments of the method.
Refer the following link for more details:
https://futurestud.io/tutorials/retrofit-send-data-form-urlencoded
I hope, this solves your problem. If not, please provide complete details of the API that you want to call.
A 400 response means that it's a disagreement between your request and the server, but that the request was created, sent, and a response was parsed. Which means Retrofit is working fine. You can use OkHttp's logging interceptor to log the raw request and compare it with what the server expects.
Also your Response size is around 5.96 MB. This is too big response. Instead of receiving this much of data in single response you could implement pagination or something similar to break down data. This could be one of the reason.
//Your Main connection Class
public class ApiClient {
public static final int DEFAULT_TIMEOUT_SEC = 90;
public static OkHttpClient client;
private static Retrofit retrofit = null;
public static Retrofit getClient() {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS)
.readTimeout(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_TIMEOUT_SEC, TimeUnit.SECONDS);
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
System.out.println("API_KEY"+PrefManager.getActiveInstance(RecrouteCandidateApplication.getsCurrentContext()).getDeviceToken());
Request request = original.newBuilder()
.header("x-access-token",YOUR_ACCESS_TOKEN"")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
//For logging the call on Logcat
HttpLoggingInterceptor interceptor1 = new HttpLoggingInterceptor();
interceptor1.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(interceptor1);
client = httpClient.build();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(AppConstants.BASE_URL)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
Use in Your Class which will initiate the connection like this
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
And This will be your ApiInterface
public interface ApiInterface {
#POST("Your url here")
Call<JsonObject> sampleMethod();
/*For non-empty body use this*/
//Call<JsonObject> getSignUpResponse(#Body JsonObject register);
//For form data use this
#FormUrlEncoded
#POST("Your url here")
Call<String> sampleMethod1(#Field(value= "param1_key", encoded = true) String param1_value);
}
Make a call like this for json
JsonObject obj= new JsonObject();
obj.addProperty("key1","keyvalue");
Call<JsonObject> call = apiService.sample1(obj);
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if (response.body().get("status").getAsString().equals("1")) {
Toast.makeText(context, response.body().get("msg").getAsString(), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, response.body().get("msg").getAsString(), Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Toast.makeText(context, AppConstants.NO_DATA_AVAILABLE, Toast.LENGTH_LONG).show();
}
});
for me the problem was because I had this line in the Gson builder :
.excludeFieldsWithoutExposeAnnotation()
with the above line, all the fields in your model classes that you send as body in retrofit will be ignored if they are not annotated with the #Exposed annotation.
removing .excludeFieldsWithoutExposeAnnotation() solved the problem for me.

How to upload audio to soundcloud via my android app using retrofit 2

I'm trying to upload my .mp3 file to soundcloud using this retrofit2 interface :
public interface ApiInterface {
#Multipart
#POST("tracks?client_id=********&client_secret=********")
Call<ResponseBody> uploadTrack(#Part("track") RequestBody file, #Part("track[title]") String title, #Part("track[sharing]") String sharing);
}
and realization with interceptor to include token:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initComponents();
sharedPreferences = getSharedPreferences(getApplicationInfo().name, MODE_PRIVATE);
token = sharedPreferences.getString(Config.ACCESS_TOKEN, "");
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Config.API_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(createOkHttpWithAuth())
.build();
apiInterface = retrofit.create(ApiInterface.class);
}
private OkHttpClient createOkHttpWithAuth() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
if (BuildConfig.DEBUG) {
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
} else {
interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
}
return new OkHttpClient.Builder()
.addInterceptor(new SoundcloudInterceptor(token))
.addNetworkInterceptor(interceptor)
.build();
}
Getting response:
File file = new File(Environment.getExternalStorageDirectory() + "/Music/test.mp3");
// create RequestBody instance from file
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
// MultipartBody.Part is used to send also the actual file name
MultipartBody.Part body =
MultipartBody.Part.createFormData("audio", file.getName(), requestFile);
Call<ResponseBody> call = apiInterface.uploadTrack(requestFile, "Test", "private");
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
//Log.v("Upload", "success" + response.body().toString());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.e("Upload error:", t.getMessage());
}
});
After request i'm receiving error 500:
05-13 12:36:23.407 6540-7186/com.example.soundcloud_app_android D/OkHttp: <-- 500 Internal Server Error https://api.soundcloud.com/tracks?client_id=**********&client_secret=**********&oauth_token=********** (3455ms)
05-13 12:36:23.407 6540-7186/com.example.soundcloud_app_android D/OkHttp: Access-Control-Allow-Headers: Accept, Authorization, Content-Type, Origin
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Access-Control-Allow-Methods: GET, PUT, POST, DELETE
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Access-Control-Allow-Origin: *
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Access-Control-Expose-Headers: Date
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Cache-Control: no-cache
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Content-Type: application/json; charset=utf-8
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Date: Fri, 13 May 2016 09:34:26 GMT
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Server: am/2
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Status: 500 Internal Server Error
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: Content-Length: 60
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: OkHttp-Sent-Millis: 1463132179952
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: OkHttp-Received-Millis: 1463132183407
05-13 12:36:23.408 6540-7186/com.example.soundcloud_app_android D/OkHttp: <-- END HTTP
Also tried passing file and MultipartBody.Part. In case of multipart i`m receiving error 422. So what is the right way to upload audio to soundcloud? I guess that i'm passing audio in wrong format and server doesn't recognise it.
Here example for upload image with retrofit 2.
First, when create retrofit for multipart request, doesn't add converter factory.
public static APIMultipartService getMultipartService() {
if (multipartService == null) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(DOMAIN)
.build();
multipartService = retrofit.create(APIMultipartService.class);
}
return multipartService;
}
Second, use RequestBody in interface.
public interface APIMultipartService {
#POST("/api/v1/job/photo/add")
Call<ResponseBody> uploadJobPhoto(#Body RequestBody body);}
And here example for create request body with file.
RequestBody body = RequestBody.create(MediaType.parse("image/*"), file);
MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
builder.addFormDataPart("pic", "photo.png", body);
builder.addFormDataPart("jobId", id);
builder.addFormDataPart("privateKey", privateKey);
Call<ResponseBody> request = ApiService.getMultipartService().uploadJobPhoto(builder.build());
request.enqueue(callbackPhotoRequest);
Try like that, maybe help you.

Retrofit 2 prints empty response body in log with HttpLoggingInterceptor.Level.BODY

I use Retrofit 2.0.0. This is the code that builds my HTTP client
protected OkHttpClient getHttpClient(){
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.addInterceptor(
chain -> {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder();
requestBuilder.header("Accept-Language", App.getInstance().getPrefs().getSelectedLanguage().toLowerCase());
requestBuilder.header("Accept-Encoding", "gzip");
if(API.this instanceof PrivateAPI){
LoginResponse loginResponse = AuthManager.getInstanse().getLoginResponse();
requestBuilder.header("Authorization", String.format("%s %s",
loginResponse.getTokenType(),
loginResponse.getAccessToken()));
}
requestBuilder.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
});
if(BuildConfig.DEBUG){
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(loggingInterceptor);
}
return builder.build();
}
And here is how I use it to init my Retrofit API interface:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(getGson()))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getHttpClient())
.build();
apiService = retrofit.create(PrivateAPIInterface.class);
Until yesterday I was getting full log in logcat as it supposed to be. But suddenly I begin to get empty response bodies in my log. So here is an example of log I get now:
D/OkHttp: --> GET http://MY_DOMAIN/utility/gaz?branchid=&phone=21919&customerid= HTTP/1.1
D/OkHttp: Accept-Language: hy
D/OkHttp: Accept-Encoding: gzip
D/OkHttp: Authorization: 0yXK65Go_hRPT32WIP4DAKjmzIaM0riSLlybHhusvwmYJSxTdTVBrkL5CaqopXgrOuNFL5xvR5uVwCbprWrxvfYTMJ1I_AUmd5TKdNL4ptkUrJuOy1kGiule_yveCFv0GbTiAXhYjdfynJICJEVWc54ibnIv_Q14dLpPuVle5IaRuHmza2Pavkrhzi42sfMsK0Qpxaueu8eRPysk6MP9WkTnSKYIAThuq3sHq8RGAnkaLBx
D/OkHttp: --> END GET
D/OkHttp: <-- 200 OK http://MY_DOMAIN/utility/gaz?branchid=&phone=21919&customerid= (394ms)
D/OkHttp: Content-Length: 8527
D/OkHttp: Content-Type: application/json; charset=utf-8
D/OkHttp: Server: Microsoft-IIS/7.5
D/OkHttp: X-Powered-By: ASP.NET
D/OkHttp: Date: Wed, 16 Mar 2016 12:30:37 GMT
D/OkHttp: OkHttp-Sent-Millis: 1458131438086
D/OkHttp: OkHttp-Received-Millis: 1458131438438
D/OkHttp: }
D/OkHttp: <-- END HTTP (8527-byte body)
As you can see everything I get instead of response body is D/OkHttp: }.
But in Postman I see a normal response body and in my app everything works fine so the problem is only with logging.
Can anybody help me to understand why this can start happening?
P.S. In case of requests that has body I see the request body the problem is only with response bodys.
With retrofit-2 you are supposed to use OkHttp3 for getting full logs. Add this to your dependecies: compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(ApiClient.class);
ResClient.class
public class RestClient {
private static ApiInterface apiInterface;
static {
setupRestClient();
}
private static void setupRestClient() {
OkHttpClient httpClient = new OkHttpClient();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(NetworkConstants.URL_BASE_LIVE)
.setLogLevel(RestAdapter.LogLevel.FULL)
.setLog(new AndroidLog("Retrofit"))
.setClient(new OkClient(httpClient))
.build();
apiInterface = restAdapter.create(ApiInterface.class);
}
public static ApiInterface getAdapter(){
return apiInterface;
}
}
ApiInterface.class
public interface ApiInterface {
// result api
//All result api async
#Headers({"Authorization: ######################"}) //for the header authorization if needed.
#GET(NetworkConstants.URL_GET_RESULTS)
void getResult(#QueryMap Map <String, String> params, Callback<ArrayList<Results>> callback);
}
Now call it like
// Fetching result through Api Hit
RestClient.getAdapter().getResult(getJobsParams(), new Callback<ArrayList<Result>>() {
#Override
public void success(ArrayList<Result> result, retrofit.client.Response response) {
// Do your Work
}
#Override
public void failure(RetrofitError error) {
// show server or other error to user
}
});

Categories

Resources