Search code examples
javaandroidxmlandroid-imageviewuniversal-image-loader

Universal image loader imageview doesn't update itself with spinner


I'm using UIL to load thrumbs in a listview.

here is the imageview and the spinner in the cell layout :

        <ImageView
            android:id="@+id/imgAlbum"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:layout_gravity="center|left"
            android:scaleType="centerCrop"
            android:visibility="gone" />

        <ProgressBar
            android:id="@+id/loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:visibility="gone" />

The list :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/background"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/list_restaurant"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="4dp" >
    </ListView>

</LinearLayout>

I config the loader like that :

public void setImageLoader(ImageLoader imageLoader, Context context) {

        File cacheDir = StorageUtils.getCacheDirectory(context);
        ImageLoaderConfiguration _config;
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
            _config = new ImageLoaderConfiguration.Builder(context).memoryCacheExtraOptions(0, 0).discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75).taskExecutor(null)
                    .taskExecutorForCachedImages(null).threadPoolSize(3) // default
                    .threadPriority(Thread.NORM_PRIORITY - 1) // default
                    .tasksProcessingOrder(QueueProcessingType.FIFO) // default
                    .denyCacheImageMultipleSizesInMemory().memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) // default
                    .memoryCacheSize(2 * 1024 * 1024).discCache(new UnlimitedDiscCache(cacheDir)) // default
                    .discCacheSize(50 * 1024 * 1024).discCacheFileCount(100).discCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
                    .imageDownloader(new BaseImageDownloader(context)) // default
                    .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
                    .enableLogging().build();
        }
        else {
            _config = new ImageLoaderConfiguration.Builder(context).memoryCacheExtraOptions(0, 0)
                    // default/screendimensions
                    .discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75).taskExecutor(AsyncTask.THREAD_POOL_EXECUTOR).taskExecutorForCachedImages(AsyncTask.THREAD_POOL_EXECUTOR)
                    .threadPoolSize(3) // default
                    .threadPriority(Thread.NORM_PRIORITY - 1) // default
                    .tasksProcessingOrder(QueueProcessingType.FIFO) // default
                    .denyCacheImageMultipleSizesInMemory().memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)) // default
                    .memoryCacheSize(2 * 1024 * 1024).discCache(new UnlimitedDiscCache(cacheDir)) // default
                    .discCacheSize(50 * 1024 * 1024).discCacheFileCount(100).discCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
                    .imageDownloader(new BaseImageDownloader(context)) // default
                    .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
                    .enableLogging().build();
        }
        if (!imageLoader.isInited()) {
            imageLoader.init(_config);
        }
    }

And in the baseadapter i use it like that :

private ImageLoader             _imageLoader;
private DisplayImageOptions     _options;

in the constructor

this._imageLoader = ImageLoader.getInstance();
this._options = new DisplayImageOptions.Builder().showImageForEmptyUri(R.drawable.error).showImageOnFail(R.drawable.error).cacheInMemory().cacheOnDisc().bitmapConfig(Bitmap.Config.RGB_565)
        .build();
Utils utils = new Utils();
utils.setImageLoader(_imageLoader, _activity);

In the GetView() :

    final ProgressBar spinner = (ProgressBar) convertView.findViewById(R.id.loading);
                _imageLoader.displayImage(etablissement.getImgThumb(), cellHolder.imageIcon, _options, new SimpleImageLoadingListener() {
                    @Override
                    public void onLoadingStarted(String imageUri, View view) {

                        view.setVisibility(View.GONE);
                        spinner.setVisibility(View.VISIBLE);
                        spinner.invalidate();
                        view.invalidate();
                    }

                    @Override
                    public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                        String message = null;
                        switch (failReason.getType()) {
                            case IO_ERROR:
                                message = "Input/Output error";
                                break;
                            case DECODING_ERROR:
                                message = "Image can't be decoded";
                                break;
                            case NETWORK_DENIED:
                                message = "Downloads are denied";
                                break;
                            case OUT_OF_MEMORY:
                                message = "Out Of Memory error";
                                break;
                            case UNKNOWN:
                                message = "Unknown error";
                                break;
                        }
                        view.setVisibility(View.VISIBLE);
                        spinner.setVisibility(View.GONE);spinner.invalidate();
                        view.invalidate();
                    }

                    @Override
                    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {

                        view.setVisibility(View.VISIBLE);
                        spinner.setVisibility(View.GONE);
                        spinner.invalidate();
                        view.invalidate();
                    }
                });

Everything works fine BUT the spinner stay instead of the imageview until you scroll the list the redraw the cells.. The imageview should refresh itself when the image is downloaded/got from cache or invalidate()

