web-dev-qa-db-fra.com

IllegalArgumentException: pointerIndex en dehors de SwipeRefreshLayout

J'ai eu quelques crashs IllegalArgumentException: pointerIndex out of range sur crashlytics et je ne comprends pas ce qui se passe. Cela ne se limite pas à une version ou à un appareil Android, cela se produit sur les versions 5.0.1, 4.4.4, 4.4.2, 4.0.4, 2.3.6, le tout sur différents appareils. Vous trouverez ci-dessous la sortie complète du journal pour plus de contexte.

Java.lang.RuntimeException: Unable to destroy activity {com.mypackage.myapp/com.mypackage.myapp.MyListActivity}: Java.lang.IllegalArgumentException: pointerIndex out of range
       at Android.app.ActivityThread.performDestroyActivity(ActivityThread.Java:3671)
       at Android.app.ActivityThread.handleDestroyActivity(ActivityThread.Java:3689)
       at Android.app.ActivityThread.handleRelaunchActivity(ActivityThread.Java:3889)
       at Android.app.ActivityThread.access$900(ActivityThread.Java:144)
       at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1284)
       at Android.os.Handler.dispatchMessage(Handler.Java:102)
       at Android.os.Looper.loop(Looper.Java:135)
       at Android.app.ActivityThread.main(ActivityThread.Java:5221)
       at Java.lang.reflect.Method.invoke(Method.Java)
       at Java.lang.reflect.Method.invoke(Method.Java:372)
       at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:898)
       at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:693)
Caused by: Java.lang.IllegalArgumentException: pointerIndex out of range
       at Android.view.MotionEvent.nativeGetAxisValue(MotionEvent.Java)
       at Android.view.MotionEvent.getY(MotionEvent.Java:1998)
       at Android.support.v4.view.MotionEventCompatEclair.getY(MotionEventCompatEclair.Java:35)
       at Android.support.v4.view.MotionEventCompat$EclairMotionEventVersionImpl.getY(MotionEventCompat.Java:95)
       at Android.support.v4.view.MotionEventCompat.getY(MotionEventCompat.Java:228)
       at Android.support.v4.widget.SwipeRefreshLayout.onTouchEvent(SwipeRefreshLayout.Java:772)
       at Android.view.View.dispatchTouchEvent(View.Java:8388)
       at Android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.Java:2398)
       at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:2158)
       at Android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.Java:2400)
       at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:2172)
       at Android.view.ViewGroup.cancelTouchTarget(ViewGroup.Java:2340)
       at Android.view.ViewGroup.removeViewInternal(ViewGroup.Java:4156)
       at Android.view.ViewGroup.removeViewInternal(ViewGroup.Java:4136)
       at Android.view.ViewGroup.removeView(ViewGroup.Java:4068)
       at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1045)
       at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1126)
       at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1108)
       at Android.support.v4.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.Java:1954)
       at Android.support.v4.app.FragmentActivity.onDestroy(FragmentActivity.Java:313)
       at Android.support.v7.app.ActionBarActivity.onDestroy(ActionBarActivity.Java:169)
       at com.mypackage.myapp.BaseActivity.onDestroy(BaseActivity.Java:105)
       at Android.app.Activity.performDestroy(Activity.Java:6112)
       at Android.app.Instrumentation.callActivityOnDestroy(Instrumentation.Java:1140)
       at Android.app.ActivityThread.performDestroyActivity(ActivityThread.Java:3658)
       at Android.app.ActivityThread.handleDestroyActivity(ActivityThread.Java:3689)
       at Android.app.ActivityThread.handleRelaunchActivity(ActivityThread.Java:3889)
       at Android.app.ActivityThread.access$900(ActivityThread.Java:144)
       at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1284)
       at Android.os.Handler.dispatchMessage(Handler.Java:102)
       at Android.os.Looper.loop(Looper.Java:135)
       at Android.app.ActivityThread.main(ActivityThread.Java:5221)
       at Java.lang.reflect.Method.invoke(Method.Java)
       at Java.lang.reflect.Method.invoke(Method.Java:372)
       at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:898)
       at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:693)

Voici un autre rapport d'accident connexe provenant de Android.view.MotionEvent.getY().

