MaterialList icon indicating copy to clipboard operation
MaterialList copied to clipboard

ArrayIndexOutOfBoundsException in SwipeDismissListener

Open eeandrew opened this issue 10 years ago • 12 comments

snapnote-demo

java.lang.ArrayIndexOutOfBoundsException: length=12; index=-1
            at java.util.ArrayList.get(ArrayList.java:310)
            at android.widget.ArrayAdapter.getItem(ArrayAdapter.java:337)
            at com.dexafree.materialList.controller.SwipeDismissListener.isCurrentItemDismissable(SwipeDismissListener.java:359)
            at com.dexafree.materialList.controller.SwipeDismissListener.onTouch(SwipeDismissListener.java:197)
            at android.view.View.dispatchTouchEvent(View.java:8382)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2424)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2158)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2430)
            at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2172)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2314)
            at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1692)
            at android.app.Activity.dispatchTouchEvent(Activity.java:2739)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2275)
            at android.view.View.dispatchPointerEvent(View.java:8578)
            at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:4021)
            at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3887)
            at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
            at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3502)
            at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
            at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3578)
            at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
            at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3635)
            at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
            at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3502)
            at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3468)
            at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3476)
            at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3449)
            at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5701)
            at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5675)
            at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5646)
            at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5791)
            at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:185)
            at android.os.MessageQueue.nativePollOnce(Native Method)
            at android.os.MessageQueue.next(MessageQueue.java:143)
            at android.os.Looper.loop(Looper.java:122)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Nati

eeandrew avatar Jan 09 '15 04:01 eeandrew

I've got the same exception in another context. See #24

FHellmann avatar Jan 09 '15 08:01 FHellmann

The Exception I got is fixed with my Pull Request #23. Could you try, if it is also fixed for you?

FHellmann avatar Jan 09 '15 08:01 FHellmann

To me it looks like the underlying array list that holds the models is not correctly updated. E.g. there is no place in the code where you ever call mAdapter.remove()

I'm just playing around with onCardDismiss method in MaterialListView:

@Subscribe
    public void onCardDismiss(DismissEvent event){
        Card dismissedCard = event.getDismissedCard();
        View dismissedCardView = null;
        for (int index = 0; index < getCount(); index++) {
            View view = getChildAt(index);
            if(view != null && view.getTag() != null && view.getTag().equals(dismissedCard)) { //add null check on view itself
                dismissedCardView = view;
                break;
            }
        }
        if(dismissedCardView != null) {
            mDismissListener.dismissCard(dismissedCardView, dismissedCard);
        }
    mAdapter.remove(dismissedCard); //Actually remove dismissed model (card) from ArrayList
    }

Adding the null check on view itself helped me avoiding the following Runtime / Nullpointer Exceptions that occured when I updated the model asynchronously.

java.lang.RuntimeException: Could not dispatch event: class com.dexafree.materialList.events.DismissEvent to handler [EventHandler public void com.dexafree.materialList.view.MaterialListView.onCardDismiss(com.dexafree.materialList.events.DismissEvent)]: Attempt to invoke virtual method 'java.lang.Object android.view.View.getTag()' on a null object reference
            at com.squareup.otto.Bus.throwRuntimeException(Bus.java:456)
            at com.squareup.otto.Bus.dispatch(Bus.java:386)
            at com.squareup.otto.Bus.dispatchQueuedEvents(Bus.java:367)
            at com.squareup.otto.Bus.post(Bus.java:336)
            at com.dexafree.materialList.events.MainThreadBus.post(MainThreadBus.java:31)
            at com.dexafree.materialList.events.BusProvider.dismiss(BusProvider.java:22)
            at com.blockconsult.nominator.MainActivity$2.onButtonPressedListener(MainActivity.java:106)
            at com.dexafree.materialList.cards.view.BaseButtonsCardItemView$1.onClick(BaseButtonsCardItemView.java:41)
            at android.view.View.performClick(View.java:4756)
            at android.view.View$PerformClick.run(View.java:19749)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.view.View.getTag()' on a null object reference
            at com.dexafree.materialList.view.MaterialListView.onCardDismiss(MaterialListView.java:164)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.squareup.otto.EventHandler.handleEvent(EventHandler.java:89)
            at com.squareup.otto.Bus.dispatch(Bus.java:384)
            at com.squareup.otto.Bus.dispatchQueuedEvents(Bus.java:367)
            at com.squareup.otto.Bus.post(Bus.java:336)
            at com.dexafree.materialList.events.MainThreadBus.post(MainThreadBus.java:31)
            at com.dexafree.materialList.events.BusProvider.dismiss(BusProvider.java:22)
            at com.blockconsult.nominator.MainActivity$2.onButtonPressedListener(MainActivity.java:106)
            at com.dexafree.materialList.cards.view.BaseButtonsCardItemView$1.onClick(BaseButtonsCardItemView.java:41)
            at android.view.View.performClick(View.java:4756)
            at android.view.View$PerformClick.run(View.java:19749)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

