Android: Downloading 1k+ images using Glide - android

I'm currently trying to create an image "player" to show a person's drive. The drives are recorded and stored as images, split as 1 image per second.
I'm pulling the images using Glide. However, as you can imagine, there are a lot of images - thousands of them. My first idea was to download the images using the downloadOnly option of Glide, and use a Discrete Seekbar, and as the images are getting downloaded, then increase the max of the Seekbar. The problem with the approach, is that it takes a long time.
This is what I currently have to download the images:
private void downloadOnlyImages(List<String> URLs){
totalImages = 0;
for(final String url: URLs){
Glide.with(this)
.load(url)
.downloadOnly(new SimpleTarget<File>() {
#Override
public void onResourceReady(File resource, GlideAnimation<? super File> glideAnimation) {
Log.i("glide", "image downloaded" + url);
mySeekBar.setMax(totalImages++);
}
});
}
}
and this is what I'm currently using with the seekbar:
mySeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
Glide.with(getActivity())
.load(URLs.get(progress))
.fitCenter()
.dontAnimate()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);
}
The idea was, download the images, and then use the seekbar to move through them, always replacing the same ImageView with the next image. Using Glide's cache, I'm trying to check if it's in cache then pull that image if not then fetch using the URL. But, this hold up the UI Thread, which is causing the delay.
TLDR: I want to be able to be able to use a seekbar as a "player" for thousand of images that I'm pulling using Glide. However, it's very laggy using my naive approach. Trying to think of a more effective and efficient way to pull the images, in a more "lazy loading" way.

Related

Efficient way to load large number of same image in ReyclerView

I developed a chat app. It uses RecyclerView to show chat info. It's exactly like facebook messenger.
My problem is, loading the image of user I'm chatting to takes time, and make the app slow when there's large number of chat messages.
I'm using picasso to load image.
Picasso.get()
.load("https://domain/images/profile_picture/" + otherImage)
.networkPolicy(NetworkPolicy.OFFLINE)
.transform(new CircleTransform())
.into(imageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
int placeHo;
if(otherGender.equals("female"))
placeHo = R.drawable.ic_female_color;
else
placeHo = R.drawable.ic_male_color;
Picasso.get()
.load("https://domain/images/profile_picture/" + otherImage)
.error(placeHo)
.transform(new CircleTransform())
.centerCrop(Gravity.TOP)
.into(imageView, new Callback() {
#Override
public void onSuccess() {
}
#Override
public void onError(Exception e) {
Log.v("Picasso","Could not fetch image");
}
});
}
});
Is there any efficient way to show the image? as it's showing the same image(user profile picture).
I can think only one reason that your RecyclerView is lagging. Because your image size is large.
See, if your chat image is about 50-100dp then you should use the same resolution image. Perhaps you are loading original image.
AFAIK I use Glide over Picasso because Glide optimize the downloaded image, as ImageView size.
See Glide doc
Glide's primary focus is on making scrolling any kind of a list of
images as smooth and fast as possible, but Glide is also effective for
almost any case where you need to fetch, resize, and display a remote
image.
You don't need to worry about cache in Picasso and Glide both. Cache is enabled by default in Picasso, so if same image is queried again, then it will be picked from cache.
Solution 1 (using Piccaso)
Resize image as much you need.
Picasso
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.resize(100, 100) // resizes the image to these dimensions (in pixel). does not respect aspect ratio
.into(imageViewResize);
Solution 2 (Using Glide)
You need not to worry about anything, you are good to go if you use Glide.
keep it Static
Or You can set it at the time of initialisation
not changing it every time on viewholder
sorry for my english and format of writing
If you are using the same image in all the Views of the same viewType then load the image in onCreateViewHolder method of the adapter and not in onBindViewHolder.
The same View with the image already loaded will be recycled (reused) and not loaded again and again, the result will be for sure faster.
You have to postpone the first image retrieve procedure at when the RecyclerView.OnChildAttachStateChangeListener() event signals that a child is added. Obliviously the Event is triggered for each of firsts visible items. The most correct way to postpone something like this is to create an Handler and then send/enqueue a Handler.sendMessage(Message.obtain(..)) one for each visible objects) items. Inside the Handler you will receive that Message and there you can execute the Picasso action.
Then you have to decide if load other (the not yet visible items) images all at once or just prepare the picture only when it is required by the Recycler.

Long display time for pictures using Glide