Java.lang.RuntimeException: Unable to destroy activity {com.mypackage.myapp/com.mypackage.myapp.MyListActivity}: Java.lang.ArrayIndexOutOfBoundsException
       at Android.app.ActivityThread.performDestroyActivity(ActivityThread.Java:2683)
       at Android.app.ActivityThread.handleDestroyActivity(ActivityThread.Java:2701)
       at Android.app.ActivityThread.handleRelaunchActivity(ActivityThread.Java:2817)
       at Android.app.ActivityThread.access$1600(ActivityThread.Java:117)
       at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:946)
       at Android.os.Handler.dispatchMessage(Handler.Java:99)
       at Android.os.Looper.loop(Looper.Java:130)
       at Android.app.ActivityThread.main(ActivityThread.Java:3733)
       at Java.lang.reflect.Method.invokeNative(Method.Java)
       at Java.lang.reflect.Method.invoke(Method.Java:507)
       at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:931)
       at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:689)
       at dalvik.system.NativeStart.main(NativeStart.Java)
Caused by: Java.lang.ArrayIndexOutOfBoundsException
       at Android.view.MotionEvent.getY(MotionEvent.Java:903)
       at Android.support.v4.view.MotionEventCompatEclair.d(MotionEventCompatEclair.Java:35)
       at Android.support.v4.view.MotionEventCompat$EclairMotionEventVersionImpl.d(MotionEventCompat.Java:95)
       at Android.support.v4.view.MotionEventCompat.d(MotionEventCompat.Java:228)
       at Android.support.v4.widget.SwipeRefreshLayout.onTouchEvent(SwipeRefreshLayout.Java:772)
       at Android.view.View.dispatchTouchEvent(View.Java:3971)
       at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:903)
       at Android.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.Java:1154)
       at Android.view.ViewGroup.removeViewInternal(ViewGroup.Java:2201)
       at Android.view.ViewGroup.removeViewInternal(ViewGroup.Java:2187)
       at Android.view.ViewGroup.removeView(ViewGroup.Java:2135)
       at Android.support.v4.app.FragmentManagerImpl.a(FragmentManager.Java:1045)
       at Android.support.v4.app.FragmentManagerImpl.a(FragmentManager.Java:1126)
       at Android.support.v4.app.FragmentManagerImpl.a(FragmentManager.Java:1108)
       at Android.support.v4.app.FragmentManagerImpl.t(FragmentManager.Java:1954)
       at Android.support.v4.app.FragmentActivity.onDestroy(FragmentActivity.Java:313)
       at Android.support.v7.app.ActionBarActivity.onDestroy(ActionBarActivity.Java:169)
       at com.mypackage.myapp.BaseActivity.onDestroy(BaseActivity.Java:105)
       at Android.app.ActivityThread.performDestroyActivity(ActivityThread.Java:2670)
       at Android.app.ActivityThread.handleDestroyActivity(ActivityThread.Java:2701)
       at Android.app.ActivityThread.handleRelaunchActivity(ActivityThread.Java:2817)
       at Android.app.ActivityThread.access$1600(ActivityThread.Java:117)
       at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:946)
       at Android.os.Handler.dispatchMessage(Handler.Java:99)
       at Android.os.Looper.loop(Looper.Java:130)
       at Android.app.ActivityThread.main(ActivityThread.Java:3733)
       at Java.lang.reflect.Method.invokeNative(Method.Java)
       at Java.lang.reflect.Method.invoke(Method.Java:507)
       at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:931)
       at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:689)
       at dalvik.system.NativeStart.main(NativeStart.Java)

Ma question est donc de savoir ce qui cause cette erreur et quelle serait la méthode acceptable pour atténuer ce problème.

EDIT: Voici le lien vers MotionEvent.Java:1998 qui est référencé dans le crash ci-dessus.

EDIT: Voici mon onDestroy ressemble à: 

@Override
public void onDestroy() {

    AppMsg.cancelAll();
    SuperCardToast.cancelAllSuperCardToasts();

    super.onDestroy();
}

Plus précisément, BaseActivity.Java:105 est l'endroit où j'appelle super.onDestroy();.

23
MrEngineer13

