Dynamically adding items to FragmentGridPagerAdapter
android, fragmentpageradapter, wear-os
Solution
Line 873 in `GridViewPager.populate()` is this:
this.mRowScrollX[row] = computePageLeft(...);
Looks like the length of the `mRowScroll` array is fixed when setting the adapter, and not updated from `getRowCount()` when `notifyDataSetChanged()` is fired. Indeed, if you check the rest of the `GridViewPager` class, you'll see it's only assigned in the `setAdapter()` method:
this.mExpectedRowCount = this.mAdapter.getRowCount();
this.mRowScrollX = new int[this.mExpectedRowCount];
In short, I would think this is a bug in `GridViewPager`, which could be circumvented by calling `setAdapter()` again whenever you want to update the row or column count.
Problem
I'm trying to display a FragmentGridPagerAdapter with 4 entries, and when the view scrolls I want to add items to the adapter. This is my FragmentPagerAdapter: ``` public class MyPagerAdapter extends FragmentGridPagerAdapter { private final Context _ctx; private HashMap<Integer, Entry> _data; public MyPagerAdapter(Context context, FragmentManager fm, HashMap<Integer, Entry> tidatals) { super(fm); _ctx = context; _data = data; } public void addEntry(Entry entry) { _data.put(_data.size(), entry); this.notifyDataSetChanged(); } @Override public Fragment getFragment(int i, int i2) { CardFragment fragment = CardFragment.create("Card", _data.get(i).getPrettyText()); fragment.setCardGravity(Gravity.BOTTOM); fragment.setExpansionEnabled(true); return fragment; } @Override public int getRowCount() { return _data.size(); } @Override public int getColumnCount(int i) { return 1; } ``` } And this is how I add data to the adapter in my Main Wear Activity: ``` //In onCreate: _data = new HashMap<Integer, Entry>(); _adapter = new TILPagerAdapter(this, getFragmentManager(), _data); _pager.setAdapter(_adapter); //When I finally get my data: ... // Do stuff, get datas in 'data' variable MainWear.this.runOnUiThread(new Runnable() { @Override public void run() { boolean firstData = _data.isEmpty(); for(TILEntry entry : data.values()) { _adapter.addEntry(entry); } if(firstData){ _pager.setAdapter(_adapter); switchViewToResults(); // Sets pager to visible } } }); ``` When I add items into the adapter and call notifyDataSetChanged(), the adapter refreshes fine, however it crashes when I scroll towards the added pages. Here is the stacktrace: ``` E/InputEventReceiver﹕ Exception dispatching input event. E/MessageQueue-JNI﹕ Exception in MessageQueue callback: handleReceiveCallback E/MessageQueue-JNI﹕ java.lang.ArrayIndexOutOfBoundsException: length=4; index=4 at android.support.wearable.view.GridViewPager.populate(GridViewPager.java:873) at android.support.wearable.view.GridViewPager.setCurrentItemInternal(GridViewPager.java:584) at android.support.wearable.view.GridViewPager.handlePointerUp(GridViewPager.java:1990) at android.support.wearable.view.GridViewPager.onTouchEvent(GridViewPager.java:1492) at android.view.View.dispatchTouchEvent(View.java:7846) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2209) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1944) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2085) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1532) at android.app.Activity.dispatchTouchEvent(Activity.java:2468) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2033) at android.view.View.dispatchPointerEvent(View.java:8026) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3989) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3868) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3433) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3483) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3452) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3559) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3460) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3616) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3433) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3483) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3452) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3460) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3433) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5589) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5569) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5540) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5669) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:5026) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) at dalvik.system.NativeStart.main(Native Method) D/AndroidRuntime﹕ Shutting down VM W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xadb04d70) E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: til.wear.robineisenberg.til_wear, PID: 5808 java.lang.ArrayIndexOutOfBoundsException: length=4; index=4 at android.support.wearable.view.GridViewPager.populate(GridViewPager.java:873) at android.support.wearable.view.GridViewPager.setCurrentItemInternal(GridViewPager.java:584) at android.support.wearable.view.GridViewPager.handlePointerUp(GridViewPager.java:1990) at android.support.wearable.view.GridViewPager.onTouchEvent(GridViewPager.java:1492) at android.view.View.dispatchTouchEvent(View.java:7846) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2209) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1944) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2215) at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1958) at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2085) at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1532) at android.app.Activity.dispatchTouchEvent(Activity.java:2468) at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2033) at android.view.View.dispatchPointerEvent(View.java:8026) at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3989) at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3868) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3433) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3483) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3452) at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3559) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3460) at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3616) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3433) at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3483) at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3452) at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3460) at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3433) at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5589) at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5569) at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5540) at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5669) at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185) at android.os.MessageQueue.nativePollOnce(Native Method) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:123) at android.app.ActivityThread.main(ActivityThread.java:5026) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:602) at dalvik.system.NativeStart.main(Native Method) ``` I printed the size of _data my Adapter when getFragment is called, _data.size() is correctly worth 8 when getFragment is called. In the log, 4 is the size of the initial adapter size. 8 is the desired size afterwards. It doesn't crash upon adding the items, but only upon scrolling through the cards towards the new items. What am I doing wrong? EDIT: Indeed, this seems to be an ommission in the notifyDataSetChanged function of the adapter. I opened a bug report w/ Google, star it if you think this needs to be fixed: https://code.google.com/p/android/issues/detail?id=73846&thanks=73846&ts=1405945122