2

I am writing an Android TV app and have bumped into this issue. I have to replace all the rows in BrowseFragment with new ones on receiving an Event. What i've tried:

mRowsAdapter.clear();
...
mRowsAdapter.add(add new rows here);

Where mRowsAdapter is the ArrayObjectAdapter with ListRow items. Also tried this approach:

mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
setAdapter(mRowsAdapter);
mRowsAdapter.add(add new rows here);

And the solutions from this question. Neither of them works. I keep getting IOBE. Here are the logs:

                               java.lang.IndexOutOfBoundsException: Index: 7, Size: 0
                                   at java.util.ArrayList.get(ArrayList.java:411)
                                   at android.support.v17.leanback.widget.ArrayObjectAdapter.get(ArrayObjectAdapter.java:56)
                                   at android.support.v17.leanback.app.ListRowDataAdapter.get(ListRowDataAdapter.java:65)
                                   at android.support.v17.leanback.widget.ItemBridgeAdapter.getItemViewType(ItemBridgeAdapter.java:248)
                                   at android.support.v7.widget.RecyclerView$Recycler.validateViewHolderForOffsetPosition(RecyclerView.java:5046)
                                   at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5172)
                                   at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5153)
                                   at android.support.v17.leanback.widget.GridLayoutManager.getViewForPosition(GridLayoutManager.java:971)
                                   at android.support.v17.leanback.widget.GridLayoutManager$2.createItem(GridLayoutManager.java:1464)
                                   at android.support.v17.leanback.widget.SingleRow.appendVisibleItems(SingleRow.java:111)
                                   at android.support.v17.leanback.widget.Grid.appendVisibleItems(Grid.java:371)
                                   at android.support.v17.leanback.widget.GridLayoutManager.appendVisibleItems(GridLayoutManager.java:1702)
                                   at android.support.v17.leanback.widget.GridLayoutManager.fastRelayout(GridLayoutManager.java:1764)
                                   at android.support.v17.leanback.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:1888)
                                   at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3374)
                                   at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:3183)
                                   at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:3627)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.support.v17.leanback.widget.ScaleFrameLayout.onLayout(ScaleFrameLayout.java:172)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1741)
                                   at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1585)
                                   at android.widget.LinearLayout.onLayout(LinearLayout.java:1494)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.widget.FrameLayout.layoutChildren(FrameLayout.java:323)
                                   at android.widget.FrameLayout.onLayout(FrameLayout.java:261)
                                   at com.android.internal.policy.DecorView.onLayout(DecorView.java:724)
                                   at android.view.View.layout(View.java:17519)
                                   at android.view.ViewGroup.layout(ViewGroup.java:5612)
                                   at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2342)
                                   at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2069)
                                   at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1246)
                                   at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6301)
                                   at android.view.Choreographer$CallbackRecord.run(Choreographer.java:871)
                                   at android.view.Choreographer.doCallbacks(Choreographer.java:683)
                                   at android.view.Choreographer.doFrame(Choreographer.java:619)
com.cloudify E/AndroidRuntime:     at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:857)
                                   at android.os.Handler.handleCallback(Handler.java:751)
                                   at android.os.Handler.dispatchMessage(Handler.java:95)
                                   at android.os.Looper.loop(Looper.java:154)
                                   at android.app.ActivityThread.main(ActivityThread.java:6077)
                                   at java.lang.reflect.Method.invoke(Native Method)
                                   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865)
                                   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

Please help. Thank you.

Community
  • 1
  • 1

3 Answers3

0

Youre getting a index out of bounds because the internal array of objects in the adapter is trying to use its own size to determine where to add the items.

When you call .add() its internally doing this -

/**
 * Adds an item to the end of the list.
 *
 * @param item The item to add to the end of the list.
 */
public void add(Object item) {
    add(mItems.size(), item);
}
/**
 * Inserts an item into this list at the specified index.
 *
 * @param index The index at which the item should be inserted.
 * @param item The item to insert into the list.
 */
public void add(int index, Object item) {
    mItems.add(index, item);
    notifyItemRangeInserted(index, 1);
}

that means that some how you calling clear is temporarily leaving something out of whack and the internal index is off of what it actually is and the arraylist poops an IOBE. Maybe try using add(0, yourArray) instead.

EDIT:

try adding some kind of validation before you add your objects. Something like:

if((myAdapter.size() - 1) > indexImTryingToAddAt)
{
    myAdapter.addAll(indexImTryingToAddAt, arrayOfObjects);
}
else
{
    Log.d("index is larger than current adapter", indexImTryingToAddAt+"");
}
James andresakis
  • 5,335
  • 9
  • 53
  • 88
  • i read the sources. in the 'clear()' method you can see the mItems.clear() line which sets the mItems.size() to 0. I have checked it with debugger and everything works fine in that regard. adapter gets cleared and re-filled with data. the FC happens during the next UI redraw. Still no idea how to beat it. – Євген Гарастович Nov 07 '16 at 17:17
  • how about using the addAll() method? have you tried that? – James andresakis Nov 07 '16 at 17:50
  • You should debug then by adding breakpoints at lines in your code and the source. Somewhere something is being added at an invalid index. Debugging with breakpoints seems to be your only option. – James andresakis Nov 08 '16 at 20:29
0

Try to do this:

    mRowsAdapter.clear();
    mRowsAdapter.add(add new rows here);
    mRowsAdapter.notifyArrayItemRangeChanged(0, mRowsAdapter.size());
Mario Velasco
  • 3,336
  • 3
  • 33
  • 50
0

The way i solved a similar issue:

You cannot put an object with a set index into ArrayObjectAdapter, if the Array is empty.

https://developer.android.com/reference/android/support/v17/leanback/widget/ArrayObjectAdapter

void add (int index, Object item)

Inserts an item into this adapter at the specified index. If the index is > size() an exception will be thrown.

I don't know how sleek my solution is, but you can do the following:

Fill the Array with "dummy" objects

mRowsAdapter.add(0, new ListRow(new HeaderItem(""), new ArrayObjectAdapter()));
mRowsAdapter.add(1, new ListRow(new HeaderItem(""), new ArrayObjectAdapter()));
mRowsAdapter.add(2, new ListRow(new HeaderItem(""), new ArrayObjectAdapter()));

and when you callbacks are done, replace them:

mRowsAdapter.replace(0, new ListRow(new HeaderItem("List1"), list1));
mRowsAdapter.replace(1, new ListRow(new HeaderItem("List2"), list2));
mRowsAdapter.replace(2, new ListRow(new HeaderItem("List3"), list3));

This way you can also add the an item counter into the HeaderItem:

mRowsAdapter.replace(2, new ListRow(new HeaderItem("List3 (" + list3.size() + ")"), list3));
S0und
  • 257
  • 4
  • 12