Robin Eisenberg
Robin Eisenberg

Reputation: 1866

Dynamically adding items to FragmentGridPagerAdapter

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

Upvotes: 4

Views: 2358

Answers (2)

Wayne Piekarski
Wayne Piekarski

Reputation: 3232

This bug should have been fixed in the latest wearable support library 1.1, that came out with the latest Android Wear 5.0 release.

Upvotes: 1

matiash
matiash

Reputation: 55380

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.

Upvotes: 3

Related Questions