I'm using an interceptor, and I would like to log the body of a request I'm making but I can't see any way of doing this.
Is it possible ?
public class LoggingInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
double time = (t2 - t1) / 1e6d;
if (request.method().equals("GET")) {
Logs.info(String.format("GET " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), response.code(), response.headers(), response.body().charStream()));
} else if (request.method().equals("POST")) {
Logs.info(String.format("POST " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), request.body(), response.code(), response.headers(), response.body().charStream()));
} else if (request.method().equals("PUT")) {
Logs.info(String.format("PUT " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), request.body().toString(), response.code(), response.headers(), response.body().charStream()));
} else if (request.method().equals("DELETE")) {
Logs.info(String.format("DELETE " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITHOUT_BODY, request.url(), time, request.headers(), response.code(), response.headers()));
}
return response;
}
}
and the result :
POST [some url] in 88,7ms
ZoneName: touraine
Source: Android
body: retrofit.client.OkClient$1#1df53f05 <-request.body().toString() gives me this, but I would like the content string
Response: 500
Date: Tue, 24 Feb 2015 10:14:22 GMT
body: [some content]
Nikola's answer did not work for me. My guess is the implementation of ByteString#toString() changed. This solution worked for me:
private static String bodyToString(final Request request){
try {
final Request copy = request.newBuilder().build();
final Buffer buffer = new Buffer();
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (final IOException e) {
return "did not work";
}
}
From the documentation of readUtf8():
Removes all bytes from this, decodes them as UTF-8, and returns the string.
which should be what you want.
I tried to comment on the correct answer from #msung, but my reputation isn't high enough.
Here's modification I did to print RequestBody before making it a full request. It works like a charm. Thanks
private static String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
copy.writeTo(buffer);
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
EDIT
Because I see there is still some people interested by this post, here is the final version (until next improvement) of my log interceptor. I hope it will save some of you guys's time.
Please note that this code is using OkHttp 2.2.0 (and Retrofit 1.9.0)
import com.squareup.okhttp.*;
import okio.Buffer;
import java.io.IOException;
public class LoggingInterceptor implements Interceptor {
private static final String F_BREAK = " %n";
private static final String F_URL = " %s";
private static final String F_TIME = " in %.1fms";
private static final String F_HEADERS = "%s";
private static final String F_RESPONSE = F_BREAK + "Response: %d";
private static final String F_BODY = "body: %s";
private static final String F_BREAKER = F_BREAK + "-------------------------------------------" + F_BREAK;
private static final String F_REQUEST_WITHOUT_BODY = F_URL + F_TIME + F_BREAK + F_HEADERS;
private static final String F_RESPONSE_WITHOUT_BODY = F_RESPONSE + F_BREAK + F_HEADERS + F_BREAKER;
private static final String F_REQUEST_WITH_BODY = F_URL + F_TIME + F_BREAK + F_HEADERS + F_BODY + F_BREAK;
private static final String F_RESPONSE_WITH_BODY = F_RESPONSE + F_BREAK + F_HEADERS + F_BODY + F_BREAK + F_BREAKER;
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
MediaType contentType = null;
String bodyString = null;
if (response.body() != null) {
contentType = response.body().contentType();
bodyString = response.body().string();
}
double time = (t2 - t1) / 1e6d;
if (request.method().equals("GET")) {
System.out.println(String.format("GET " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), response.code(), response.headers(), stringifyResponseBody(bodyString)));
} else if (request.method().equals("POST")) {
System.out.println(String.format("POST " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), stringifyRequestBody(request), response.code(), response.headers(), stringifyResponseBody(bodyString)));
} else if (request.method().equals("PUT")) {
System.out.println(String.format("PUT " + F_REQUEST_WITH_BODY + F_RESPONSE_WITH_BODY, request.url(), time, request.headers(), request.body().toString(), response.code(), response.headers(), stringifyResponseBody(bodyString)));
} else if (request.method().equals("DELETE")) {
System.out.println(String.format("DELETE " + F_REQUEST_WITHOUT_BODY + F_RESPONSE_WITHOUT_BODY, request.url(), time, request.headers(), response.code(), response.headers()));
}
if (response.body() != null) {
ResponseBody body = ResponseBody.create(contentType, bodyString);
return response.newBuilder().body(body).build();
} else {
return response;
}
}
private static String stringifyRequestBody(Request request) {
try {
final Request copy = request.newBuilder().build();
final Buffer buffer = new Buffer();
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (final IOException e) {
return "did not work";
}
}
public String stringifyResponseBody(String responseBody) {
return responseBody;
}
}
With a current version of OkHttp, you can use the HTTP Logging Interceptor and set the level to BODY
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(Level.BODY);
With this you cannot granularily configure the output for different HTTP methods, but it also works for other methods that might have a body.
Here an example showing the output of a PATCH request (minimally redacted):
--> PATCH https://hostname/api/something/123456 HTTP/1.1
Content-Type: application/json-patch+json; charset=utf-8
Content-Length: 49
Authorization: Basic YWRtaW46c2VjcmV0Cg==
Accept: application/json
[ { "op": "add", "path": "/path", "value": true }]
--> END PATCH (xx-byte body)
As you can see, this also prints out the headers and as the documentation states, you should really take care:
The logs generated by this interceptor when using the HEADERS or BODY levels have the potential to leak sensitive information such as "Authorization" or "Cookie" headers and the contents of request and response bodies. This data should only be logged in a controlled way or in a non-production environment.
You can redact headers that may contain sensitive information by calling redactHeader().
logging.redactHeader("Authorization");
logging.redactHeader("Cookie");
Version that handles requests with or without a body:
private String stringifyRequestBody(Request request) {
if (request.body() != null) {
try {
final Request copy = request.newBuilder().build();
final Buffer buffer = new Buffer();
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (final IOException e) {
Log.w(TAG, "Failed to stringify request body: " + e.getMessage());
}
}
return "";
}
Kotlin version :
val buf = okio.Buffer()
requestBody.writeTo(buf)
Log.d("AppXMLPostReq", "reqBody = ${buf.readUtf8()}")
Create a Separate new class and implement Intercepter.
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
var logInfo = ""
val requestBody=loggerUtil.getRequestBody
return response
}
yourOkHttpClient.addInterceptor(yourInstance)
GetRequestBody
var requestContent = ""
val requestBody = request.body
val buffer = Buffer()
if (requestBody != null) {
requestBody.writeTo(buffer)
}
val contentType = requestBody?.contentType()
val charset: Charset =
contentType?.charset(StandardCharsets.UTF_8) ?:StandardCharsets.UTF_8
if (buffer.isProbablyUtf8()) {
requestContent = buffer.readString(charset)
}
Extension to find Whether buffer data is UT8 format
fun Buffer.isProbablyUtf8(): Boolean {
try {
val prefix = Buffer()
val byteCount = size.coerceAtMost(64)
copyTo(prefix, 0, byteCount)
for (i in 0 until 16) {
if (prefix.exhausted()) {
break
}
val codePoint = prefix.readUtf8CodePoint()
if (Character.isISOControl(codePoint) && !Character.isWhitespace(codePoint)) {
return false
}
}
return true
} catch (_: EOFException) {
return false // Truncated UTF-8 sequence.
}
}
Are we supposed to call .close() on the buffer object ? or use the try-with-resources statement ?
private String getBodyAsString(Request request) throws IOException {
try(var buffer = new Buffer()) {
request.body().writeTo(buffer);
return buffer.readUtf8();
}
}
Related
I am just trying to show user data after hitting the API using Retrofit. my api response is:
{
"password":"111222333",
"name":"test name",
"email":"testem#gmail.com",
"username":"test1",
"customer_id":"201060",
"phone":"0196789"
}
but unfortunately, I am getting
"Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $"
error.
I am totally stuck to show my json response.
My User.java class:
public class User {
#SerializedName("name")
#Expose
private String name;
#SerializedName("email")
#Expose
private String email;
#SerializedName("username")
#Expose
private String username;
#SerializedName("customer_id")
#Expose
private String customerId;
#SerializedName("phone")
#Expose
private String phone;
#SerializedName("password")
#Expose
private String password;
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public String getUsername() {
return username;
}
public String getCustomerId() {
return customerId;
}
public String getPhone() {
return phone;
}
public String getPassword() {
return password;
}
}
My Login class:
Gson gson = new GsonBuilder().setLenient().create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://us-central1-gmx-notification.cloudfunctions.net/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
all_api = retrofit.create(allApi.class);
private void getUserDetails(String userName,String passWord){
Call<User> call = all_api.getUserDetails(userName,passWord);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if(!response.isSuccessful()){
Log.d(response.body());
}
else{
User user = response.body();
String content = "";
content+= "Name: "+user.getName()+"\n";
content+= "Email: "+user.getEmail()+"\n";
content+= "Customer ID: "+user.getCustomerId()+"\n";
content+= "Phone: "+user.getPhone()+"\n";
Log.d(content);
}
});
}
and my retrofit api class:
package com.material.components;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface allApi {
#GET("login")
Call <User> getUserDetails(
#Query("email") String email,
#Query("password") String password
);
}
When i hit you api https://us-central1-gmx-notification.cloudfunctions.net/login?email=qwery#gmail.com&password=12345678
I got this response
Error: could not handle the request
So as your error says you expected Object but got a string. So or an error on the backend side or the request is incorrect or you forgot to add something to the request(Header or something else...).
For sure problem not in your model just got not a model that you expect in the response. Add Interceptor in your OkHttpClient to see what you get to be sure.
You need add this dependency to gradle
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1'
And here is a code example your API that will printing all networking stuff in the log:
public class NetworkManager {
private static RESTAuthService restAuthService;
/*timeout values in seconds*/
private static final int CONNECTION_TIMEOUT = 10;
private static final int WRITE_TIMEOUT = 10;
private static final int READ_TIMEOUT = 10;
static RESTAuthService getRESTAuthService() {
if (restAuthService == null) {
synchronized (NetworkManager.class) {
if (restAuthService == null) {
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new RESTInterceptor())
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(NetworkConfig.BASE_AUTH_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
restAuthService = retrofit.create(RESTAuthService.class);
}
}
}
return restAuthService;
}
private static class RESTInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Buffer buffer = new Buffer();
if (request.body() != null) {
request.body().writeTo(buffer);
}
Log.d("HTTP Request", "Request to " + request.url().toString()
+ "\n" + request.headers().toString()
+ "\n" + buffer.readUtf8());
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
String msg = response.body().string();
msg = msg.replace("\r", ""); // Note: Messages with '\r' not displayed correctly in logcat
Log.d("HTTP Response", String.format("Response from %s in %.1fms%n\n%s",
response.request().url().toString(), (t2 - t1) / 1e6d, msg));
Log.d("HTTP Response", "Response code = " + response.code());
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), msg))
.build();
}
}
}
Your MyLogin class will be something like this:
public class MuLogin {
/*timeout values in seconds*/
private static final int CONNECTION_TIMEOUT = 10;
private static final int WRITE_TIMEOUT = 10;
private static final int READ_TIMEOUT = 10;
allApi = all_api;
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new RESTInterceptor())
.connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
.writeTimeout(WRITE_TIMEOUT, TimeUnit.SECONDS)
.readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://us-central1-gmx-notification.cloudfunctions.net/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
all_api =retrofit.create(allApi.class);
public void getUserDetails(String userName, String passWord) {
Call<User> call = all_api.getUserDetails(userName, passWord);
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if (!response.isSuccessful()) {
Log.d(response.body());
} else {
User user = response.body();
String content = "";
content += "Name: " + user.getName() + "\n";
content += "Email: " + user.getEmail() + "\n";
content += "Customer ID: " + user.getCustomerId() + "\n";
content += "Phone: " + user.getPhone() + "\n";
Log.d(content);
}
});
}
}
private static class RESTInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Buffer buffer = new Buffer();
if (request.body() != null) {
request.body().writeTo(buffer);
}
Log.d("HTTP Request", "Request to " + request.url().toString()
+ "\n" + request.headers().toString()
+ "\n" + buffer.readUtf8());
long t1 = System.nanoTime();
Response response = chain.proceed(request);
long t2 = System.nanoTime();
String msg = response.body().string();
msg = msg.replace("\r", ""); // Note: Messages with '\r' not displayed correctly in logcat
Log.d("HTTP Response", String.format("Response from %s in %.1fms%n\n%s",
response.request().url().toString(), (t2 - t1) / 1e6d, msg));
Log.d("HTTP Response", "Response code = " + response.code());
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), msg))
.build();
}
}
}
How to check if the URL is an image URL that must be either PNG, GIF, JPG formats
I see that it can be done with this code:
URLConnection connection = new URL("http://foo.bar/w23afv").openConnection();
String contentType = connection.getHeaderField("Content-Type");
boolean image = contentType.startsWith("image/");
But, I need to check using either Glide or OKHttpClient.
How to achieve this using two techniques mentioned above?
If all you want to do is check the Content-Type of a URL, without actually downloading the content, an HTTP HEAD request would be appropriate.
The HEAD method is identical to GET except that the server MUST NOT
return a message-body in the response. The metainformation contained
in the HTTP headers in response to a HEAD request SHOULD be identical
to the information sent in response to a GET request. This method can
be used for obtaining metainformation about the entity implied by the
request without transferring the entity-body itself. This method is
often used for testing hypertext links for validity, accessibility,
and recent modification.
You can do this with OkHttp as follows:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("http://foo.bar/w23afv")
.head()
.build();
try {
Response response = client.newCall(request).execute();
String contentType = response.header("Content-Type");
boolean image = false;
if (contentType != null) {
image = contentType.startsWith("image/");
}
} catch (IOException e) {
// handle error
}
If you are okay with the HEAD request I think that Jeff Lockhart is the cleanest solution. Anyway I post here below a more comprehensive solution about your question:
With okhttp3 only
implementation 'com.squareup.okhttp3:okhttp:3.14.0'
You could check headers of an HEAD request also accessing body ContentType.
Check headers onto onResponse()
OkHttpClient client = new OkHttpClient();
Request requestHead = new Request.Builder()
.url("your tiny url")
.head()
.build();
Request request = new Request.Builder()
.url("your tiny url")
.build();
// HEAD REQUEST
client.newCall(requestHead).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
Log.d("OKHTTP3 onFailure", e.getMessage());
}
#Override
public void onResponse(#NonNull Call call, #NonNull Response response) throws IOException {
try {
final ResponseBody _body = response.body();
if (_body != null) {
final MediaType _contentType = _body.contentType();
if (_contentType != null) {
final String _mainType = _contentType.type(); // image
final String _subtypeType = _contentType.subtype(); // jpeg/png/etc.
Log.d("OKHTTP3 - media content type", _contentType.toString());
Log.d("OKHTTP3 - media main type", _mainType);
Log.d("OKHTTP3 - media sub type", _subtypeType);
boolean isImage = _mainType.equals("image");
Log.d("OKHTTP3 - I'VE GOT AN IMAGE", "" + isImage);
if (isImage) {
Log.d("OKHTTP3 WE HAVE AN IMAGE!", "yay!");
} else {
Log.d("OKHTTP3 SKIP CONTENT!", "Buuu!");
}
}
}
} catch (Exception e) {
Log.d("OKHTTP3 Interrupted Exception", e.getMessage());
}
}
});
// GET REQUEST
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
Log.d("OKHTTP3 onFailure", e.getMessage());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try {
final ResponseBody _body = response.body();
final MediaType _contentType = _body.contentType();
final String _mainType = _contentType.type(); // image
final String _subtypeType = _contentType.subtype(); // jpeg/png/etc.
Log.d("OKHTTP3 - media content type", _contentType.toString());
Log.d("OKHTTP3 - media main type", _mainType);
Log.d("OKHTTP3 - media sub type", _subtypeType);
boolean isImage = _mainType.equals("image");
Log.d("OKHTTP3 - I'VE GOT AN IMAGE", "" + isImage);
if (isImage) {
final InputStream inputStream = response.body().byteStream();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
runOnUiThread(() -> {
helloImageView.setImageBitmap(bitmap);
});
}
} catch (Exception e) {
Log.d("OKHTTP3 Interrupted Exception", e.getMessage());
}
}
});
Check headers with interceptor:
Interceptors is good because it centralises in a single place where you check your url.
OkHttpClient clientWithInterceptor = new OkHttpClient.Builder()
.addInterceptor(chain -> {
Response _response = chain.proceed(request);
final ResponseBody _body = _response.body();
if (_body != null) {
final MediaType _contentType = _body.contentType();
if (_contentType != null) {
final String _mainType = _contentType.type(); // image
final String _subtypeType = _contentType.subtype(); // jpeg/png/etc.
Log.d("OKHTTP3 - media content type", _contentType.toString());
Log.d("OKHTTP3 - media main type", _mainType);
Log.d("OKHTTP3 - media sub type", _subtypeType);
boolean isImage = _mainType.equals("image");
Log.d("OKHTTP3 - I'VE GOT AN IMAGE", "" + isImage);
if (isImage) {
return _response;
} else {
return return415Response(chain);
}
} else {
return return415Response(chain);
}
} else {
return return415Response(chain);
}
}).build();
clientWithInterceptor.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
Log.d("OKHTTP3 onFailure", e.getMessage());
}
#Override
public void onResponse(Call call, Response response) throws IOException {
Log.d("OKHTTP3 - onResponse", "" + response.toString());
if (response.isSuccessful()) {
final InputStream inputStream = response.body().byteStream();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
runOnUiThread(() -> {
helloImageView.setImageBitmap(bitmap);
});
}
}
});
//*/
}
private Response return415Response(Interceptor.Chain chain) {
return new Response.Builder()
.code(415) // Media type not supported... or whatever
.protocol(Protocol.HTTP_1_1)
.message("Media type not supported")
.body(ResponseBody.create(MediaType.parse("text/html"), ""))
.request(chain.request())
.build();
}
Using Glide v4 along with okhttp3
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
implementation 'com.github.bumptech.glide:annotations:4.9.0'
implementation "com.github.bumptech.glide:okhttp3-integration:4.9.0"
You need to extend GlideAppModule
#GlideModule
public class OkHttpAppGlideModule extends AppGlideModule {
#Override
public void applyOptions(#NonNull Context context, #NonNull GlideBuilder builder) {
super.applyOptions(context, builder);
}
#Override
public void registerComponents(#NonNull Context context, #NonNull Glide glide, #NonNull Registry registry) {
OkHttpClient client = new OkHttpClient.Builder()
.readTimeout(15, TimeUnit.SECONDS)
.connectTimeout(15, TimeUnit.SECONDS)
.addNetworkInterceptor(chain -> {
Response _response = chain.proceed(chain.request());
int _httpResponseCode = _response.code();
if (_httpResponseCode == 301
|| _httpResponseCode == 302
|| _httpResponseCode == 303
|| _httpResponseCode == 307) {
return _response; // redirect
}
final ResponseBody _body = _response.body();
if (_body != null) {
final MediaType _contentType = _body.contentType();
if (_contentType != null) {
final String _mainType = _contentType.type(); // image
final String _subtypeType = _contentType.subtype(); // jpeg/png/etc.
Log.d("OKHTTP3 - media content type", _contentType.toString());
Log.d("OKHTTP3 - media main type", _mainType);
Log.d("OKHTTP3 - media sub type", _subtypeType);
boolean isImage = _mainType.equals("image");
Log.d("OKHTTP3 - I'VE GOT AN IMAGE", "" + isImage);
if (isImage) {
Log.d("OKHTTP3 WE HAVE AN IMAGE!", "yay!");
return _response;
} else {
return return415Response(chain);
}
} else {
return return415Response(chain);
}
} else {
return return415Response(chain);
}
}).build();
OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(client);
registry.replace(GlideUrl.class, InputStream.class, factory);
}
private Response return415Response(Interceptor.Chain chain) {
return new Response.Builder()
.code(415) // Media type not supported... or whatever
.protocol(Protocol.HTTP_1_1)
.message("Media type not supported")
.body(ResponseBody.create(MediaType.parse("text/html"), ""))
.request(chain.request())
.build();
}
Then calling
Glide.with(this)
.load("your tini url")
.into(helloImageView);
You enter your okhttp client interceptor and you can act accordingly.
in okHttpClient you have to use below line as a URL and make API Call, if call successful then you can check your condition.
ex:-
String url = new URL("http://foo.bar/w23afv").toString();
OkHttpHandler okHttpHandler= new OkHttpHandler();
okHttpHandler.execute(url);
If you obtain the image string. you can simply check for that image url that ends with (jpg or png) using this String format method.
imageString.endsWith("jpg") || imageString.endsWith("png")
If you are getting "Image path" as a string then try this...
image_extension = image_path.substring(image_path.length() - 3)
then compare this image_extension with png,jpg and gif
I am trying to upload files in Amazon S3 using OkHttp3 library. I am able to upload the files using AsyncTask.Right now, I am showing a normal ProgressDialog. But, I want to replace the ProgressDialog with a ProgressBar. For this, I am doing the following things, but somehow it does not work:
1) Creating a custom ResponseBody and ProgressListener:
private static class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
this.responseBody = responseBody;
this.progressListener = progressListener;
}
#Override
public MediaType contentType() {
return responseBody.contentType();
}
#Override
public long contentLength() {
return responseBody.contentLength();
}
#Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
#Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
return bytesRead;
}
};
}
}
interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done);
}
2) Implementing the ProgressListener interface within the AsyncTask using for uploading the files:
final ProgressListener progressListener = new ProgressListener() {
#Override
public void update(long bytesRead, long contentLength, boolean done) {
Log.d(AppGlobal.TAG, " " + bytesRead);
Log.d(AppGlobal.TAG, " " + contentLength);
Log.d(AppGlobal.TAG, " " + done);
Log.d(AppGlobal.TAG, (100 * bytesRead) / contentLength + " % done ");
Log.d(AppGlobal.TAG, " " + "-------------------------");
}
};
3) Creating a OkHttp client and passing the progressListener created in Step 2 using a network interceptor:
Request request = new Request.Builder()
.header("Proxy-Authorization", "Basic " + Base64.encodeToString(data, Base64.NO_WRAP))
.addHeader("Content-Type", "application/octet-stream")
.addHeader("Connection", "Keep-Alive")
.url(url)
.put(RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(1000, TimeUnit.SECONDS)
.writeTimeout(1000, TimeUnit.SECONDS)
.readTimeout(3000, TimeUnit.SECONDS)
.proxy(proxy)
.proxyAuthenticator(proxyAuthenticator)
.addNetworkInterceptor(new Interceptor() {
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
okhttp3.Response response = client.newCall(request).execute();
But, the Log.d() statements used in the "update()" function of progressListener never gets executed.
If I can get these Log statements to print, then I can update the progress bar accordingly. Can someone kindly help me out.
Here is the full code used in "doInBackground" method of AsyncTask:
#Override
protected Void doInBackground(File... inputs) {
try {
file = inputs[0];
Date expiration = new Date();
long milliSeconds = expiration.getTime();
milliSeconds += 1000 * 60 * 60; // Add 1 hour.
expiration.setTime(milliSeconds);
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(Constants.BUCKET_NAME, AppGlobal.deviceId + "/" + file.getName());
generatePresignedUrlRequest.setMethod(HttpMethod.PUT);
generatePresignedUrlRequest.setContentType("application/octet-stream");
generatePresignedUrlRequest.setExpiration(expiration);
final URL url = Util.getS3Client(UploadActivity.this).generatePresignedUrl(generatePresignedUrlRequest);
Log.d("DXXXXXX", " URL -> " + url);
String domain = AppGlobal.getDomain(UploadActivity.this);
int port = Integer.valueOf(AppGlobal.getPort(UploadActivity.this));
final String signature = AppGlobal.getSignature(UploadActivity.this);
Proxy proxy = new Proxy(Proxy.Type.HTTP,
InetSocketAddress.createUnresolved(domain, port));//the proxy server(Can be your laptop ip or company proxy)
try {
String headerVal = String.format("%s:%s", "vzServices", signature);
final byte[] data = headerVal.getBytes("UTF-8");
okhttp3.Authenticator proxyAuthenticator = new okhttp3.Authenticator() {
#Override
public Request authenticate(Route route, okhttp3.Response response) throws IOException {
String credential = Credentials.basic("vzServices", signature);
return response.request().newBuilder().header("Proxy-Authorization", credential).build();
}
};
final ProgressListener progressListener = new ProgressListener() {
#Override
public void update(long bytesRead, long contentLength, boolean done) {
Log.d(AppGlobal.TAG, " " + bytesRead);
Log.d(AppGlobal.TAG, " " + contentLength);
Log.d(AppGlobal.TAG, " " + done);
Log.d(AppGlobal.TAG, (100 * bytesRead) / contentLength + " % done ");
Log.d(AppGlobal.TAG, " " + "-------------------------");
}
};
Request request = new Request.Builder()
.header("Proxy-Authorization", "Basic " + Base64.encodeToString(data, Base64.NO_WRAP))
.addHeader("Content-Type", "application/octet-stream")
.addHeader("Connection", "Keep-Alive")
.url(url)
.put(RequestBody.create(MediaType.parse("application/octet-stream"), file))
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(1000, TimeUnit.SECONDS)
.writeTimeout(1000, TimeUnit.SECONDS)
.readTimeout(3000, TimeUnit.SECONDS)
.proxy(proxy)
.proxyAuthenticator(proxyAuthenticator)
.addNetworkInterceptor(new Interceptor() {
#Override public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), progressListener))
.build();
}
})
.build();
okhttp3.Response response = client.newCall(request).execute();
responseCode = response.code();
Log.d("Response code : ", " " + response.code());
Log.d("DXXXXXX", " URL 1 -> " + url);
success = true;
buffer = null;
} catch (Exception ex) {
// Handle the error
Log.d(TAG, "Error: " + ex.getLocalizedMessage());
ex.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
You should enable the progress bar first, just before calling the okhttp3 processing. Then, on response and on error, you should dismiss it.
Here's the snippet (I don't know okhttp but I've used volley many times. This example was kept simple enough to let you understand what I mean.)
sendJsonRequest(){
//enable progress bar here
enableProgressBar();
JsonObjectRequest jsObjRequest = new JsonObjectRequest(Request.Method.GET, URL, null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// dismiss it
hideProgressDialog();
System.out.println(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// dismiss it and/or handle errors
hideProgressDialog();
// ...
}
});
queue.add(jsObjRequest);
}
I have found this example below to send HTTP POST message with OKHttp.
I do not understand how to pass a body string to RequestBody. Why it takes two argument?
RequestBody formBody = new FormBody.Builder()
.add("message", "Your message")
.build();
Request request = new Request.Builder()
.url("http://rhcloud.com")
.post(formBody).addHeader("operation", "modifyRecords")
.build();
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful())
throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0, size = responseHeaders.size(); i < size; i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
}
}
I'm not sure if I understand what you mean quite right, but if you are asking why the FormBody .add() takes two arguments, it's because these are Key-Value-Pairs. The first parameter is the name and the second the value.
Anyway I think this example shows a clearer way how to post a string:
public static final MediaType MEDIA_TYPE_MARKDOWN
= MediaType.parse("text/x-markdown; charset=utf-8");
private final OkHttpClient client = new OkHttpClient();
public void run() throws Exception {
String postBody = ""
+ "Releases\n"
+ "--------\n"
+ "\n"
+ " * _1.0_ May 6, 2013\n"
+ " * _1.1_ June 15, 2013\n"
+ " * _1.2_ August 11, 2013\n";
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))
.build();
Response response = client.newCall(request).execute();
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
System.out.println(response.body().string());
}
I am using Asycntask for handling my service. However, I want to use Retrofit and like to get some advice before moving on. My json services are like following. All of them have a result JSONObject and data(JSONObject or JSONArray). When I look at some tutorials, it says retrofit works with GSON and I have to convert my models to GSON format(http://www.jsonschema2pojo.org/). The thing I want to learn is, should I also add this result part of my services into my model. While using Asynctask, I am parsing result part and if the message is "ok", i start my data parsing. If message is not "ok", then I show an alert dialog with message. Can I get some advice about that?
{
result: {
code: 0,
message: "OK",
dateTime: "20160204135212",
},
movie: [
{
name: "Movie 1",
category: "drama"
},
{
name: "Movie 2"
category: "comedy"
}
]
}
Seems you need to use Interceptors.
Interceptors is the mechanism which allow to you do some work before use response. I mark the line, where you need to add transformation logic.
public static class LoggingInterceptor implements Interceptor {
#Override
public com.squareup.okhttp.Response intercept(Chain chain) throws IOException {
Log.i("LoggingInterceptor", "inside intercept callback");
Request request = chain.request();
long t1 = System.nanoTime();
String requestLog = String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers());
if (request.method().compareToIgnoreCase("post") == 0) {
requestLog = "\n" + requestLog + "\n" + bodyToString(request);
}
Log.d("TAG", "request" + "\n" + requestLog);
com.squareup.okhttp.Response response = chain.proceed(request);
long t2 = System.nanoTime();
String responseLog = String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers());
String bodyString = response.body().string();
Log.d("TAG", "response only" + "\n" + bodyString);
Log.d("TAG", "response" + "\n" + responseLog + "\n" + bodyString);
// HERE YOU CAN ADD JSON DATA TO EXISTING RESPONSE
return response.newBuilder()
.body(ResponseBody.create(response.body().contentType(), bodyString))
.build();
}
public static String bodyToString(final Request request) {
try {
final Request copy = request.newBuilder().build();
final Buffer buffer = new Buffer();
copy.body().writeTo(buffer);
return buffer.readUtf8();
} catch (final IOException e) {
return "did not work";
}
}
}
Yes, this response from your service should be a model in your app.
Retrofit will automatically serialize the json to java object in onResponse
#Override
public void onResponse(Response<Result> response){
if(response.isSuccess()){
Result result = response.body();
if(result.getMessage().equals("OK")){
//do something
}else{
//show an alert dialog with message
}
}