Load placeholder images using Glide - Android - android

I have a ViewPager, which uses a custom adapter. The items are cards with header text (TextView title), some text below the header (TextView desc), and ImageView above them. Images are loaded from DB via Glide library. And it works, the images are loaded successfully, but while loading the image for the first time, the card is shown empty - even without text. Is there a way to show this card with the text and some background image in ImageView while the image from DB is loading?
Sorry, if my question looks silly, I'm working with Glide for the first time.
ViewPager adapter's code:
#NonNull
#Override
public Object instantiateItem(#NonNull ViewGroup container, final int position) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
// init root view (our 'card')
View view = layoutInflater.inflate(R.layout.vp_item, container, false);
// some code..
title.setText( events.get(position).getTitle() );
desc.setText( events.get(position).getDesc() );
// filling UI elements with data
Glide.with(context)
.load(events.get(position).getImageUrl())
.apply(new RequestOptions().override(800, 600))
.transition(DrawableTransitionOptions.withCrossFade())
.into(imageView);
// some code..
container.addView(view, 0);
return view;
}

You need to use the placeholder function which is provided by Glide as following:
Glide.with(context)
.load(events.get(position).getImageUrl())
.placeholder(R.drawable.placeholder_image) /// add this
.apply(new RequestOptions().override(800, 600))
.transition(DrawableTransitionOptions.withCrossFade())
.into(imageView);

Related

how to put array of download URLs of images to viewpager

I made a view pager with an image view inside it, and I want to make something like an image slider using the view pager. I have an array of download URLs. how can i put those URLs to open the image to the image view. I tried searching for other tutorials but they all use bitmaps.
Use Global Array to store URLs and than display using GLide Like>>>
#Override
public Object instantiateItem(ViewGroup container, final int position) {
layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View view = layoutInflater.inflate(R.layout.image_fullscreen_preview, container, false);
ImageView imageViewPreview = (ImageView) view.findViewById(R.id.image_preview);
final ProgressBar pbLoad = view.findViewById(R.id.pbLoad);
String image = images.get(position);
imageViewPreview.setTag(image);
Glide.with(getActivity()).load(image).thumbnail(0.5f).crossFade().diskCacheStrategy(DiskCacheStrategy.ALL).into(imageViewPreview);
container.addView(view);
return view;
}

Loading Gridview is choppy

I am trying to load a gridview with cards that hold product information.
I'm not sure if this is the best way of handling this sort of data loading.
First i'm setting my adapter:
cardView.setAdapter(new productCardAdapter(getActivity(),products));
Products is a object that holds a product object, inside the product object has values like image,name,price, etc..
in my public class productCardAdapter extends BaseAdapter
I set the products
this.products = products;
then in the
public View getView(int i, View view, ViewGroup viewGroup) {
I am setting the values based off the index i
if(view == null){
// CREATE NEW
view = inflater.inflate(R.layout.product_card,null);
// GET CURRENT PRODUCT
Products.Product product = products.products.get(i);
// CREATE WIDGETS
TextView cardTitle = (TextView)view.findViewById(R.id.txtProductName);
ImageView cardImage = (ImageView)view.findViewById(R.id.imgProductImage);
CardView card = (CardView)view.findViewById(R.id.tmpCard);
TextView cardSKU = (TextView)view.findViewById(R.id.txtProductSKU);
TextView cardPrice = (TextView)view.findViewById(R.id.txtProductPrice);
// GET IMAGE
if (product.picture.length() > 0) {
// PUT IMAGE
cardImage.setImageBitmap(BitmapFactory.decodeFile(functions.getLocalPicturePath(product.picture)));
}else{
// GENERATE GRADIENT
card.setBackground(colors.generateGradient());
}
// SET VALUES
cardTitle.setText(product.name);
cardSKU.setText(product.sku);
cardPrice.setText("$"+product.price);
// CHECK FOR SALE PRICE
if(product.salePrice > 0){
cardPrice.setText("$"+product.salePrice);
}
}
return view;
when loading it makes a choppy transition that lasts close to 1 second.
Is there ways I can improve on this?
First, enable StrictMode. It will then yell at you that you are doing disk I/O on the main application thread. It won't yell at you that you are doing an expensive bitmap-decoding operation on the main application thread, though that's a problem too.
Then, as njzk2 suggests, use one of the vast array of image-loading libraries for Android, such as Picasso, to load your image asynchronously.
Google's sample code https://developer.android.com/guide/topics/ui/layout/gridview.html is setting a bad example !
To fix that sample code, instead of :
imageView.setImageResource(mThumbIds[position]);
You'll want to use a library, I used Glide, to load the image in a thread. Like this:
public View getView(int position, View convertView, ViewGroup parent) {
CircleImageView imageView;
if (convertView == null) {
// not recycled
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_image, parent, false);
imageView = (CircleImageView) view;
} else {
// recycled
imageView = (CircleImageView) convertView;
}
Glide
.with(parent.getContext())
.load(mThumbIds[position])
.placeholder(R.mipmap.ic_launcher)//REQUIRED
.dontAnimate()//REQUIRED
.into(imageView);
//imageView.setImageResource(mThumbIds[position]);
return imageView;
}
Get CircleImageView here: https://github.com/hdodenhof/CircleImageView
Get Glide here: https://github.com/bumptech/glide
By the way, the XML for my R.layout.item_image is :
<?xml version="1.0" encoding="utf-8"?>
<de.hdodenhof.circleimageview.CircleImageView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/image_avatar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
app:civ_border_width="1dp"
app:civ_border_color="#FF000000"/>

