13

I am having an issue with GridLayoutManger setSpanSizeLookup, when an orientation of activity changes, I am changing the span count while checking if the specific position is some sort of type, this works perfectly on orientation change, my only problem is, I'm using zxing library to do barcode scanning, whenever a button is clicked I'm opening the zxing default intent and retrieve date from it, however when zxing is opening it goes to landscape and my current activity orientation is portrait this gives me the IllegalArgumentException that the layout manage throws when only opening the Xzing intent, the crash log is as this
java.lang.IllegalArgumentException: Item at position 0 requires 2 spans but GridLayoutManager has only 1 spans.
this problem doesn't occur if i rotate the phone, only happens when I launch the Xzing intent, i couldn't really figure out how how I solve this issue as its bugging me. here is my spanSizeLookup -

manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
     @Override
     public int getSpanSize(int position) {
        return adapter.getHolders().get(position).getLabelHolder() != null ? getResources().getInteger(R.integer.span) : 1;
     }
});

the span is base on screen size so it can be 1-2, 2-3 and 3-4. i repeat this doesn't give me any error on orientation change, only the error occur when I open the zxing
P.S if i open zxing intent while my activity is on landspace the crash wont occur.

Edit

it seems like only launching the zxing default intent causing this issue, I'm having an activity where it goes landscape after it launches and the exception didn't occur, as a workaround i did, was that i created an activity that handles the barcode scanning with a delay of 1 second to launch the intent as if i didn't do that, it will throw the same exception.

Edit 2

I just found that, even without setSpanSpizeLookup the crash still occurs. by just calling manager.setSpanCount(getResources().getInteger(R.integer.span))

Aditi Parikh
  • 1,522
  • 3
  • 13
  • 34
Kosh
  • 6,140
  • 3
  • 36
  • 67

4 Answers4

9

Here's the source code that throws the exception in GridLayoutManager.layoutChunk()

final int spanSize = getSpanSize(recycler, state, pos);
if (spanSize > mSpanCount) {
    throw new IllegalArgumentException("Item at position " + pos + " requires " +
           spanSize + " spans but GridLayoutManager has only " + mSpanCount
           + " spans.");
}

Is your spanSize greater than your spanCount? Try to debug and probably change your spanCount and see how it works.

---- Updated ----

There're couple ways to switch between list and grid.

  1. Only changing the spanCount.

    You have to call LayoutManager.requestLayout() after you change your spanCount. Otherwise your app may crash.

  2. Only changing the SpanSizeLookUp.

    private class CustomSpanSize extends GridLayoutManager.SpanSizeLookup {
    
      private static final int LIST_SPAN_SIZE = 1;
      private static final int GRID_SPAN_SIZE = 2;
    
      private int mSpanSize = LIST_SPAN_SIZE;
    
      public void asList() {
        mSpanSize = LIST_SPAN_SIZE;
      }
    
      public void asGrid() {
        mSpanSize = GRID_SPAN_SIZE;
      }
    
      @Override
      public int getSpanSize(int position) {
        return mSpanSize;
      }
    }
    

    and use it like that

    @Override
    protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
    
      mLayoutManager = new GridLayoutManager(this, 2);
    
      mCustomSpanSize = new CustomSpanSize();
      mLayoutManager.setSpanSizeLookup(mCustomSpanSize);
      RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler);
      recyclerView.setHasFixedSize(true);
      recyclerView.setLayoutManager(mLayoutManager);
    
      ...
    }
    
    public void someFunction() {
      if (changed) {
        mCustomSpanSize.asList();
      } else {
        mCustomSpanSize.asGrid();
      }
      // use this to update the layout
      mAdapter.notifyDataSetChanged();
      // or you can use this to update the layout
      mLayoutManager.requestLayout();
    }
    

    this way won't crash even you forget to call notifyDataSetChanged or requestLayout

