0

I'm getting ArrayIndexOutOfBoundsException pointing to my onError method of Picasso:

Picasso.get().load(category.get(holder.getAdapterPosition()).getImage()).noFade().tag("tag").resize(100, 100).centerCrop().networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.image_placeholder).into(holder.img, new Callback() {

        @Override
        public void onSuccess() {}

        @Override
        public void onError(Exception e) {
            //Error points to this line
            Picasso.get().load(category.get(holder.getAdapterPosition()).getImage()).noFade().resize(100, 100).centerCrop().memoryPolicy(MemoryPolicy.NO_CACHE).placeholder(R.drawable.image_placeholder).into(holder.img);
        }

    });

I was not able to reproduce this issue on my device, so I'm not sure why it is happening?

So far this only happens on devices running Android 8.0.0.

I have internet permissions.

Here is my log from crashlytics:

Fatal Exception: java.lang.ArrayIndexOutOfBoundsException: length=73; index=-1
   at java.util.ArrayList.get(ArrayList.java:439)
   at com.app.name.Recycler.RecyclerVideoAdapter$2.onError(RecyclerVideoAdapter.java:413)
   at com.squareup.picasso.ImageViewAction.error(ImageViewAction.java:72)
   at com.squareup.picasso.Picasso.deliverAction(Picasso.java:581)
   at com.squareup.picasso.Picasso.complete(Picasso.java:535)
   at com.squareup.picasso.Picasso$1.handleMessage(Picasso.java:122)
   at android.os.Handler.dispatchMessage(Handler.java:105)
   at android.os.Looper.loop(Looper.java:164)
   at android.app.ActivityThread.main(ActivityThread.java:6944)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Any help would be appreciated.

Edit 1:

To clarify, I changed the following from:

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {

Picasso.get().load(category.get(holder.getAdapterPosition()).getImage()).noFade().tag("tag").resize(100, 100).centerCrop().networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.image_placeholder).into(holder.img, new Callback() {

    @Override
    public void onSuccess() {}

    @Override
    public void onError(Exception e) {
        //Error points to this line
        Picasso.get().load(category.get(holder.getAdapterPosition()).getImage()).noFade().resize(100, 100).centerCrop().memoryPolicy(MemoryPolicy.NO_CACHE).placeholder(R.drawable.image_placeholder).into(holder.img);
    }

});

to the following:

@Override
public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) {
final int adapterPosition = holder.getAdapterPosition();
Picasso.get().load(category.get(adapterPosition).getImage()).noFade().tag("tag").resize(100, 100).centerCrop().networkPolicy(NetworkPolicy.OFFLINE).placeholder(R.drawable.image_placeholder).into(holder.img, new Callback() {

    @Override
    public void onSuccess() {}

    @Override
    public void onError(Exception e) {
        //Error points to this line
        Picasso.get().load(category.get(adapterPosition).getImage()).noFade().resize(100, 100).centerCrop().memoryPolicy(MemoryPolicy.NO_CACHE).placeholder(R.drawable.image_placeholder).into(holder.img);
    }

});
ClassA
  • 2,480
  • 1
  • 26
  • 57
  • 1
    the problem is that `holder.getAdapterPosition()` is returning -1. I'd recommend you declaring a final variable like `final int adapterPosition = holder.getAdapterPosition()` before first line of provided code, and using `adapterPosition` instead of `holder.getAdapterPosition()` because `holder.getAdapterPosition()` may change between you call `Picasso` and `onError` happens – Vladyslav Matviienko Oct 19 '18 at 04:55
  • @VladyslavMatviienko Thank you, I recently made changes to `holder.getAdapterPosition()` by removing the `final` before position in my `onBindViewHolder` and started using `holder.getAdapterPosition()` instead. I will change it to declaring it like you said. Thank you once again. – ClassA Oct 19 '18 at 05:00
  • @VladyslavMatviienko can you please look at edit 1 and confirm that what I'm doing now is correct? – ClassA Oct 19 '18 at 05:05
  • yes you did exactly what I meant – Vladyslav Matviienko Oct 19 '18 at 05:07
  • 1
    but why don't you use the `position` variable instead of getting it dynamically? – Vladyslav Matviienko Oct 19 '18 at 05:07
  • @VladyslavMatviienko I stopped using it because I read somewhere that `position` should not be final in `onBindViewHolder`, not sure why I changed it in the first place. – ClassA Oct 19 '18 at 05:14
  • I disagree with that it should not be final. There is no single reason for that – Vladyslav Matviienko Oct 19 '18 at 05:15
  • @VladyslavMatviienko Ok I will go back to using `position` then. In other words I wasted your time and mine, lol. Sorry about that. – ClassA Oct 19 '18 at 05:17
  • no problems. Looks like I have just found the source where you read about that position is bad. https://medium.com/@haydar_ai/better-way-to-get-the-item-position-in-androids-recyclerview-820667d435d4 However, I see no proofs that it is true, and even if that was a problem in some version of Android's support lib, it should be already fixed. – Vladyslav Matviienko Oct 19 '18 at 05:20
  • @VladyslavMatviienko Yes that was the exact article I read. I also got this lint warning when changing it to `final` - https://stackoverflow.com/questions/34942840/lint-error-do-not-treat-position-as-fixed-only-use-immediately – ClassA Oct 19 '18 at 05:24
  • @VladyslavMatviienko and also this answer - https://stackoverflow.com/a/37500645/8199772 – ClassA Oct 19 '18 at 05:27
  • The last link makes sense. So probably you should revert to the code you had originally, but only add some check for `holder.getAdapterPosition() >= 0 && holder.getAdapterPosition() < getCount()` – Vladyslav Matviienko Oct 19 '18 at 07:12

0 Answers0