Picasso image load incredibly laggy in android listview?

278 views Asked by At

In my application, I am using the last.fm api, picasso, and "artist" & "album" strings to fetch album art images for a listview feed. When I scroll through the feed, it is super laggy and I'm not sure why. If there is new data, a button appears on the screen to update, and it scrolls to the top of the listview. When I use picasso to fetch images, the auto scroll is incredibly laggy. If I am using a stored png or something, it works fine.

Here is my getView() method in custom adapter class--this particular layout is "playcut" in the switch case:

case PLAYCUT_LAYOUT: //Playcut
             convertView = mInflater.inflate(R.layout.listview_cell, null);

            convertView.findViewById(R.id.play).setVisibility(View.GONE);

            holder.cell_image = (ImageView) convertView.findViewById(R.id.cell_image);

            holder.cell_image.setImageResource(R.drawable.no_album_art);

            StringBuilder stringBuilder = new StringBuilder("http://ws.audioscrobbler.com/2.0/");
            stringBuilder.append("?method=album.getinfo");
            stringBuilder.append("&api_key=");
            stringBuilder.append("2ead17554acf667f27cf7dfd4c368f15");
            String albumURL;

            try{
                stringBuilder.append("&artist=" + URLEncoder.encode(oslist.get(position).get("artistName"), "UTF-8"));
                stringBuilder.append("&album=" + URLEncoder.encode(oslist.get(position).get("releaseTitle"), "UTF-8"));
                albumURL = new RetrieveAlbumArtUrlTask().execute(stringBuilder.toString()).get();
                Picasso.with(context).load(albumURL).error(R.drawable.no_album_art).into(holder.cell_image);

            }catch(UnsupportedEncodingException e){

            } catch(InterruptedException e){

            } catch(ExecutionException e){

            } catch(IllegalArgumentException e){
                Log.v("TEST","SUP");
                holder.cell_image.setImageResource(R.drawable.no_album_art);
            }

            holder.song = (TextView) convertView.findViewById(R.id.song);
            holder.artist = (TextView) convertView.findViewById(R.id.artist);

            holder.song.setText(oslist.get(position).get("songTitle"));
            holder.artist.setText(oslist.get(position).get("artistName"));


            final RelativeLayout playcutLayout = (RelativeLayout) convertView.findViewById(R.id.playcut);

            convertView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                        updateView(position);

                }
            });

            convertView.setTag(holder);
            break;
        case NULL_LAYOUT:

And here is a relevant AsyncTask method in that same class:

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

    protected String doInBackground(String... urls) {
        String albumArtUrl = null;
        try {

            XMLParser parser = new XMLParser();
            String xml = parser.getXmlFromUrl(urls[0]); // getting XML from URL
            Document doc = parser.getDomElement(xml);
            NodeList nl = doc.getElementsByTagName("image");
            for (int i = 0; i < nl.getLength(); i++) {
                Element e = (Element) nl.item(i);

                if(e.getAttribute("size").contentEquals("extralarge")){
                    albumArtUrl = parser.getElementValue(e);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return albumArtUrl;
    }
}
1

There are 1 answers

0
reidzeibel On

I think it is because of the retrieve RetrieveAlbumArtUrlTask and the String concatenation that occurs there (however fast it might be).

Each time your view is created (when scrolled) :

  1. The getView() method will go through the switch statement
  2. View will be drawn as requested by each case
  3. On the PlayCut case

    This stringBuilder operation can be replaced

    Old

        StringBuilder stringBuilder = new StringBuilder("http://ws.audioscrobbler.com/2.0/");
        stringBuilder.append("?method=album.getinfo");
        stringBuilder.append("&api_key=");
        stringBuilder.append("2ead17554acf667f27cf7dfd4c368f15");
    
        String albumURL;
    
        try{
            stringBuilder.append("&artist=" + URLEncoder.encode(oslist.get(position).get("artistName"), "UTF-8"));
            stringBuilder.append("&album=" + URLEncoder.encode(oslist.get(position).get("releaseTitle"), "UTF-8"));
            albumURL = new RetrieveAlbumArtUrlTask().execute(stringBuilder.toString()).get();
            Picasso.with(context).load(albumURL).error(R.drawable.no_album_art).into(holder.cell_image);
    
        }catch(UnsupportedEncodingException e){
    
        } catch(InterruptedException e){
    
        } catch(ExecutionException e){
    
        } catch(IllegalArgumentException e){
            Log.v("TEST","SUP");
            holder.cell_image.setImageResource(R.drawable.no_album_art);
        }
    

    New

        //make a constant field with value 
        //"http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=2ead17554acf667f27cf7dfd4c368f15&artist=%s&album=%s"
        //maybe like 
    
        private static final String APIURL = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=2ead17554acf667f27cf7dfd4c368f15&artist=%s&album=%s";
    
        //then use 
    
        String artistName =  URLEncoder.encode(oslist.get(position).get("artistName"), "UTF-8");
        String albumName = URLEncoder.encode(oslist.get(position).get("albumName"), "UTF-8");
        String albumURL = new RetrieveAlbumArtUrlTask().execute(String.format(APIURL, artistName, albumName)).get();
    
        //then use picasso as usual
    

I think String operations during getView() is costly, therefore I'd like to keep it minimum.

Also, can you try doing the picasso loading without RetrieveAlbumArtUrlTask ? If it is indeed faster, then the Background task is the culprit