TextViews recycle their positions and title when scrolling, Glide Gallery

I am trying to use the Glide Image Library to load images in a gridview an using REccycler View. However, I wanted the to have a title TextView beneath each image.
I have set a custom layout for this and tried to load the TextView in the onBindViewHolder. This works but on scrolling, the positions are recycled, and the TextViews Titles are changed, making a mess of it.
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Image image = images.get(position);
// // setup Glide request without the into() method
// DrawableRequestBuilder<String> thumbnailRequest = Glide
// .with(mContext)
// .load(image.getMedium());
// pass the request as a a parameter to the thumbnail request
Glide.with(mContext).load(image.getMedium())
.thumbnail(0.3f)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.thumbnail);
titleText.setText(image.getName());
}
How do I fix this dear developers?
I think the problem is that the titleText is not stored in the ViewHolder.
Save it inside your holder object and use:
holder.titleText.setText(image.getName());
This will change the TextView accordingly as the holder changes. Else it will be a mess as the holders are recycled.
something like:
class MyViewHolder extends RecyclerView.ViewHolder{
TextView titleText;
ImageView thumbnail;
.
.
.
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Image image = images.get(position);
Glide.with(mContext).load(image.getMedium())
.thumbnail(0.3f)
.crossFade()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.thumbnail);
holder.titleText.setText(image.getName());
}
}

ViewPager inside RecyclerView: ImageView not showing in the first page

