3
\$\begingroup\$

I have a list view which display in each view a Album's name, the associated Artist and the album art.

Here is the code of my ListFragment which display this list:

public class AlbumsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {

AlbumsAdapter mAdapter;

        @Override
           public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
           View myFragmentView = inflater.inflate(R.layout.albums_fragment_layout, container, false);
           return myFragmentView;
         }


        @Override
          public void onActivityCreated(Bundle savedInstanceState) {
           super.onActivityCreated(savedInstanceState);

                    mAdapter = new AlbumsAdapter(getActivity(), null);
                    setListAdapter(mAdapter);
                    getLoaderManager().initLoader(0, null, this);                               
        }


static final String[] ALBUM_SUMMARY_PROJECTION = { MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST, MediaStore.Audio.Albums.ALBUM_ART,};  



        public Loader<Cursor> onCreateLoader(int id, Bundle args) {      
            String select = null;  
            return new CursorLoader(getActivity(), MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,ALBUM_SUMMARY_PROJECTION, select, null, null);  
        }  



        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {  
            mAdapter.swapCursor(data);  
        }  



        public void onLoaderReset(Loader<Cursor> loader) {  
            mAdapter.swapCursor(null);  
        }  
    }

Here is my custom CursorAdapter's code:

public class AlbumsAdapter extends CursorAdapter {


    private final LayoutInflater mInflater;

     public AlbumsAdapter(Context context, Cursor c) {
        super(context, c);
        mInflater=LayoutInflater.from(context);

    }
    @Override
    public void bindView(View view, Context context, Cursor cursor) {

        ViewHolder holder = (ViewHolder) view.getTag();
        if (holder == null) {
            holder = new ViewHolder();
            holder.albumTitle = (TextView) view.findViewById(R.id.albumTextView);
            holder.artistName = (TextView) view.findViewById(R.id.artistTextView);
            holder.coverAlbum = (ImageView)view.findViewById(R.id.album_cover);
            holder.column1 = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM);
            holder.column2 = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ARTIST);
            holder.column3 = cursor.getColumnIndexOrThrow(MediaStore.Audio.Albums.ALBUM_ART);
            view.setTag(holder);
        }
        holder.albumTitle.setText(cursor.getString(holder.column1));
        holder.artistName.setText(cursor.getString(holder.column2));
        Bitmap coverBitmap = BitmapFactory.decodeFile(cursor.getString(holder.column3));
        holder.coverAlbum.setImageBitmap(coverBitmap);
    }

    static class ViewHolder {
        TextView albumTitle;
        TextView artistName;
        ImageView coverAlbum;
        int column1; 
        int column2;
        int column3;
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        final View view=mInflater.inflate(R.layout.albums_row,parent,false); 
        return view;
    }


}

As you can see, I use already the trick of the ViewHolder to avoid calling findViewById too often.

But the problem is that my list is still very slow. What can I do to optimize it even more? For instance I could load in priority the Albums' title and Artists' names and display them and then, load in a second time the cover (asynchronously).

I've also tried to scale down the resolution of the Cover's Bitmap before displaying them in the ImageViews, but I saw no improvement :/

Do you have any idea how to make this list less laggy? Any advice is welcome.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Your lag will be coming from this line:

 Bitmap coverBitmap = BitmapFactory.decodeFile(cursor.getString(holder.column3));

Your right about doing it asyncrhonously. You could also scale the image.

What you'll want to do is:

  • spawn a new thread
  • use a handler for when the bitmap has decoded
  • set the bitmap on the imageview in the callback

You could set the image to a spinner whilst it is loading.

An example of something similar is:

http://blog.blundellapps.co.uk/imageview-with-loading-spinner/

And an example of image scaling is:

http://developer.android.com/training/displaying-bitmaps/load-bitmap.html#load-bitmap

\$\endgroup\$
3
  • \$\begingroup\$ stumbled upon this and got some kind of malware popping up from clicking his link \$\endgroup\$ Commented Jun 18, 2019 at 19:47
  • 1
    \$\begingroup\$ @BigTLarrity thanks for the heads up. I didn't renew my .com domain only my .co.uk, I've updated the link. (some bad person seems to have bought the original then) \$\endgroup\$
    – Blundell
    Commented Jun 20, 2019 at 13:39
  • \$\begingroup\$ lol theres some rascals around aint there :P at least it is sorted now, hope i haven't been pwned haha xD \$\endgroup\$ Commented Jun 20, 2019 at 13:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.