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

asked Sep 18, 2015 at 19:10
\$\endgroup\$
2
  • 1
    \$\begingroup\$ -1 for Pharrell but +2 for the stuff that looks good ;-) \$\endgroup\$ Commented Sep 18, 2015 at 19:16
  • \$\begingroup\$ @rolfl Haha, that's the generic music player from GoogleIO, i'll upload screenshot of mine. ;) \$\endgroup\$ Commented 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.

answered Feb 17, 2016 at 13:33
\$\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\$ Commented Apr 9, 2016 at 21:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.