Trey Cai
  • 1,195
  • 1
  • 12
  • 18
  • hi Trey, thanks for the answer, if you read through my question, that exception never occur if i rotate the phone manually, however it happens when i lunch zxing intent which in turn make my current activity goes landscape and crashes, thats what confusing me, if i rotate it, it wont crash – Kosh Aug 15 '15 at 08:53
  • 1
    hi k0sh, may I ask when your GridLayoutManager will has only 1 span. – Trey Cai Aug 15 '15 at 09:02
  • when there is an item that is for example lets called it SEPARATOR – Kosh Aug 15 '15 at 09:04
  • sorry for late response. could you post some sample code for me to debug? i need some code that will reproduce the crash. – Trey Cai Aug 17 '15 at 03:18
  • hi Trey, its okay. here is a project i started yesterday, you could pull it and in Home class, line 115, remove manager.requestLayout() and it will be crashing as well, i will try and make a simple project later as i am at work right now. https://github.com/k0shk0sh/KAM – Kosh Aug 17 '15 at 03:21
  • 1
    It's nothing wrong about your sample code. You have to call `requestLayout` after you change your spanCount. especially when you try to change spanCount smaller. Changing spanSize to switch between list and grid is another way. A safety way. It won't crash if you forget to `requestLayout`. also you can call `Adapter.notifyDataSetChanged()` to update the spanSize. – Trey Cai Aug 18 '15 at 15:09
  • Thanks Trey to keep updating me on this, i will check with tomorrow morning and update you back. – Kosh Aug 18 '15 at 15:11
  • hi Trey, calling requestLayout followed by adapter.notifyDtaSetChanged() does not solve the issue. i guess its an internal bug in android, i can't even try block it to prevent the crash. – Kosh Aug 20 '15 at 02:24
  • oh my bad. sorry to make you confused. What I mean is, for changing spanCount, you have to call requestLayout, but for changing spanSizeLookUp, you can call requestLayout or Adapter.notifyDataSetChanged – Trey Cai Aug 20 '15 at 03:57
  • you mean adding the request layout inside of the spansize lookup method? i have added below it on configuration change im calling requestLayout and also notifying adapter. that didn't do it . so frustrated about it :D . – Kosh Aug 20 '15 at 03:59
  • Hello Trey, please check my answer if you have any clue why was it the cause. thanks for your help tho. – Kosh Dec 21 '16 at 14:35
0

Edit: call setSpanCount() and make it a bigger number than that span no? Perhaps more code would be in order.

That sounds like it could have been a concurrent modification error. Try not using a delay per sé, but running modifications on the UI thread. This will block the UI from trying to access the list.

if(adapter.getHolders().get(position).getLabelHolder() != null)
    return getResources().getInteger(R.integer.column);
else 
    return 1;

so what is getResources().getInteger(R.integer.column)?

Isn't that going to be the same number every time?

Sinister Beard
  • 3,570
  • 12
  • 59
  • 95
Andrew G
  • 2,596
  • 2
  • 19
  • 26
  • getResources().getInteger(R.integer.column) depends on the orientation as i mentioned it can be 2,3,4 depending on which device size and which orientation the device is – Kosh Aug 15 '15 at 06:45
  • ah, got it. slightly confusing attribute name. – Andrew G Aug 15 '15 at 06:50
  • kinda of, as im using that attr with different stuff, so instead of creating new attr that does the same im re-using it :p, im not really sure if i tried ur solution, however i will check it right away and update u – Kosh Aug 15 '15 at 06:59
  • did you read the doc on that. It's not exactly obvious. https://developer.android.com/reference/android/support/v7/widget/GridLayoutManager.html#setSpanCount(int) ...Because once you've turned the device columns have changed orientation. They're still columns. Clear as mud. – Andrew G Aug 15 '15 at 07:24
  • the orientation is always vertical for gridLayoutManager, the only thing that changes is the spanCount. – Kosh Aug 15 '15 at 07:26
  • Try not overriding it. and just using the methods in the API first! – Andrew G Aug 15 '15 at 07:26
  • override what? im just setting the spanCount and the issue still occurs. – Kosh Aug 15 '15 at 07:27
  • I think you're confused about which span you're referring to. the `GridLayoutManager.SpanSizeLookup` class you extend is for determining span of each item, not of the entire structure. – Andrew G Aug 15 '15 at 07:53
  • 1
    Andy, lets get things together shall we? spanSizeLookup is meant to customize each row of the gridmanager and how would you determine if first row should display two or one, which setSpanCount is meant to determine how many spans per row should the gridmanager takes, if you read my second update which mention even without setspansizelookup the crash still occurs. i think i know what im doing – Kosh Aug 15 '15 at 08:00
0

Amazingly, I had the same issue and just found the solution. After initializing the GridLayoutManager with the spanCount passed in the constructor, our app would crash. BUT, if I setSpanCount() after constructing the object, IT WORKS! :O

We're using RecyclerView 23.0.1. hope this helps someone.

Henrique de Sousa
  • 5,727
  • 49
  • 55
0

Too late to answer this question, however in a latest project that i worked on, i faced the same issue & after some really debugging, i found out what was the cause to the issue but no clue why would it cause it.

zxing Library intent it actually calls CLEAR_TOP before calling the startActivityForResult & that was the problem, after modifying the source code of zxing Intent to remove that particular line, the crash is gone.

Kosh
  • 6,140
  • 3
  • 36
  • 67