Also I added the mAdapter.remove(card) call to actually update the underlying array list that holds the models (cards). To me this still feels hacky as I do not (yet) understand where model <-> view synchronization is supposed to happen but at least I have no more exceptions in my app.

cblock avatar Jan 11 '15 11:01 cblock

...ok. I was too fast. After the above updates the underlying model list is now seriously broken. Maybe some of you guys has a better idea. I guess one of the problems is that most real life implementations load the data asynchronously (e.g. making network calls inside UIThread to load data is prohibited). But the current implementation seems to be not thread safe.

cblock avatar Jan 11 '15 11:01 cblock

@FHellmann I adapt your modifications, now this exception will not be thrown. Thanks. However I got another bug, Please help me. If I swipe out the card from the bottom up, it works totally fine. However, If I swipe out the card from the top down or any other way (except the bottom-up way), I got this following bug:

Here is the Java Code for My Card: SnapNoteMainCard

Here is the Java Code for My Card View: SnapNoteMainCardItemView

snapnote-bug-demo

eeandrew avatar Jan 12 '15 04:01 eeandrew

@cblock The Call to remove a card from the Adapter is inside of the OnDismissCallback. You're right. Currently the Adapter is not Thread save. I will fix this after my exams, or maybe you create a Pull Request. ;-)

FHellmann avatar Jan 12 '15 07:01 FHellmann

@eeandrew Your Bug does not come from your Card Code. Dismissing the Card will be called from the SwipeDismissListener which calls the OnDismissCallback where the Card will be removed then. I can't explain this behavior to me. I will take a look at this Bug as soon I will find the time.

FHellmann avatar Jan 12 '15 08:01 FHellmann

@FHellmann It seems the layout is changed from RelativeLayout to LinearLayout.

eeandrew avatar Jan 13 '15 02:01 eeandrew

I am also still having this issue when swiping away cards. Was this marked as fixed?

ghost avatar May 05 '15 20:05 ghost

I get this exception and I'm not using the Swipe ability or the OnDismissCallback. It's hard for me to replicate what causes this.

java.lang.ArrayIndexOutOfBoundsException: length=12; index=-1
at  java.util.ArrayList.get(ArrayList.java:310)
at  com.dexafree.materialList.controller.MaterialListAdapter.getCard(MaterialListAdapter.java:97)
at  com.dexafree.materialList.view.MaterialListView$2.canDismiss(MaterialListView.java:62)
at com.dexafree.materialList.controller.SwipeDismissRecyclerViewTouchListener.onTouch(SwipeDismissRecyclerViewTouchListener.java:212)
at  android.view.View.dispatchTouchEvent(View.java:8382)

maarek avatar Aug 24 '15 20:08 maarek

@maarek do you already use the current version (3.0.1) of MaterialList?

FHellmann avatar Aug 28 '15 12:08 FHellmann

@FHellmann No. On 2.4.5. Found out last night why I was having issues with this. One word: Threads. The cards were being refreshed (cleared and readded) on a background thread.This caused all of the arraylist issues I have been seeing in the adapter.

maarek avatar Aug 28 '15 15:08 maarek