Question

I have a custom adapter for my listview, in the listview it sets a asynctask per image to load the image from a webservice in the background and then display it. But the images keep refreshing and sometimes loading wrong images after some time.(The first time loaded it shows the right image) LogoLoader is the asynctask.

Adapter class:

public class SearchResultAdapter extends ArrayAdapter<SearchResultRowItem> {

Context context;
private MainActivity main;

public SearchResultAdapter(Context context, int resourceId, List<SearchResultRowItem> items,MainActivity main) {
    super(context, resourceId, items);
    this.context = context;
    this.main = main;
}

/*private view holder class*/
private class ViewHolder {
    ImageView imageView;
    TextView txtTitle;
    TextView txtDesc;
    TextView txtAdres;
    TextView txtAfstand;
}

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder = null;
    SearchResultRowItem rowItem = getItem(position);

    LayoutInflater mInflater = (LayoutInflater) context
            .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.listitem, null);
        holder = new ViewHolder();
        holder.txtDesc = (TextView) convertView.findViewById(R.id.desc);
        holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
        holder.txtAdres = (TextView) convertView.findViewById(R.id.adres);
        holder.txtAfstand = (TextView) convertView.findViewById(R.id.afstand);
        holder.imageView = (ImageView) convertView.findViewById(R.id.logo);
        convertView.setTag(holder);
    } else {
        holder = (ViewHolder) convertView.getTag();
    }


    holder.txtDesc.setText(Html.fromHtml(rowItem.getDesc()));
    holder.txtTitle.setText(rowItem.getTitle());
    holder.txtAdres.setText(rowItem.getAdres());
    holder.txtAfstand.setText(rowItem.getAfstand());

    if (holder.imageView != null && rowItem.hasLogo()) {
        holder.imageView.setImageResource(R.drawable.loader);
        LogoLoader logoLoader = new LogoLoader(holder.imageView, rowItem.getOrganisatieId(), 100, 100, main);
        logoLoader.execute();
    }

    convertView.setBackgroundColor(position % 2 == 0 ? Color.WHITE : Color.parseColor("#F8F8F8"));
    return convertView;
}

}

LogoLoader class:

public class LogoLoader extends AsyncTask<Void, Void, String> {

private ImageView imageView;
private UUID OrganisationGuid;
private int maxWidth;
private int maxHeight;

private MainActivity main;

public LogoLoader(ImageView imageView, UUID OrganisationGuid, int maxHeight, int maxWidth,MainActivity main) {
    this.imageView = imageView;
    this.OrganisationGuid = OrganisationGuid;
    this.maxHeight = maxHeight;
    this.maxWidth = maxWidth;
    this.main = main;
}

@Override
protected String doInBackground(Void... params) {
    WebserviceAdapter task = new WebserviceAdapter(
            "api/Logo/GetLogos?ids="+OrganisationGuid.toString()+
            "&maxWidth="+Integer.toString(maxWidth)+
            "&maxHeight="+Integer.toString(maxHeight));
    return task.result;
}

@Override
protected void onPostExecute(String result){
    try {
        JSONObject json = new JSONObject(result);

        JSONArray jsonArray = json.getJSONArray("Results");
        JSONObject imageObject = jsonArray.getJSONObject(0);

        byte[] imageData = Base64.decode( imageObject.getString("Data").getBytes(), Base64.DEFAULT);
        Drawable logoDrawable = null;
        if (imageData != null) {
            Bitmap logoBitmap = BitmapFactory.decodeByteArray(imageData, 0,
                    imageData.length);
            logoDrawable = new BitmapDrawable(main.getResources(), logoBitmap);
        }
        imageView.setImageDrawable(logoDrawable);
    } catch (JSONException e) {
        imageView.setImageDrawable(null);
    }

}

}

Was it helpful?

Solution

The repetitive loading is due to the listview's getView method being called regularly multiple times and loading of wrong images is due to feature of resuing views. ListView try to reuse item views to conserve memory and increase efficiency. The solution to the first problem is to load a image only once and save it somewhere (if images are thumbnails then in memory and if images are larger then on SDCard). and solution to the second problem is to use

holder.imageView.setImageBitmap(null);

before if (holder.imageView != null && rowItem.hasLogo()) { so that whenever a view gets rendered, it has no previous image loaded. I hope you got my point. And also you can use Universal Image Loader library for loading of images. I have used it and it works like a charm.

OTHER TIPS

I can recommend a different way to load the images and that works like a charm: Android Query.

You can download that jar file from here: http://code.google.com/p/android-query/downloads/list

AQuery androidAQuery=new AQuery(this);

As an example:

androidAQuery.id(YOUR IMAGEVIEW).image(YOUR IMAGE TO LOAD, true, true, getDeviceWidth(), ANY DEFAULT IMAGE YOU WANT TO SHOW);

It's very fast and accurate, and using this you can find many more features like Animation when loading; getting a bitmap, if needed; etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top