Je suppose que l'exception est levée tant qu'un événement tactile est toujours en cours (transmis au contact natif alors que l'activité est sur le point de onDestroy(). Il est correct d'atténuer cela en interceptant l'exception pour éviter un crash. Activité sur le point d'être détruit s'il est entré dans cet état. 

Je ne suis pas sûr (n'avez pas encore été testé), mais vous pouvez essayer d'empêcher que des événements soient transmis à la mise en œuvre, si une exception à la capture ne vous convient pas.

public class ComeUpWithBetterNameSwipeRefreshLayout extends SwipeRefreshLayout {

    private boolean mAcceptEvents;

    public ComeUpWithBetterNameSwipeRefreshLayout(Context context) {
        super(context);
    }

    public void setAcceptEvents(boolean mAcceptEvents) {
        this.mAcceptEvents = mAcceptEvents;
    }
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mAcceptEvents? super.onInterceptTouchEvent(ev) : true;
    }

    public ComeUpWithBetterNameSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mAcceptEvents = true;
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mAcceptEvents = false;
    }
}

ou 

@Override
public void onDestroy() {
    mSwipeRefreshLayout.setAcceptEvents(false);
    AppMsg.cancelAll();
    SuperCardToast.cancelAllSuperCardToasts();

    super.onDestroy();
}

Prendre 2:

SwipeRefreshLayout essaie d'obtenir getY () à partir d'un index de pointeur invalide. Si vous appelez findPointerIndex(ev, activePointer), -1 sera renvoyé s'il ne parvient pas à trouver. Empêcher l'envoi d'un événement tactile avec un pointeur non valide inférieur à 0 et un index de pointeur supérieur ou égal au nombre de pointeurs pour cet événement empêchera probablement la validation du pointeur dans native MotionEvent implementation de générer IAE.

 @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if(ev.getAction() == MotionEvent.ACTION_CANCEL) {
        int pointerCount = MotionEventCompat.getPointerCount(ev);
        int index = MotionEventCompat.getActionIndex(ev);
        mActivePointerId = MotionEventCompat.getPointerId(ev, index);
        index = MotionEventCompat.findPointerIndex(ev,mActivePointerId);
        if (index > -1 && index < pointerCount) {
            super.onInterceptTouchEvent(ev);
        } else {
            return true;
        }
    }else if(ev.getAction() == MotionEventCompat.ACTION_POINTER_DOWN && super.onInterceptTouchEvent(ev)) {
        final int index = MotionEventCompat.getActionIndex(ev);
        mActivePointerId = MotionEventCompat.getPointerId(ev, index);
        return false;
    }else if(ev.getAction() == MotionEventCompat.ACTION_POINTER_UP && super.onInterceptTouchEvent(ev)){
        onSecondaryPointerUp(ev);
        return false;
    }else if(ev.getAction() == MotionEvent.ACTION_DOWN && super.onInterceptTouchEvent(ev)){
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        return false;
    }
    return super.onInterceptTouchEvent(ev);
}

private void onSecondaryPointerUp(MotionEvent ev) {
    final int pointerIndex = MotionEventCompat.getActionIndex(ev);
    final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
    if (pointerId == mActivePointerId) {
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
        mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
    }
}
12
Nikola Despotoski

Il est déjà connecté à Suivi des problèmes AOSP .

Vous pouvez résoudre ce problème en sous-classant la SwipeRefreshLayout et en captant l'exception, comme ceci:

public class SwipeRefreshLayout extends Android.support.v4.widget.SwipeRefreshLayout {
    public SwipeRefreshLayout(Context context) {
        super(context);
    }

    public SwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        try {
            return super.onTouchEvent(ev);
        } catch (IllegalArgumentException e) {
            //Fix for support lib bug, happening when onDestroy() is 
            return true;
        }
    }
}
10
Sameer Z.

Si vous ne voyez aucun problème apparent dans votre application, vous pouvez essayer d'utiliser une version "silencieuse" personnalisée de la SwipeRefreshLayout:

public class CustomSwipeRefreshLayout extends SwipeRefreshLayout{

    public CustomSwipeRefreshLayout(Context context) {
        super(context);
    }

    public CustomSwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        try{
            return super.onTouchEvent(event);
        }
        catch(Exception e){
            return true;
        }
    }
}
1
bonnyz

Pour ceux qui cherchaient toujours, je le voyais lorsque les événements tactiles étaient en conflit avec le tiroir de navigation. J'ai ajouté un chèque au onTouch de mon activité 

if (mNavigationDrawerFragment != null && mNavigationDrawerFragment.isDrawerOpen()) {
    return super.onTouchEvent(event);
}