Here the list loading stay like that : http://imagik.fr/view-rl/45673

Here when i scroll down the imageview refresh : http://imagik.fr/view-rl/45674

Here when i re-scoll up the imageview refresh : http://imagik.fr/view-rl/45675

Any idea ??

EDIT:

The full adapter code (with the UIL part inside) :

public class AdapterDirectories extends BaseAdapter {
    /**
     * PRIVATE ATTRIBUTES
     */
    // LOG
    private static final String     TAG             = AdapterDirectories.class.getSimpleName();
    // IHM
    private static LayoutInflater   _inflater       = null;
    private Activity                _activity;
    // DATA
    private DataManager             _dataManager;
    private ImageLoader             _imageLoader;
    private DisplayImageOptions     _options;
    private int                     _section;
    private float                   _latitude;
    private float                   _longitude;
    private List<Contact>           _listContacts   = new ArrayList<Contact>();
    private List<Favoris>           _listFavoris    = new ArrayList<Favoris>();

    public AdapterDirectories(Activity activity, boolean favoris, float latitude, float longitude, int section) {

        this._activity = activity;
        this._latitude = latitude;
        this._longitude = longitude;
        this._section = section;
        //
        ContactRepository contactRep = null;
        //
        if (favoris == false) {
            _listContacts = EtablissementApplication._dataManager.get_listOfContacts(_section, _activity);
        }
        else {
            // FAVORITE
            this._listFavoris = EtablissementApplication._dataManager.get_listOfFavoris();
            // DATA
            contactRep = new ContactRepository(_activity);
            contactRep.Open();
            for (Favoris unFavoris : _listFavoris) {
                _listContacts.add(contactRep.GetById(unFavoris.getIdentifiantContact()));
            }
            contactRep.Close();
        }
        _inflater = (LayoutInflater) _activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this._imageLoader = ImageLoader.getInstance();
        this._options = new DisplayImageOptions.Builder().showImageForEmptyUri(R.drawable.error).showImageOnFail(R.drawable.error).cacheInMemory().cacheOnDisc()
                .displayer(new RoundedBitmapDisplayer(Utils.IMAGE_BORDER_RADIUS)).bitmapConfig(Bitmap.Config.RGB_565).build();
        Utils utils = new Utils();
        utils.setImageLoader(_imageLoader, _activity);
    }

    @Override
    public int getCount() {

        return _listContacts.size();
    }

    @Override
    public Object getItem(int position) {

        return position;
    }

