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
Related
I'm running multiple network requests(getResponse method) in a for loop and I'm trying to get list of the responses only when ALL of the network requests are done.
I am trying to use CompletableFuture. getResponse uses OKHttp (asynch request and response)
Log.d("api_log", "Started doing things");
List<CompletableFuture> futures = new ArrayList();
for (int i = 0; i < mylist.size(); i++) {
try {
int finalI = i;
futures.add(CompletableFuture.runAsync(() -> getResponse(context, mylist.get(finalI).id)));
}
catch (Exception e) {}
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRunAsync(() -> Log.d("api_log", "Ended doing things"));
This is the getResponse method:
private void getResponse(final Context context, final String id) {
Log.d("api_log", "id is: " + id);
final String url = context.getString(R.string.myurl) + "/" + id;
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
Request request = new Request.Builder()
.url(url)
.method("GET", null)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override
public void onResponse(Call call, final Response response) throws IOException {
if (!response.isSuccessful()) {
return;
}
// response HAS RECEIVED
final String strResponse = response.body().string();
Log.d("api_log", "response: " + strResponse);
}
});
}
Actual: "Ended doing things" is printed before all the responses are printed.
Expected: "Ended doing things" should be printed after all the responses are printed.
How can I achieve it?
I'm trying to perform offline cashing when internet connection is lost so that i can display data from cache . here is what I've done till now .
my question is how can make my observable return the cached arraylist of data instead of just returning error?
my service generator :
public class ServiceGenerator {
public static final String API_BASE_URL = UrlManager.BASE_URL_API;
private static final String CACHE_CONTROL = "Cache-Control";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60,TimeUnit.SECONDS)
.readTimeout(60,TimeUnit.SECONDS);
private static Gson gson = new GsonBuilder()
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()));
private static Retrofit retrofit;
public static Gson getGson() {
return gson;
}
public static void setup() {
httpClient.addInterceptor(provideOfflineCacheInterceptor());
httpClient.addInterceptor(new AddCookiesInterceptor()); // VERY VERY IMPORTANT
httpClient.addInterceptor(new ReceivedCookiesInterceptor()); // VERY VERY IMPORTANT
httpClient.addInterceptor( provideHttpLoggingInterceptor() );
httpClient.addNetworkInterceptor(new StethoInterceptor());// Stetho
httpClient.addNetworkInterceptor(provideCacheInterceptor());
httpClient.cache(provideCache());
OkHttpClient client = httpClient.build();
retrofit = builder.client(client).build();
}
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null);
}
public static <S> S createService(Class<S> serviceClass, final String authToken) {
if (authToken != null) {
httpClient.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()
.header("Authorization", authToken)
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
return retrofit.create(serviceClass);
}
public static Interceptor provideCacheInterceptor() {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
// re-write response header to force use of cache
CacheControl cacheControl = new CacheControl.Builder()
.maxAge(2, TimeUnit.MINUTES)
.build();
return response.newBuilder()
.header(CACHE_CONTROL, cacheControl.toString())
.build();
}
};
}
public static Interceptor provideOfflineCacheInterceptor() {
return new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!UruzApplication.hasNetwork()) {
CacheControl cacheControl = new CacheControl.Builder()
.maxStale(7, TimeUnit.DAYS)
.build();
request = request.newBuilder()
.cacheControl(cacheControl)
.build();
}
return chain.proceed(request);
}
};
}
private static Cache provideCache() {
Cache cache = null;
try {
cache = new Cache(new File(UruzApplication.getInstance().getCacheDir(), "http-cache"),
10 * 1024 * 1024); // 10 MB
} catch (Exception e) {
Timber.e(e, "Could not create Cache!");
}
return cache;
}
private static HttpLoggingInterceptor provideHttpLoggingInterceptor ()
{
HttpLoggingInterceptor httpLoggingInterceptor =
new HttpLoggingInterceptor( new HttpLoggingInterceptor.Logger()
{
#Override
public void log (String message)
{
Timber.d( message );
}
} );
httpLoggingInterceptor.setLevel( true ? HEADERS : NONE );
return httpLoggingInterceptor;
}
}
my observer :
public static Observable<List<WeekDietPlan>>
fetchPackageWeeksDaysDietPlan(int traineeId) {
DietService requestService = ServiceGenerator.createService(DietService.class);
return requestService.getPackageWeekDaysDietPlan(UrlManager.getTraineeDietPackageDetailsUrl(),
traineeId)
.flatMap(new Function<JsonElement, Observable<List<WeekDietPlan>>>() {
#Override
public Observable<List<WeekDietPlan>> apply(JsonElement jsonElement) throws Exception {
JsonObject asJsonObject = jsonElement.getAsJsonObject();
String result = asJsonObject.get(UrlManager.ResultTypes.RESULT).getAsString();
Timber.d(TAG, "result Tag" + result);
if (UrlManager.ResultTypes.isError(result) || UrlManager.ResultTypes.isFailure(result)) {
String errorMessage = asJsonObject.get(UrlManager.ResultTypes.RESULT_ERROR_MESSAGE).getAsString();
return Observable.error(new Exception(errorMessage));
}
if (UrlManager.ResultTypes.isSucess(result)) {
if (!GsonHelper.isNull(asJsonObject.get(UrlManager.ResultTypes.RESULT_DATA)) && asJsonObject.get(UrlManager.ResultTypes.RESULT_DATA).isJsonArray()) {
return Observable.just(WeekDietPlan.PackageDietWeekDaysListParser.fromJsonElement(asJsonObject.getAsJsonArray(UrlManager.ResultTypes.RESULT_DATA)));
} else {
return Observable.error(new Exception("Data is empty"));
}
}
if (UrlManager.ResultTypes.isLogin(result)) {
return Observable.error(new SessionTimeoutException());
}
return Observable.error(new Exception("Unkown Tag"));
}
})
.observeOn(AndroidSchedulers.mainThread());
}
my api call :
private void retrievePackageWeekDaysPlan() {
hideConnectionErrorLayout();
if (!swipRefreshLayout_reLoad.isRefreshing()) {
swipRefreshLayout_reLoad.setRefreshing(true);
}
DietNetworkCall.fetchPackageWeeksDaysDietPlan(1).subscribe(new Observer<List<WeekDietPlan>>() {
#Override
public void onSubscribe(Disposable d) {
Timber.d(TAG, "onSubscribe() called with: d = [" + d + "]");
compositeSubscription.add(d);
}
#Override
public void onNext(List<WeekDietPlan> list) {
Timber.d(TAG, "onNext() called with: value = [" + list.size() + "]");
swipRefreshLayout_reLoad.setRefreshing(false);
hideConnectionErrorLayout();
if (list.size() == 0)
{
Toast.makeText(getContext(), R.string.noDietPackageAvailable, Toast.LENGTH_SHORT).show();
}
bindRecyclerData(list);
}
#Override
public void onError(Throwable e) {
e.printStackTrace();
Timber.d(TAG, "onError() called with: e = [" + e + "]");
swipRefreshLayout_reLoad.setRefreshing(false);
if (e instanceof IOException) {
Toast.makeText(getContext(), R.string.connectionError, Toast.LENGTH_SHORT).show();
} else if (e instanceof NullPointerException) {
} else if (e instanceof SessionTimeoutException) {
AuthenticationManager.logOut();
} else {
Toast.makeText(getContext(),
e.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
#Override
public void onComplete() {
Log.d(TAG, "onComplete() called");
}
});
}
I know this is late, and directed towards future folks.
There is a need to create a Network Interceptor like this
public abstract class NetworkConnectionInterceptor implements Interceptor {
public abstract boolean isInternetAvailable();
public abstract void onInternetUnavailable();
public abstract void onCacheUnavailable();
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (!isInternetAvailable()) {
onInternetUnavailable();
request = request.newBuilder().header("Cache-Control",
"public, only-if-cached, max-stale=" + 60 * 60 * 24).build();
Response response = chain.proceed(request);
if (response.cacheResponse() == null) {
onCacheUnavailable();
}
return response;
}
return chain.proceed(request);
}
}
Then add it with your okhttp builder. You can refer to this link.
One more you should take care is to check your response "Cache-control" header. Its value has to be like this "max-age=2592000".
To return the cached data instead of the error, you could use the onErrorReturn operator that:
Instructs an Observable to emit an item (returned by a specified
function) rather than invoking onError if it encounters an error.
List of the different operators to recover on error: https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
I need to post a message to server.
- MediaType : application/x-www-form-urlencoded
So, I used FormEncodingBuilder class for making body.
I wrote this code.
Uri.Builder uri = new Uri.Builder()
.scheme(SCHEME)
.encodedAuthority(HOST)
.appendPath("v3")
.appendPath("svc")
.appendPath("auth");
FormEncodingBUilderformBody = new FormEncodingBUilder()
.add("name", data.getName())
.add("gender", data.getGender())
.build();
Request request = new Request.Builder()
.url(uri.build().toString())
.post(formBody)
.build();
try {
Response response = mHttpClient.newCall(request).execute();
String body = response.body().string();
return body;
} catch (Exception e) {
throw new ApiException(0, e.toString());
}
but server didn't read parameter.
So, server request parameter's value.
How do I make message?
Maybe you need to set charset.
but FormEncodingBuilder class use only MediaType "application/x-www-form-urlencoded".
So, you can make new class like FormEncodingBuilder.
public class OkHttpFormBuilder {
private MediaType CONTENT_TYPE = MediaType.parse("application/x-www-form-urlencoded;charset=utf-8");
private final StringBuilder content = new StringBuilder();
public OkHttpFormBuilder() {
}
public MediaType getCONTENT_TYPE() {
return CONTENT_TYPE;
}
public void setCONTENT_TYPE(MediaType CONTENT_TYPE) {
this.CONTENT_TYPE = CONTENT_TYPE;
}
public OkHttpFormBuilder add(String name, String value) {
if(this.content.length() > 0) {
this.content.append('&');
}
try {
this.content.append(URLEncoder.encode(name, "UTF-8")).append('=').append(URLEncoder.encode(value, "UTF-8"));
return this;
} catch (UnsupportedEncodingException var4) {
throw new AssertionError(var4);
}
}
public String getContent()
{
return this.content.toString();
}
public RequestBody build() {
if(this.content.length() == 0) {
throw new IllegalStateException("Form encoded body must have at least one part.");
} else {
byte[] contentBytes = this.content.toString().getBytes(Util.UTF_8);
return RequestBody.create(CONTENT_TYPE, contentBytes);
}
}}
After you make formbody using this class, try send to server
I tried to use this Android Picasso library, How to add authentication headers? to access a protected image that returns the base64 version of the image. My problem is that the picasso always failed. and I don't know why. the authorization code is valid since the profile details are loaded. only the image was not. Here is my implementation how to get the image.
public class PicaAuth {
private static Picasso sPicasso;
private PicaAuth() {
}
public static Picasso getImageLoader(final Context context) {
if (sPicasso == null) {
Picasso.Builder builder = new Picasso.Builder(context);
builder.downloader(new CustomOkHttpDownloader(context));
sPicasso = builder.build();
}
return sPicasso;
}
private static class CustomOkHttpDownloader extends OkHttpDownloader {
public CustomOkHttpDownloader(Context context) {
super(context);
}
#Override
protected HttpURLConnection openConnection(final Uri uri) throws IOException {
HttpURLConnection connection = super.openConnection(uri);
connection.setRequestProperty("Authorization", Auth.getBearerAccessToken());
return connection;
}
}
}
Main Activity
PicaAuth.getImageLoader(MainActivity.this)
.load(uri)
.into(mImage, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
Log.d("Image Success");
}
#Override
public void onError() {
Log.e("Image Failed");
}
});
You need to intercept the answer and change it
OkHttpClient client;
OkHttpClient.Builder builderOkHttpClient;
builderOkHttpClient = new OkHttpClient.Builder();
builderOkHttpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.build();
Response response = chain.proceed(newRequest);
try {
MediaType contentType = response.body().contentType();
String base64String = response.body().string().getBytes("UTF-8");
base64String = base64String .replace("data:image/jpeg;base64,", "");
byte[] decodedString = Base64.decode(base64String , Base64.DEFAULT);
ResponseBody body = ResponseBody.create(contentType, decodedString);
response = response.newBuilder().body(body).build();
} catch (JSONException e) {
e.printStackTrace();
}
return response;
}
});
int cacheSize = 10 * 1024 * 1024;
Cache cache = new Cache(context.getCacheDir(), cacheSize);
builderOkHttpClient.cache(cache);
client = builderOkHttpClient.build();
Application.getAppComponent().inject(this);
picasso = new Picasso.Builder(context)
.downloader(new OkHttp3Downloader(client))
.loggingEnabled(true)
.indicatorsEnabled(true)
.listener(new Picasso.Listener() {
#Override
public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
Log.e("PICASSO", "loading image " + uri);
Log.e("PICASSO ERROR", exception.getMessage());
}
}
).build();
Above answer works great. Then if the base 64 encoded image is further stored inside a JSON Object.
String jsonData = response.body().string();
JSONObject Jobject = new JSONObject(jsonData);
String base64String = (String) Jobject.get("ImageData");
I have added volley for request to get Json object, If wifi is turned on then it takes data but does not get in case of offline mode even cache is enabled for the request.
I do the following code
public class VolleySingleton extends Application
{
public static final String TAG = VolleySingleton.class.getSimpleName();
private RequestQueue mRequestQueue;
private static VolleySingleton mInstance;
private ImageLoader mImageLoader;
private final String DEFAULT_CACHE_DIR = "sl_cache";
#Override
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
}
#Override
public void onCreate()
{
super.onCreate();
mInstance = this;
}
public static synchronized VolleySingleton getInstance()
{
return mInstance;
}
public ImageLoader getImageLoader()
{
getRequestQueue();
if (mImageLoader == null)
{
mImageLoader = new ImageLoader(this.mRequestQueue, new LruBitmapCache());
}
return this.mImageLoader;
}
public <T> void addToRequestQueue(Request<T> req, String tag)
{
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
public <T> void addToRequestQueue(Request<T> req)
{
req.setTag(TAG);
getRequestQueue().add(req);
}
public void cancelPendingRequests(Object tag)
{
if (mRequestQueue != null)
{
mRequestQueue.cancelAll(tag);
}
}
public RequestQueue getRequestQueue()
{
if (mRequestQueue == null)
{
Cache cache = new DiskBasedCache(getCacheDir(), 1024 * 1024 * 10); // 10MB cap
Network network = new BasicNetwork(new HurlStack());
mRequestQueue = new RequestQueue(cache, network);
mRequestQueue.start();
}
return mRequestQueue;
}
}
private void getData(String url, String tag)
{
final JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>()
{
#Override
public void onResponse(JSONObject response)
{
Log.wtf("HOME", response.toString());
String result = parseData(response.toString());
postProcessing(result);
//SocialLadder.getInstance().getRequestQueue().getCache().invalidate(url, true);
}
}, new Response.ErrorListener()
{
#Override
public void onErrorResponse(VolleyError error)
{
VolleyLog.wtf("HOME", "Error: " + error.getMessage());
stopRefresher();
}
})
{
#Override
protected Response<JSONObject> parseNetworkResponse(NetworkResponse response)
{
try
{
String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
return !jsonString.isEmpty() ? Response.success(new JSONObject(jsonString), HttpHeaderParser.parseCacheHeaders(response)) : Response.success(new JSONObject(), HttpHeaderParser.parseCacheHeaders(response));
}
catch (JSONException ex)
{
ex.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return null;
}
};
jsonObjReq.setShouldCache(true);
VolleySingleton.getInstance().addToRequestQueue(jsonObjReq, tag);
}
Please help, I want to cache my screen data.
Edit
Cache Data
private String getCache(String url)
{
String data = "";
Cache cache = VolleySingleton.getInstance().getRequestQueue().getCache();
Cache.Entry entry = cache.get(url);
if (entry != null)
{
try
{
data = new String(entry.data, "UTF-8");
// handle data, like converting it to xml, json, bitmap etc.,
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
/*else
{
// Cached response doesn't exists. Make network call here
}*/
return data;
}
Just add this line in **BasicNetwork* class or modify it as follow
#Override
public NetworkResponse performRequest(Request<?> request) throws VolleyError {
long requestStart = SystemClock.elapsedRealtime();
while (true) {
HttpResponse httpResponse = null;
byte[] responseContents = null;
Map<String, String> responseHeaders = Collections.emptyMap();
try {
if(!ConnectivityUtils.isNetworkEnabled(BBApplication.getContext())) {
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,
request.getCacheEntry().data, responseHeaders, true);
}
// Gather headers.
Map<String, String> headers = new HashMap<String, String>();
addCacheHeaders(headers, request.getCacheEntry());
httpResponse = mHttpStack.performRequest(request, headers);
StatusLine statusLine = httpResponse.getStatusLine();
int statusCode = statusLine.getStatusCode();
responseHeaders = convertHeaders(httpResponse.getAllHeaders());
// Handle cache validation.
if (statusCode == HttpStatus.SC_NOT_MODIFIED) {
Cache.Entry entry = request.getCacheEntry();
if (entry == null) {
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
}
// A HTTP 304 response does not have all header fields. We
// have to use the header fields from the cache entry plus
// the new ones from the response.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
entry.responseHeaders.putAll(responseHeaders);
return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, entry.responseHeaders, true, SystemClock.elapsedRealtime() - requestStart);
}
// Some responses such as 204s do not have content. We must check.
if (httpResponse.getEntity() != null) {
responseContents = entityToBytes(httpResponse.getEntity());
} else {
// Add 0 byte response as a way of honestly representing a
// no-content request.
responseContents = new byte[0];
}
// if the request is slow, log it.
long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
logSlowRequests(requestLifetime, request, responseContents, statusLine);
if (statusCode < 200 || statusCode > 299) {
throw new IOException();
}
return new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
} catch (SocketTimeoutException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (ConnectTimeoutException e) {
attemptRetryOnException("connection", request, new TimeoutError());
} catch (NoHttpResponseException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (UnknownHostException e) {
attemptRetryOnException("socket", request, new TimeoutError());
} catch (MalformedURLException e) {
throw new RuntimeException("Bad URL " + request.getUrl(), e);
} catch (IOException e) {
int statusCode = 0;
NetworkResponse networkResponse = null;
if (httpResponse != null) {
statusCode = httpResponse.getStatusLine().getStatusCode();
} else {
throw new NoConnectionError(e);
}
VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
if (responseContents != null) {
networkResponse = new NetworkResponse(statusCode, responseContents, responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
attemptRetryOnException("auth", request, new AuthFailureError(networkResponse));
} else {
// TODO: Only throw ServerError for 5xx status codes.
throw new ServerError(networkResponse);
}
} else {
throw new NetworkError(networkResponse);
}
}
}
}
and for data request expiry you can change the Cached.Entry using using own HttpHeaderParser
Click for BasicNetwork
What is this code will do it will check for internet connection and Network call and revert if it has cached copy .
Note The API response should be cache-able because Volley only cache data if Response Header permits . See here for Cached Control Header
In order to cache anything with Volley you need to have two things:
1) server allows you to cache it. it usually appears in a cache control tag in the HTTP header.
2) you save it or in this scenario you tell the Volly to save.
so i think your problem is in number one. that means the server dose not allow you to cache those files, in order to confirm my answer you can do one of these things:
download this plug in (RESTClient) for mozilla and send your request and check the header file for cache control. if the server dose not allow you to cache you will see something like below image, notice cache control tag
set break point in headerValue = headers.get("Cache-Control"); at HttpHeaderParse class and see whats going on when Volley wants to parse the cache control tag.