6
\$\begingroup\$

I've created a Grid with a RecyclerView similar to the GoogleIO 2014's generic media player one.

GoogleIO generic music player GoogleIO generic music player

Mine

Mine :3

The thing is that the images doesn't load immediately, but with a delay, so I had to put that "dirty" code for add a crossfade every time an image is loaded.

Beside that, I just want the code to be the most efficient and clean possible.

RecyclerViewAdapter

public class AlbumsRecyclerViewAdapter extends CursorRecyclerAdapter<AlbumsRecyclerViewAdapter.AlbumHolder> {

    private Context mContext;
    private int mArtistColumnIndex = -1;
    private int mAlbumColumnIndex = -1;
    private int mIdColumnIndex = -1;
    private int mDefaultTextColor, mDefaultBackgroundColor;
    private int mTileElevation;
    private int mImageSize = DEFAULT_IMAGE_SIZE;
    private static float IMAGE_SIZE_MULTIPLIER = 0.50f;
    private HashMap<Long, Palette> mPaletteCache = new HashMap<>();

    private static int DEFAULT_IMAGE_SIZE = 150;

    private static final int[] ATTRS = new int[]{
            android.R.attr.textColorPrimaryInverse
    };

    public AlbumsRecyclerViewAdapter(Context context, Cursor c) {
        super(c);
        mContext = context;
        final TypedArray typedArray = context.obtainStyledAttributes(ATTRS);
        mDefaultTextColor = typedArray.getColor(0, Color.WHITE);
        typedArray.recycle();
        mTileElevation = context.getResources().getDimensionPixelSize(R.dimen.tile_elevation);
        mDefaultBackgroundColor = ContextCompat.getColor(context, R.color.grid_item_background);

    }

    @Override
    public void onBindViewHolder(AlbumHolder holder, Cursor cursor) {
         holder.bind(cursor);
    }

    @Override
    public AlbumHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new AlbumHolder(LayoutInflater.from(mContext).inflate(R.layout.album_grid_item, parent, false));
    }

    public class AlbumHolder extends RecyclerView.ViewHolder {

        private TextView mName, mArtist;
        private ImageView mImage;

        public AlbumHolder(View itemView) {
            super(itemView);
            mName = (TextView) itemView.findViewById(R.id.album_grid_item_name);
            mArtist = (TextView) itemView.findViewById(R.id.album_grid_item_artist);
            mImage = (ImageView) itemView.findViewById(R.id.album_grid_item_image);
            ViewCompat.setElevation(itemView, mTileElevation);

    }

    private void resetColors() {
        mName.setTextColor(mDefaultTextColor);
        mArtist.setTextColor(mDefaultTextColor);
        itemView.setBackgroundColor(mDefaultBackgroundColor);
    }

    private void getColumnsIndices(Cursor cursor) {
        if (mAlbumColumnIndex == -1 && cursor != null) {
            mAlbumColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM);
        }
        if (mArtistColumnIndex == -1 && cursor != null) {
            mArtistColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST);
        }
        if (mIdColumnIndex == -1 && cursor != null) {
            mIdColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums._ID);
        }
    }

    private boolean setColorsFromCache(long albumId) {
        Palette palette = mPaletteCache.get(albumId);
        if (palette != null) {
            setColorsFromPalette(palette, false);
            return true;
        }
        return false;
    }

    private void setColorsFromPalette(Palette palette, boolean animate) {
        Palette.Swatch swatch = palette.getVibrantSwatch();
        if (swatch != null) {
            if (animate) {
                ViewUtils.setBackgroundColorWithAnimation(itemView, mDefaultBackgroundColor, palette.getVibrantColor(swatch.getRgb()));
                ViewUtils.setTextColorWithAnimation(mName, mDefaultTextColor, palette.getVibrantSwatch().getBodyTextColor());
                ViewUtils.setTextColorWithAnimation(mArtist, mDefaultTextColor, palette.getVibrantSwatch().getBodyTextColor());
            } else {
                itemView.setBackgroundColor(palette.getVibrantColor(swatch.getRgb()));
                mName.setTextColor(palette.getVibrantSwatch().getBodyTextColor());
                mArtist.setTextColor(palette.getVibrantSwatch().getBodyTextColor());
            }
        }
    }


    public void bind(Cursor cursor) {
        if (mImageSize == DEFAULT_IMAGE_SIZE) {
            mImage.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @SuppressLint("NewApi")
                @SuppressWarnings("deprecation")
                @Override
                public void onGlobalLayout() {
                    mImageSize = (int) (mImage.getWidth() * IMAGE_SIZE_MULTIPLIER);
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
                        mImage.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    else
                        mImage.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                }
            });
        }
        resetColors();
        getColumnsIndices(cursor);
        if (cursor != null) {
            final long albumId = cursor.getLong(mIdColumnIndex);
            final boolean colorsFromCache = setColorsFromCache(albumId);
            String name = cursor.getString(mAlbumColumnIndex);
            String artist = cursor.getString(mArtistColumnIndex);
            mName.setText(name);
            mArtist.setText(artist);
            Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
            Uri uri = ContentUris.withAppendedId(sArtworkUri, albumId);
            Glide.with(mContext)
                    .load(uri)
                    .asBitmap()
                    .override(mImageSize, mImageSize)
                    .listener(new RequestListener<Uri, Bitmap>() {
                        @Override
                        public boolean onException(Exception e, Uri model, Target<Bitmap> target, boolean isFirstResource) {
                            return false;
                        }

                        @Override
                        public boolean onResourceReady(Bitmap resource, Uri model, Target<Bitmap> target, boolean isFromMemoryCache, boolean isFirstResource) {
                            if (!colorsFromCache)
                                Palette
                                        .from(resource)
                                        .generate(new Palette
                                                          .PaletteAsyncListener() {
                                                      @Override
                                                      public void onGenerated(Palette palette) {
                                                          setColorsFromPalette(palette, true);
                                                          mPaletteCache.put(albumId, palette);
                                                      }
                                                  }

                                        );
                            ViewUtils.setImageBitmapWithAnimation(mImage, resource);
                            return true;
                        }
                    })
                    .into(mImage);
            itemView.setOnClickListener(new View.OnClickListener()

                                        {
                                            @Override
                                            public void onClick(View v) {

                                            }
                                        }

            );
        }

    }

}
}