I have a ViewPager as the row of a RecyclerView. It is like a "featured products" row.
I set the adapter of the ViewPager in the onBindViewHolder of the RecyclerView. ViewPager contains a TextView and an ImageView. ImageView is loaded from an URL via Glide in instantiateItem. The list of items in the ViewPager is 4.
The problem is, the ImageViews of the first two items in the ViewPager are not loaded. If I swipe the ViewPager to the 3rd item and back, I see the first ImageView successfully.
TextViews work fine. The problem is only with the images.
If I debug the code, I observe that the code block that belongs to Glide is reached.
If I use the ViewPager as a standalone view in the fragment (not as a row of the RecyclerView) I observe no problems.
There is a similar question:
Image not loading in first page of ViewPager (PagerAdapter)
But that unfortunately does not apply to my case. I declare my variables locally and with the final modifier already.
PagerAdapter's instantiateItem is like follows:
#Override
public Object instantiateItem(ViewGroup container, int position) {
final LayoutInflater inflater = (LayoutInflater) container.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View v = inflater.inflate(viewpager_layout, container, false);
final ImageView imgProduct = (ImageView) v.findViewById(R.id.imgProduct);
final TextView lblName = (TextView) v.findViewById(R.id.lblName);
final Product product = data.get(position);
lblName.setText(product.name);
Glide
.with(ctx)
.load(product.url)
.asBitmap()
.thumbnail((float) 0.4)
.placeholder(R.drawable.placeholder)
.error(R.drawable.placeholder)
.animate(R.animator.fade_in)
.into(imgProduct);
}
RecyclerView's onBindViewHolder looks like:
#Override
public void onBindViewHolder(final DataObjectHolder holder, int position) {
int listType = getItemViewType(position);
final ProductList item = data.get(position);
if (listType == 0) {
final List<Product> lstProducts = GetProducts(item.products);
final MyPagerAdapter myAdapter = new MyPagerAdapter(ctx, lstProducts);
holder.viewPager.setAdapter(myAdapter);
myAdapter.notifyDataSetChanged(); // this changes nothing also..
}
else {
// removed..
}
}
I work with the AppCompat library by the way.
All suggestions are welcome. Thank you.
Glide sets images asynchronously and helps to avoid any lag in UI thread. If there are many images it does take some time for the image to set in, but it doesn't cause any lag.
It's a simple Asynchronous request issue, when you swipe to the third tab and come back, till the data would have come and come and then it's gets binded with the UI.
I had faced the similar issue in my project.
I am assuming that you are using a new fragment for each view pager
One thing you can do is...
1.While creating fragment in viewPager in **getItem()**, set a tag with fragment.
2. create a viewPager **addOnPageChangeListener** and on page selected, get that fragment by tag and check if image is loaded or not.
3. If not loaded, then show some loader, and wait for the response, after response hide the loader

Android - Gridview images mixes on scroll

I have a gridview which displays two column imageviews. I am loading these images with an async task (see this post Lazy load of images in ListView )
But when i am scrolling gridview , the images in positions are mixing. For example 14th image shows 1th image , i think view is trying to show old image before async task finishes.
My code :
public Content getItem(int position) {
return contents.get(position);
}
public long getItemId(int position) {
return position;
}
#Override
public boolean hasStableIds() { return true; }
public View getView(int position, View convertView, ViewGroup parent) {
Thumbnail contentView;
Content current = contents.get(position);
if (convertView == null) {
contentView = new Thumbnail(mContext);
}
else {
contentView = (Thumbnail) convertView;
}
contentView.title = current.getTitle();
contentView.image = current.getImage();
contentView.link = current.getLink();
contentView.init();
return contentView;
}
Init function
TextView titleText = (TextView)super.findViewById(R.id.titleText);
titleText.setText(title);
ImageView imageControl = (ImageView)super.findViewById(R.id.thumbImage);
DrawableManager loadImage = new DrawableManager(); loadImage.fetchDrawableOnThread(imgUrl, imageControl);
Waiting for your help
Thanks
It happens because of resource reusing. What you should do:
First, just set some kind of default image to your imageView (contentView.image.setImageResource(DEFAULT_RESOURCE)) inside getView method (transitional default picture is better than wrong one).
Set unique tag to your image, for example, position or url of image to load (contentView.image.setTag(url)).
When AsyncTask finishes, you can use some checks like
String url=(String)imageView.getTag();
if (url.equals(mUrl)) { //mUrl can be transmitted to AsyncTask instance separately
mActivity.runOnUiThread(new Runnable() {
#Override
public void run() {
imageView.setImageDrawable(bmp);
});
});
}
It's needed because Adapter does not allocate memory for all N ImageView for N items. It stores just required amount for visible items and some reserved ImageViews. So there is no warranty that ImageView reference that you store will be actual within several seconds cause it can became invisible and be reused by visible ones.
Don't load images yourself. Use Universal Image Loader . It can cache, images and loaded bitmaps. Making your problem go away. It also supports showing stub images and automatic pause on scrolling and so on.
It solves your specic problems by only loading an image for the last instance of an imageView if you reuse it.
imageLoader.displayImage(imageUri, imageView);
Is all that is needed to asynchronously load an image.

Categories

Resources