    @Override
    public long getItemId(int position) {

        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view = convertView;
        CellHolder cellHolder = null;
        Contact _contact = _listContacts.get(position);
        Etablissement etablissement = new Etablissement();
        //
        // GET
        if (convertView == null) {
            view = _inflater.inflate(R.layout.directory_list_item, null);
            cellHolder = new CellHolder();
            cellHolder.textTitle = (TextView) view.findViewById(R.id.annuaire_titre_etablissement);
            cellHolder.textCategory = (TextView) view.findViewById(R.id.annuaire_categorie_etablissement);
            cellHolder.textDistance = (TextView) view.findViewById(R.id.annuaire_distance_etablissement);
            cellHolder.imageIcon = (ImageView) view.findViewById(R.id.img_icon);
            cellHolder.textPromo = (TextView) view.findViewById(R.id.promo);
            cellHolder.textTarif = (TextView) view.findViewById(R.id.annuaire_tarif_etablissement);
            view.setTag(cellHolder);
        }
        else {
            cellHolder = (CellHolder) convertView.getTag();
        }
        //
        // SET
        cellHolder.textTitle.setText(_contact.getName().toUpperCase());
        try {
            //
            EtablissementRepository etablissementRep = new EtablissementRepository(_activity);
            etablissementRep.Open();
            int idEta = etablissementRep.GetByIdContact(_contact.getIdentifiant());
            etablissement = etablissementRep.GetById(idEta);
            etablissementRep.Close();
            // CATEGORIES
            if (_section == 0) {
                if (etablissement.getSection() != null && !etablissement.getSection().getLibelle().equals("")) {
                    cellHolder.textCategory.setText(etablissement.getSection().getLibelle());
                }
                else {
                    cellHolder.textCategory.setVisibility(View.GONE);
                }
            }
            else {
                String categories = "";
                for (Categorie cat : etablissement.getCategories()) {
                    categories = categories + cat.getLibelle() + "|";
                }
                if (!categories.equals("")) {
                    cellHolder.textCategory.setText(categories);
                }
                else {
                    cellHolder.textCategory.setText(_activity.getString(R.string.txt_no_categories));
                }
            }
            //
            // TARIF
            String trancheTarif = "";
            if (etablissement.getTarif() != null) {
                trancheTarif = etablissement.getTarif().getMinPrice() + "\u20ac à " + etablissement.getTarif().getMaxPrice() + "\u20ac";
            }
            if (!trancheTarif.equals("") && etablissement.getTarif().getMinPrice() > 0 && etablissement.getTarif().getMaxPrice() > 0) {
                cellHolder.textTarif.setText(trancheTarif);
            }
            else {
                cellHolder.textTarif.setText("- \u20ac à - \u20ac");
            }
            // PROMO
            boolean etatPromotion = false;
            for (Promotion promo : etablissement.getPromotions()) {
                if (promo.isPromoOnGoing()) {
                    etatPromotion = true;
                }
            }
            if (!etatPromotion) { // PROMO OFF
                cellHolder.textPromo.setVisibility(View.VISIBLE);
            }
            else { // PROMO ON
                cellHolder.textPromo.setVisibility(View.VISIBLE);
            }
            // LOGO
            final ProgressBar spinner = (ProgressBar) convertView.findViewById(R.id.loading);
            _imageLoader.displayImage(etablissement.getImgThumb(), cellHolder.imageIcon, _options, new SimpleImageLoadingListener() {
                @Override
                public void onLoadingStarted(String imageUri, View view) {

                }

                @Override
                public void onLoadingFailed(String imageUri, View view, FailReason failReason) {

                    String message = null;
                    switch (failReason.getType()) {
                        case IO_ERROR:
                            message = "Input/Output error";
                            break;
                        case DECODING_ERROR:
                            message = "Image can't be decoded";
                            break;
                        case NETWORK_DENIED:
                            message = "Downloads are denied";
                            break;
                        case OUT_OF_MEMORY:
                            message = "Out Of Memory error";
                            break;
                        case UNKNOWN:
                            message = "Unknown error";
                            break;
                    }
                }

                @Override
                public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {

                }
            });
        }
        catch (Exception e) {
        }
        // DISTANCE
        int distanceFormatee = 0;
        if (_latitude == 0 || _longitude == 0) {
            cellHolder.textDistance.setText("");
        }
        else {
            int distance = (int) distanceBetween(_latitude, _longitude, _contact.getLatitude(), _contact.getLongitude());
            distanceFormatee = distance / 1000;
            if (distance < 1000) {
                cellHolder.textDistance.setText("< 1 km");
            }
            else {
                cellHolder.textDistance.setText(distanceFormatee + " km");
            }
        }
        //
        // SAVE DISTANCE
        EtablissementApplication._dataManager.get_listOfContacts(_section, _activity).get(position).setDistance(distanceFormatee);
        //
        // DATA SAVE
        List<Integer> _mapData = new ArrayList<Integer>();
        _mapData.add(_contact.getIdentifiant());
        _mapData.add(etablissement.getIdentifiant());
        DataManager._contactForEtaHashMap.put(_contact.getName(), etablissement);
        DataManager._mapContact.put(position, _mapData);
        return view;
    }

    public class CellHolder {
        public TextView     textTitle;
        public TextView     textAdress;
        public TextView     textCategory;
        public TextView     textTarif;
        public TextView     textPromo;
        public ImageView    imageIcon;
        public TextView     textDistance;
    }

    public void clearData() {

        _listContacts.clear();
        _listFavoris.clear();
    }

    private double distanceBetween(float lat_a, float lng_a, float lat_b, float lng_b) {

        float pk = (float) (180 / 3.14169);
        float a1 = lat_a / pk;
        float a2 = lng_a / pk;
        float b1 = lat_b / pk;
        float b2 = lng_b / pk;
        float t1 = FloatMath.cos(a1) * FloatMath.cos(a2) * FloatMath.cos(b1) * FloatMath.cos(b2);
        float t2 = FloatMath.cos(a1) * FloatMath.sin(a2) * FloatMath.cos(b1) * FloatMath.sin(b2);
        float t3 = FloatMath.sin(a1) * FloatMath.sin(b1);
        double tt = Math.acos(t1 + t2 + t3);
        return 6366000 * tt;
    }
}

Solution

  • You can achieve expected behaviour by this:

    Your list item layout:

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    
        <ProgressBar
            android:id="@+id/loading"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" />
    
        <ImageView
            android:id="@+id/imgAlbum"
            android:layout_width="48dip"
            android:layout_height="48dip"
            android:layout_gravity="center|left"
            android:scaleType="centerCrop" />
    </RelativeLayout
    

    If you have ProgressBar and ImageView in this order, then ImageView will overlay the ProgressBar, when Image Loader set image into it so ProgressBar will not be visible anymore.

    Then in your getView() method just simply load image with standard way. You dont have to bother with hiding/showing ProgressBar