Et cela semble être mieux. dans NavigationDrawerFragment:

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
    super.onDrawerSlide(drawerView, slideOffset);
    mIsDrawerOpen = slideOffset != 0;
    getActivity().invalidateOptionsMenu();
}

et renvoyer mIsDrawerOpen dans isDrawerOpen()

1
Sreedevi J

Il semble que, dans l'événement onTouchEvent de SwipeRefreshLayout, ils viennent d'ajouter la validation pointerId sur ACTION_CANCEL mais pas la validation pointerIndex disponible pour ACTION_MOVE. J'ai donc créé une classe personnalisée pour elle et je la gère pour ACTION_CANCEL & ACTION_UP.

Jusqu'à présent, tout fonctionne correctement et va publier une mise à jour de mon application bientôt. Si toujours obtenir une exception sur crashlytics, alors je mettrai à jour ma solution. Jusqu'à ce moment-là, profitez-en :)

classe publique SwipeRefreshLayoutX étend SwipeRefreshLayout {

private int mActivePointerId;

public SwipeRefreshLayoutX(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
}

public SwipeRefreshLayoutX(Context context, AttributeSet attrs) {
    super(context, attrs);
    // TODO Auto-generated constructor stub
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    final int action = MotionEventCompat.getActionMasked(event);

    switch (action) {

        case MotionEvent.ACTION_DOWN:
            mActivePointerId = MotionEventCompat.getPointerId(event, 0);
            break;

        case MotionEvent.ACTION_POINTER_DOWN:{
            final int index = MotionEventCompat.getActionIndex(event);
            mActivePointerId = MotionEventCompat.getPointerId(event, index);
            break;  
        }

        case MotionEvent.ACTION_POINTER_UP:{
            onSecondaryPointerUp(event);
            break;
        }

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:{

            final int pointerIndex = MotionEventCompat.findPointerIndex(event, mActivePointerId);

            if (pointerIndex < 0) {
                Log.e("ash", "Got ACTION_UP event but have an invalid active pointer id.");
                return false;
            }

            break;
        }   

    }

    return super.onTouchEvent(event);

}

private void onSecondaryPointerUp(MotionEvent ev) {
    final int pointerIndex = MotionEventCompat.getActionIndex(ev);
    final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
    if (pointerId == mActivePointerId) {
        // This was our active pointer going up. Choose a new
        // active pointer and adjust accordingly.
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
        mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
    }
}

}

0
EEJ

J'ai constaté une erreur similaire lorsque le nombre d'éléments dans un ViewPager (qui étendent ViewGroup) était défini de manière incorrecte. Ainsi, l'application appellerait Android.view.MotionEvent.getY(10) lorsqu'il y aurait 10 (et non 11) éléments dans la liste. Vous pouvez essayer de déboguer en obtenant le nombre d'éléments contenus dans le ViewGroup.

Je serais également intéressé de savoir ce qu'il y a dans votre méthode com.mypackage.myapp.BaseActivity.onDestroy. 

Aussi, j'ai remarqué ceci, il y a apparemment un bogue dans Eclair: https://stackoverflow.com/a/16519902/2832027 Est-il possible qu'il y ait un bogue dans Eclair qui a été corrigé mais certaines personnes vous n'avez pas la mise à jour, si cela fonctionne bien sur votre version d'Eclair?

UPDATE: En regardant votre méthode onDestroy et les erreurs - Il semble que le fait d'appeler onDestroy peut déclencher un dernier événement dans le ViewGroup qui appelle la dernière vue du groupe en cours de visualisation. AppMsg.cancelAll() ou SuperCardToast.cancelAllSuperCardToasts() pourrait-il détruire ces vues? Pourriez-vous placer le super.onDestroy () devant eux dans votre méthode onDestroy? 

Cependant, si tel est le problème, il est étrange que vous ne puissiez pas le reproduire vous-même. Il pourrait également s'agir d'un problème de longueur des utilisateurs de ViewGroup par rapport aux vôtres. Si vous avez des groupes de vues très courts, pouvez-vous reproduire le problème? 

Les journaux d'erreurs que vous affichez semblent ne concerner que Eclair, mais vous dites que le problème se produit sur tous les périphériques. Pouvez-vous publier un journal des erreurs pour un périphérique non Eclair? 

0
TTransmit