I'm developing an App on which I have plenty of ListViews. On each ListView Item, there is a picture. In order to load the pictures from the server taking in consideration:
Basic Authentication.
SSL certification.
I would like to know what is the best way to do that. I've try to make a recursive method which uses ImageRequest from Volley Library but it seems like it is a little bit blocking the UI Thread...
I've tried Picasso also which allows to load asynchronously pictures thanks to an association between the ImageView and the request by couldn't make it work with Basic Authentication and by ignoring SSL Certification.
Here is my not solved problem
I'm looking for some other solutions... So If someone has an idea, would be really appreciated...
Thanks in advance !
Picasso is a god solution. To add a custom header just use your own downloader.
OkHttpClient picassoClient = client.clone();
picassoClient.interceptors().add(new MyInterceptor());
// ...
new Picasso.Builder(context).downloader(new OkHttpDownloader(picassoClient)).build();
Read about that in this issue: https://github.com/square/picasso/issues/900
You can also user Fresco (https://github.com/facebook/fresco) with OkHttp: http://frescolib.org/docs/using-other-network-layers.html
Context context;
OkHttpClient okHttpClient; // build on your own
ImagePipelineConfig config = OkHttpImagePipelineConfigFactory
.newBuilder(context, okHttpClient)
. // other setters
. // setNetworkFetcher is already called for you
.build();
Fresco.initialize(context, config);
Related
I'm using Fresco library to display images in my Android app. I'd like to display some images (jpg or png) that I have set with public grants.
When I was doing quick tests, I just took any image from internet to set a URL, but when using the real ones that I need to use, I have the following url https://drive.google.com/uc?export=view&id=<>, but as it is a redirect and, once redirected, new url is not the image itself, Fresco is unable to display it.
I have tried Picasso as an alternative library, but with out any success.
I have also tried the download url for both libraries (https://drive.google.com/uc?export=download&id=<>). But no result.
Anybody knows how could it be possible to get this images? Or the only solution is to download it (using the second url) processing the object received store a bitmap of it and displaying it?
For downloading it, what should i use and how? retrofit?
Thanks in advance.
Fresco supports different network stacks. For example, you can use OkHttp with Fresco, which should follow redirects or modify the default one to allow redirects - or write your own based on them.
Guide for OkHttp: http://frescolib.org/docs/using-other-network-layers.html
Related GitHub issue: https://github.com/facebook/fresco/issues/61
I found a solution for this problem (but could be only applicable if you use Google Cloud or Google Script).
It consists on creating a doGet() service with the following code inside:
var file = DriveApp.getFileById(fileId)
return Utilities.base64Encode(file.getBlob().getBytes());
and use that base64 value in your app. With this format, Fresco can do the magic
It is not an immediate solution, and requires to do somework in other platform that is not your Android app, but it works perfectly.
Are you sure that there is no problems with your URLs?
Picasso works with direct URLs like: https://kudago.com/media/images/place/06/66/06662fda6309ce1ee9116d13bd1c66d5.jpg
Then you can download your image like:
Picasso.with(this)
.load(url)
.noFade()
.placeholder(R.drawable.placeholder_grey) //if you want to use a stub
.into(imageView, new com.squareup.picasso.Callback() {
#Override
public void onSuccess() {
//here you can operate with image after it is downloaded
}
#Override
public void onError() {
}
});
Hope it will help you.
I am working on an app with a lot of dynamic and changing content.
I pull all my data from my server when the app is loading.
As a result, nearly every activity/fragment is loading separately which will cause the user to wait a lot of time for each "page" to load individually.
My goal is to create one loading page when the app starts while being responssible for all the downloading and will disk cache all the images and info(strings) and ti pull them at the right time. (or at least to most of it)
I had the chance to use retrofit, okhttp and Picasso as a single additional library, I know though that they can work together and to be synced and that disk cacheing is available through at least two of this libraries (picasso and okhttp) I'm not sure though which one should do which part and how I can sync them together.
I will appreciate every Tip/Guidance, thanks ahead.
okhttp provides support for cache control headers. I've implemented them in an app before to provide a cache when network is flaky using this guide like so:
int cacheSize = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(cacheDirectory, cacheSize);
client = new OkHttpClient.Builder()
.cache(cache)
.build();
As Retrofit uses okhttp internally (if you're using the latest at least), you don't configure any caching for it. Just use the okhttp client you just configured:
RestAdapter restAdapter = new RestAdapter.Builder()
.setClient(new OkClient(client))
.setServer("http://example.com")
...
.build();
Picasso automatically caches images using some default cache size limit. You can change Picasso's default, and I've found some answers here and here. You could set the cache size in the onCreate of your application:
Picasso.Builder builder = new Picasso.Builder(this);
builder.downloader(new OkHttpDownloader(this,Integer.MAX_VALUE));
Picasso picasso = builder.build();
picasso.setIndicatorsEnabled(true);
picasso.setLoggingEnabled(true);
Picasso.setSingletonInstance(picasso);
Picasso also lets you prefetch images earlier on in an app's lifecycle if you have the time to begin with (say, on a loading screen) and want to make later parts of the app load quicker. To do that, I would use the fetch method from the Picasso builder to get the images, but not insert them into any ImageViews. You can Google it too, but there's a quick answer here which explains the background behind this:
Picasso.with(getApplicationContext())
.load(url)
.fetch();
IIRC you need to make sure you fetch the same sized and transformed image as you try and retrieve later, because Picasso caches the transformed image result rather than the raw downloaded image.
Hi I'm trying to understand how to use the Picasso library to cache my downloaded images, so I created a very simple app with one activity, put an ImageView on it and wrote the simplest Picasso line:
Picasso.with(this).load("http://www.estambiente.it/wp-content/uploads/2009/12/Patern_test.jpg")
.placeholder(R.drawable.holder)
.error(R.drawable.error)
.into(im);
but I wanted to see the cache indicators, so I wrote this to show them:
OkHttpClient picassoClient = new OkHttpClient();
Picasso picasso = new Picasso.Builder(this).downloader(new OkHttpDownloader(picassoClient)).build();
picasso.setIndicatorsEnabled(true);
picasso.load("http://www.estambiente.it/wp-content/uploads/2009/12/Patern_test.jpg").into(im);
this code always show the red flag (meaning the image comes from the network) and if I try to open the app while I'm not connected, the error image is shown.
what am I missing here?
I have been trying to use Fresco library by Facebook.
From the documentation I understood that the caching of images works out of the box with the ImagePipelines when we use the SimpleDraweeView. I pretty much see things working perfectly only with the minor hiccup that eventhough Fresco fetches images from my URI the images in the DiskCache and other Caches are not replaced by it.
I'm positive about my code fetching the images because my images do show up the first time I run the app after I clear the cache and I implemented a RequestListener and a ControllerListener which both turned up success.
Here is my current setup:
// Setting the collaborator image.
GenericDraweeHierarchy collaboratorPicHierarchy =
genericDraweeHierarchyBuilder
.setPlaceholderImage(
getInitialsAsDrawable(
collaborator.getUser().getInitials()
)
)
.setRoundingParams(new RoundingParams()
.setRoundAsCircle(true)
)
.build();
holder.collaborator.setHierarchy(collaboratorPicHierarchy);
holder.collaborator.setImageURI(
Uri.parse(AltEngine.formURL("user/getProfilePic/") +
accessToken + "/" +
collaborator.getUser().getUuid()
)
);
All this code lies inside an Adapter and in the Adapter's constructor I have initialized Fresco.
imagePipelineConfig = ImagePipelineConfig.newBuilder(this.context)
.build();
Fresco.initialize(this.context, imagePipelineConfig);
After a lot of searching in StackOverflow I found that the following Snippet could be used.
Fresco.getImagePipelineFactory().getMainDiskStorageCache().remove(new SimpleCacheKey(uri.toString()));
Fresco.getImagePipelineFactory().getSmallImageDiskStorageCache().remove(new SimpleCacheKey(uri.toString()));
I tried that in the onRequestSuccess of ImageRequest instance which I associated with the SimpleDraweeView but that resulted in the placeholder being shown everytime I refresh the ListView which is bad.
The next solution I found was from here Android - How to get image file from Fresco disk cache? which suggested that it might be necessary to implement my own DiskCacheConfig for Fresco to invalidate my DiskCache so I tried configured my DiskCache with the code I found in the SO question.
DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder().setBaseDirectoryPath(this.context.getCacheDir())
.setBaseDirectoryName("v1")
.setMaxCacheSize(100 * ByteConstants.MB)
.setMaxCacheSizeOnLowDiskSpace(10 * ByteConstants.MB)
.setMaxCacheSizeOnVeryLowDiskSpace(5 * ByteConstants.MB)
.setVersion(1)
.build();
imagePipelineConfig = ImagePipelineConfig.newBuilder(this.context)
.setMainDiskCacheConfig(diskCacheConfig)
.build();
Fresco.initialize(this.context, imagePipelineConfig);
Still the Cache is not updated by the image from the network.
I dont know what has gone wrong here. May be I've got Fresco wrong altogether. Any how I am stuck here and dont have a clue on how to proceed. I have been through the docs a couple of times and due to my hard luck I might have missed something important. Please point me in a proper direction.
This is basically the same question as was asked here: https://github.com/facebook/fresco/issues/124.
And in fact, you had about the right idea in the two lines you pasted above with the removal from disk cache. You just need to call them in the right place. onRequestSuccess is not the right place since that will nuke the image you just downloaded.
You want to remove the old entry from cache before even sending out a request for a new one. If Fresco finds the image on disk, it won't even send out a network request.
There is a handy com.android.volley.NetworkImageView widget extending ImageView. According to a Google presentation, to use it one needs only this in the layout xml file:
<com.android.volley.toolbox.NetworkImageView
and this in the Activity source code:
mImageView.setImageUrl(imageUrl, mImageLoader);
But what if I need to put a cookie or parameter into the request? I've seen this question, but I think this requires modifying volley library. Is there an easier way?
Here you can find a project with different simple examples about using Volley including using cookies and GET/POST parameters.
The proposed solution by Ogre_BGR is not a proper one as he is using Apache's HTTP client. And volley uses Apache's HTTP client only on API 8 and lower as there it is less buggy than URLConnection. But since Gingerbread (2.3) it is recommended to use URLConnection and it is the one that Android's team is maintaining and updating.
I think that a better solution is the one that you've given a link to. It does not modify Volley, it just adds/saves cookies to the ones that Volley already uses. And it is a common thing to extend some of the *Request classes of Volley for quick and easy call of API requests ( see here ). Ogre_BGR's solution completely changes the HttpStack of Volley.
You need to set you xml layout file to
<com.android.volley.toolbox.NetworkImageView...
You are missing "toolbox" in your class name.
As for the cookies, what I did to keep using URLConnetion (which is the default use case for Volley on API > 8) is to implement a custom class that extends HurlStack (Volley's implementation of an HTTP client using URLConnection), and overriding createConnection(URL url), which is the method used to get a connection prior to every request.
I just added my user agent (none is send by default, using HurlStack), and a cookie (also, isn't managed automatically in HurlStack).
Here's my code for the class:
public class CustomHurlStack extends HurlStack {
public CustomHurlStack() {
super();
}
#Override
protected HttpURLConnection createConnection(URL url) throws IOException {
// Create a connection with custom attributes
HttpURLConnection conn = super.createConnection(url);
conn.addRequestProperty("User-Agent", "myUserAgent/1.0");
conn.addRequestProperty("cookie", "myCookie");
return conn;
}
}
This should be a viable solution, and I'm not sure why Volley doesn't include such a configurable class to use, but oh well, you can create your own in just a minute or so, as described above.
private static RequestQueue mQueue;
String userAgent = "volley/0";
HttpStack stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
mQueue = Volley.newRequestQueue(this, stack, 100 * 1024 * 1024);