Search code examples
androidandroid-recyclerviewandroid-palette

Palette API not working (Works only when I'm debugging)


I created a simple RecyclerView and a CardView in it. In CardView there are ImageView and TextView. So I'm get the url of the image and load it using Picasso. Everything worked well before using Palette API. So I want to get the color from image and set it to CardView and TextView.

Here's my RecyclerView.Adapter

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> {

    private List<String> imagesUrl;
    private List<String> imageDescription;

    RecyclerAdapter(List<String> imagesUrl, List<String> imageDescription) {
        this.imagesUrl = imagesUrl;
        this.imageDescription = imageDescription;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
        View itemView = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, int position) {
        myViewHolder.textView.setText(imageDescription.get(position));
        Picasso.get()
                .load(imagesUrl.get(position))
                .into(new Target() {
                    @Override
                    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                        myViewHolder.imageView.setImageBitmap(bitmap);
                        myViewHolder.getPalette();
                    }

                    @Override
                    public void onBitmapFailed(Exception e, Drawable errorDrawable) {
                        myViewHolder.imageView.setImageResource(R.drawable.error);
                    }

                    @Override
                    public void onPrepareLoad(Drawable placeHolderDrawable) {
                        myViewHolder.imageView.setImageResource(R.drawable.placeholder);
                    }
                });
    }

    @Override
    public int getItemCount() {
        return imagesUrl.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        private ImageView imageView;
        private TextView textView;
        private CardView cardView;

        MyViewHolder(@NonNull View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.imageView);
            textView = itemView.findViewById(R.id.textView);
            cardView = itemView.findViewById(R.id.cardView);
        }

        private void getPalette() {
            Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
            Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() {
                @Override
                public void onGenerated(@Nullable Palette palette) {
                    //assert palette != null;
                    Palette.Swatch swatch = palette.getVibrantSwatch();
                    //assert swatch != null;
                    textView.setTextColor(swatch.getBodyTextColor());
                    cardView.setCardBackgroundColor(swatch.getRgb());
                }
            });
        }
    }
}

Every time it shows the placeholder image. When I'm doing debug, it works. So what's the problem?


Solution

  • So problem is not in Palette API. Problem is that target is being garbage collected.So the solution is to implement it on an object or store it in a field and set it as tag to our ImageView.

    Here. That's now working.

    @Override
    public void onBindViewHolder(@NonNull final MyViewHolder myViewHolder, int position) {
        myViewHolder.textView.setText(imageDescription.get(position));
        Target target = new Target() {
            @Override
            public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                myViewHolder.imageView.setImageBitmap(bitmap);
                myViewHolder.getPalette();
            }
    
            @Override
            public void onBitmapFailed(Drawable errorDrawable) {
                myViewHolder.imageView.setImageResource(R.drawable.error);
            }
    
            @Override
            public void onPrepareLoad(Drawable placeHolderDrawable) {
                myViewHolder.imageView.setImageResource(R.drawable.placeholder);
            }
        };
    
        Picasso.with(context)
                .load(imagesUrl.get(position))
                .into(target);
    
        myViewHolder.imageView.setTag(target);
    }
    

    I think this will help anyone someday))) Thank you