0

I saw a kind of a similar unanswered question, but I can't comment and ask questions there and he is having this problem all the time even on a first load: Picasso doesn't load first image of ArrayAdapter

So the problem is: I have an app where I can scroll the GridView endlessly and download movie posters. When I return to the very beginning of the screen - it sometimes doesn't update only first poster and shows some other picture.

I set Targets to the ImageView to keep strong reference. My code is following:

@Override
public View getView(final int position, View view, ViewGroup parent) {

    final MovieObject movieObject = getItem(position);

    if (view == null) {
        view = LayoutInflater.from(getContext()).inflate(R.layout.movie_item, parent, false);
    }

    final ProgressBar spinner = (ProgressBar) view.findViewById(R.id.movie_item_spinner);
    final ImageView poster = (ImageView) view.findViewById(R.id.movie_poster);

    // Target to show/hide ProgressBar on ImageView
    final Target target = new Target() {

        @Override
        public void onPrepareLoad(Drawable drawable) {
            poster.setBackgroundResource(R.color.white);
            spinner.setVisibility(View.VISIBLE);
        }

        @Override
        public void onBitmapLoaded(Bitmap photo, Picasso.LoadedFrom from) {
            poster.setBackgroundDrawable(new BitmapDrawable(photo));
            spinner.setVisibility(View.GONE);
        }

        @Override
        public void onBitmapFailed(Drawable drawable) {
            poster.setBackgroundResource(R.color.white);
        }
    };

    // Save strong reference to be able to show pictures without sliding the screen
    poster.setTag(target);

    Picasso.with(getContext()).load(movieObject.poster_path).into((Target) poster.getTag());

    // If movie doesn't have an image - uses text instead
    if (movieObject.poster_path.contains("null"))
    {
        TextView imageText = (TextView) view.findViewById(R.id.movie_poster_text);
        imageText.setText(movieObject.title);
    }
    poster.setContentDescription(movieObject.title);

    return view;
}

How can I solve this problem?

Add: I also tried saving Targets in a MovieObject, I also tried declaring separate class for Target - nothing helped.

Community
  • 1
  • 1
Dmytro Karataiev
  • 1,214
  • 1
  • 14
  • 19
  • have you tried the viewholder pattern? also if you use viewholder pattern dont use targets, alternatively you can try to use recyclerviews – Bhargav Dec 18 '15 at 22:24
  • The first thing I see here is that you are going to have a bad time because you didn't implement `equals` and `hashCode` on your `Target`. https://square.github.io/picasso/2.x/picasso/com/squareup/picasso/Target.html – Eric Cochran Dec 18 '15 at 22:40
  • @Bhargav, thank you for your comment, solved the problem with a CallBack. As for viewholder (as far as I understand, correct me if I'm wrong please) - it won't help me with the progressbar (it should disappear on loading of the image). – Dmytro Karataiev Dec 18 '15 at 23:09
  • @EricCochran, yes, I've read about these methods and I'm still not convinced, that they would help. Could you please give me a link on some example of their usage or a better explanation? Thank you in advance! – Dmytro Karataiev Dec 18 '15 at 23:11
  • @DmytroKarataiev It's to tell Picasso to "cancel" the previous call to an equivalent `Target`. You could end up with the wrong images in there at the wrong time due to the reuse of these Views. – Eric Cochran Dec 19 '15 at 00:14
  • @EricCochran, thank you a lot, now it makes sense. I think my problem was because I hadn't implemented them. – Dmytro Karataiev Dec 19 '15 at 00:18

1 Answers1

0

Solved the problem with a callback:

@Override
public View getView(final int position, View view, ViewGroup parent) {

    ...

    spinner.setVisibility(View.VISIBLE);

    Picasso.with(getContext()).load(movieObject.poster_path).into(poster, new Callback() {
        @Override
        public void onSuccess() {
            spinner.setVisibility(View.GONE);
        }

        @Override
        public void onError() {
            poster.setBackgroundResource(R.color.white);
        }
    });

    ...

    return view;
}

I'm still not sure how the poster will be recycled.

In Picasso docs they have a following note:

Note: The Callback param is a strong reference and will prevent your Activity or Fragment from being garbage collected. If you use this method, it is strongly recommended you invoke an adjacent Picasso.cancelRequest(android.widget.ImageView) call to prevent temporary leaking.

Where should I implement it?

Dmytro Karataiev
  • 1,214
  • 1
  • 14
  • 19