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;
}
}
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