I am doing an API request to Imgur using Retrofit in order to retrieve about 40 URLs and then display them in a RecyclerView using Glide like such:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
Glide
.with(context)
.load(list.get(position).getLink()) // Gets the URL in my list
.centerCrop()
.placeholder(R.mipmap.placeholder)
.crossFade()
.into(holder.imageView);
}
The request gets answered quickly, but most of my images stay as placeholders as some of them appear one by one later on.
What is causing this delay in the display of my images? Is it perhaps linked to the speed of my Internet connection?
Additionally is my approach a correct one when it comes to "large" amounts of pictures?
Please note that most ImageViews do not load, even the ones that are visible to my user.
This might be depending on your internet connection. If so, you can use imgur smaller sizes, you can add one of those letter at the end of your filename:
s = Small Square (90×90)
b = Big Square (160×160)
t = Small Thumbnail (160×160)
m = Medium Thumbnail (320×320)
l = Large Thumbnail (640×640)
h = Huge Thumbnail (1024×1024)
i.e. this:
http://i.imgur.com/bF8zPs4.jpg
becomes this (for the small square):
http://i.imgur.com/bF8zPs4s.jpg
Once you've set the url for the image in Glide, the image itself still needs to be downloaded and shown in the ImageView, which is causing the delay. If the images are not loading, can you check if the image url loads the image in your browser for example?
A better approach to load images in an adapter with Glide is to use a RequestManager which you pass in the constructor of your adapter. Glide will then subscribe to the lifecycle of your activity of fragment. This will prevent images from being downloaded when your activity of fragment has been destroyed, which is especially useful when Glide has to download large images.
public MyAdapter(List<Object> items, RequestManager requestManager) {
this.items = items;
this.requestManager = requestManager;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
requestManager
.load(list.get(position).getLink()) // Gets the URL in my list
.centerCrop()
.placeholder(R.mipmap.placeholder)
.crossFade()
.into(holder.imageView);
}
And then you can call the constructor of your adapter in an acitivty or a fragment as such:
MyAdapter myAdapter = new MyAdapter(items, Glide.with(this));
I've been using this approach after I've found this answer from TWiStErRob.
it is depend on your internet connection speed and the size of images.
if the size of images it to large,it may cause of of Memory exception.
In Recyclerview, Glide only loads images in visible imageViews. ImageViews that are not visible will be loaded once you scrolldown. This is due to recycler property of RecyclerView.
Add following line in you onBindViewHolder and see the logs, you will understand it:
Log.w("Link", list.get(position).getLink());

Where do images need to be stored in and Android app?

I've been reading quite a lot on the topic, still not quite clear though. At the moment I'm creating an app, loading an image and a text on one screen. For loading the images I opted for Glide, but where is the most appropriate place to read them from? All of the tutorials I passed pass the image's URL. Isn't it slower when loaded from the net? Thanks a lot!
If you care for apk size then do not put these images static. Instead you can keep these images on server(your or free server) and easily load those images using libraries like Glide or Picasso.
Isn't it slower when loaded from the net?
No. It will download image once and then cache it for future use. So it's very fast.
If you think apk size will doesn't matter for you and user should not face problem due to unavailability of internet then you can keep those images static inside app iteself.
If you want to build an app that uses dynamic images or you want to update your images without updating your application, getting them from the server is better. And in my opition picasso is easy to use and straightforward. Also uses it's own framework caching. But if you think that your images wont change, put them in an asset folder so that they are in app's internal memory. Getting them from the server has it's downsides like you need to use a placeholder images because they won't be retrieved immediately.
You must use caching mechanisms if you want the images always from network. The system I follow is like this: (PS. I use Picasso, fast and reliable):
Picasso.with(this).load(URL).networkPolicy(NetworkPolicy.OFFLINE). //load from cache first time
into(imageView, new Callback() { //Picasso Callback
#Override
public void onSuccess() {
if(isNetworkAvailable()) { // if network available then update the cache for this URL
Picasso.with(MyActivity.this).invalidate(URL);
}
progress.setVisibility(View.GONE); // Progressbar
}
#Override
public void onError() { // Image not loaded, try again one last time
Picasso.with(MyActivity.this).load(URL).into(imageView, new Callback() {
#Override
public void onSuccess() {
progress.setVisibility(View.GONE);
}
#Override
public void onError() {
progress.setVisibility(View.GONE);
}
});
}
});

what is the best to download images data from network in android

i am downloading (pref-etch) images from server at some time of interval
so i wanted to know what is the best way to download images
asyntask
service
intentservice
please help
Case 1: If you have to download very few images (like one or two in an activity) from Internet, then use Asynctask .
Case 2: If you have to download many images specially for ListView items , you must have to implement it in a dedicated background thread by using HandlerThread, Handler , message and Looper in Android. Avoid using a service here. Also, you have to implement image caching as you dont want to download the same image multiple times in a session.
Advice: If the second is your case, don't implement the above by yourself. Save your time and use some awesome, efficient and fast libraries used by millions of Android apps.
You can use:
Picasso by Square
Glide
Volley
Edit: How to use Picasso for downloading images.
All the above mentioned libraries can do that beautifully. I am sharing the solution with Picasso.
Picasso.with(mContext).load("url").into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
//save the bitmap into permanent storage or do whatever you want like showing in some ImageView etc.
}
#Override
public void onBitmapFailed(Drawable drawable) {
}
#Override
public void onPrepareLoad(Drawable drawable) {
}
});
Hope this helps. If still have any issue , please feel free to comment.

Glide caching off screen images in memory

I want to load and cache images only in memory and not pass them to a view and later on when I need them to be loaded on the UI to get them from memory cache if they existed in memory.
I tried:
Glide.with().load(uri).into(new SimpleTarget<GlideDrawable>(WIDTH,HEIGHT)
{
#Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation) {
//left empty
}
}
);
But when later on I make the call to load that uri in an ImageView it will still load it from the path and not memory.
Is there another way to have images cached in memory without loading them on the UI?
Documentation on how to cache images on background thread can be found here.
Here is some example code from the page showing how a file would be downloaded to cache, without displaying the image in the UI:
FutureTarget<File> future = Glide.with(applicationContext)
.load(yourUrl)
.downloadOnly(500, 500);
// Can be omitted if you only want to have the data cached (same goes for the "future" instance variable
File cacheFile = future.get();
However, make sure you have configured Glide such that caching is enabled: https://github.com/bumptech/glide/wiki/Configuration
Actually I found the preload method in API for this exact purpose:
preload API change log

Categories

Resources