ViewUtils

public class ViewUtils {

public static int DEFAULT_ANIMATION_DURATION = 150;

//This class should not be instantiated
private ViewUtils() {
}

@SuppressWarnings("deprecation")
public static void setBackground(View view, Drawable drawable) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
        view.setBackgroundDrawable(drawable);
    } else {
        view.setBackground(drawable);
    }
}

public static void setBackgroundColorWithAnimation(View view, int fromColor, int toColor) {
    ColorDrawable[] colors = {new ColorDrawable(fromColor), new ColorDrawable(toColor)};
    TransitionDrawable transitionDrawable = new TransitionDrawable(colors);
    setBackground(view, transitionDrawable);
    transitionDrawable.startTransition(DEFAULT_ANIMATION_DURATION);
}

public static void setImageBitmapWithAnimation(ImageView imageView, Bitmap bitmap) {
    final TransitionDrawable transitionDrawable =
            new TransitionDrawable(new Drawable[]{
                    new ColorDrawable(Color.TRANSPARENT),
                    new BitmapDrawable(imageView.getContext().getResources(), bitmap)
            });
    imageView.setImageDrawable(transitionDrawable);
    transitionDrawable.startTransition(DEFAULT_ANIMATION_DURATION);

}

public static void setTextColorWithAnimation(final TextView textView, int fromColor, int toColor) {
    ValueAnimator anim = new ValueAnimator();
    anim.setIntValues(fromColor, toColor);
    anim.setEvaluator(new ArgbEvaluator());
    anim.setDuration(DEFAULT_ANIMATION_DURATION);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            textView.setTextColor((int) animation.getAnimatedValue());
        }
    });
    anim.start();
}

}

CursorRecyclerAdapter

https://gist.github.com/quanturium/46541c81aae2a916e31d

\$\endgroup\$
2
  • 1
    \$\begingroup\$ -1 for Pharrell but +2 for the stuff that looks good ;-) \$\endgroup\$
    – rolfl
    Sep 18, 2015 at 19:16
  • \$\begingroup\$ @rolfl Haha, that's the generic music player from GoogleIO, i'll upload screenshot of mine. ;) \$\endgroup\$ Sep 18, 2015 at 19:39

1 Answer 1

2
\$\begingroup\$
private void getColumnsIndices(Cursor cursor) {
    if (mAlbumColumnIndex == -1 && cursor != null) {
        mAlbumColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM);
    }
    if (mArtistColumnIndex == -1 && cursor != null) {
        mArtistColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST);
    }
    if (mIdColumnIndex == -1 && cursor != null) {
        mIdColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums._ID);
    }
}

If the cursor is null, you don't need to do anything in this function. So turn it into a guard clause:

private void getColumnsIndices(Cursor cursor) {
    if (cursor == null) { return; }

    if (mAlbumColumnIndex == -1) {
        mAlbumColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM);
    }
    if (mArtistColumnIndex == -1) {
        mArtistColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST);
    }
    if (mIdColumnIndex == -1) {
        mIdColumnIndex = cursor.getColumnIndex(MediaStore.Audio.Albums._ID);
    }
}

private void setColorsFromPalette(Palette palette, boolean animate) {
    Palette.Swatch swatch = palette.getVibrantSwatch();
    if (swatch != null) {
        if (animate) {
            ViewUtils.setBackgroundColorWithAnimation(itemView, mDefaultBackgroundColor, palette.getVibrantColor(swatch.getRgb()));
            ViewUtils.setTextColorWithAnimation(mName, mDefaultTextColor, palette.getVibrantSwatch().getBodyTextColor());
            ViewUtils.setTextColorWithAnimation(mArtist, mDefaultTextColor, palette.getVibrantSwatch().getBodyTextColor());
        } else {
            itemView.setBackgroundColor(palette.getVibrantColor(swatch.getRgb()));
            mName.setTextColor(palette.getVibrantSwatch().getBodyTextColor());
            mArtist.setTextColor(palette.getVibrantSwatch().getBodyTextColor());
        }
    }
}

Here you make 4 calls (but only 2 at most per method invocation) to palette.getVibrantSwatch().getBodyTextColor(), which is a bit of a waste to me. Try storing the result of the method call in a temporary variable. Alternatively, consider extracting changing of color values to separate functions; one for animated color changes, one for static color changes. Arguments would be the body text color and the RGB from the swatch.

\$\endgroup\$
1
  • \$\begingroup\$ Well, it turns out that the actual implementation of the Cursor caches the column indices, so I completly removed that part. Anyway, thanks for the advices for the setColorsFromPalette method. I'll accept this answer. \$\endgroup\$ Apr 9, 2016 at 21:31

Your Answer

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

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