web-dev-qa-db-ja.com

IllegalArgumentException:pointerIndexがSwipeRefreshLayoutから範囲外です

Crashlyticsでこれらの_IllegalArgumentException: pointerIndex out of range_クラッシュがいくつか発生しており、何が起こっているのか理解できません。 1つのAndroidビルドまたはデバイスに限定されません。5.0.1、4.4.4、4.4.2、4.0.4、2.3.6のすべてのデバイスで発生します。以下は完全なものですより多くのコンテキストのログ出力。

_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)
_

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)
_

だから私の質問は、このエラーの原因は何ですか?この問題を軽減するための許容できる方法は何ですか?

編集:これは、上記のクラッシュで参照されている MotionEvent.Java:1998 へのリンクです。

編集:私のonDestroyは次のようになります:

_@Override
public void onDestroy() {

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

    super.onDestroy();
}
_

具体的には、_BaseActivity.Java:105_がsuper.onDestroy();を呼び出す場所です。

26
MrEngineer13

タッチイベントがまだ発生しているときに例外がスローされたと想定します(アクティビティがonDestroy()に向かっている間にネイティブタッチにストリーミングされます。クラッシュを回避するために例外をキャッチすることでこれを軽減してもかまいません。 。この状態になった場合、アクティビティは破棄されようとしています。

確かではありませんが(テストを繰り返して)、例外をキャッチすることが適切でない場合は、イベントが実装に渡されないようにすることができます。

_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;
    }
}
_

または

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

    super.onDestroy();
}
_

テイク2

SwipeRefreshLayoutは無効なポインタインデックスからgetY()を試み、findPointerIndex(ev, activePointer)を呼び出すと、見つからない場合は_-1_が返されます。無効なポインターが0未満で、ポインターインデックスがそのイベントのポインターカウント以上であるタッチイベントのディスパッチを防止すると、おそらく native MotionEvent 実装内のポインターの検証で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);
    }
}
_
14

AOSP issue tracker にすでに記録されています。

SwipeRefreshLayoutをサブクラス化して例外をキャッチすることで、次のように修正できます。

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.

アプリに明らかな問題が見られない場合は、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

まだ見ている人のために、タッチイベントがナビゲーションドロワーと競合していたときに私はこれを見ました。アクティビティのonTouchにチェックを追加しました

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

そしてそれはより良いようです。 NavigationDrawerFragment内:

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

mIsDrawerOpenisDrawerOpen()で返します

1
Sreedevi J

SwipeRefreshLayoutのonTouchEvent内では、ACTION_CANCELにpointerId検証を追加しただけで、ACTION_MOVEで使用できるpointerIndex検証を追加していないようです。そのため、カスタムクラスを作成し、ACTION_CANCELとACTION_UPのために処理しています。

これまでのところ、すべてが正常に動作しており、アプリのアップデートがまもなくリリースされます。それでもcrashlyticsで例外が発生する場合は、ソリューションを更新します。その時までお楽しみください:)

パブリッククラスSwipeRefreshLayoutX extends 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

ViewPager(ViewGroupを拡張する)の項目数が正しく設定されていない場合にも、同様のエラーが発生しました。したがって、リストに10個(11個ではない)の項目がある場合、アプリはAndroid.view.MotionEvent.getY(10)を呼び出します。 ViewGroupにあるものの数を取得することでデバッグを試すことができます。

また、com.mypackage.myapp.BaseActivity.onDestroyメソッドの中に何があるのか​​知りたいです。

また、私はこれを見つけました、明らかにエクレアにバグがあります: https://stackoverflow.com/a/16519902/2832027 エクレアに修正されたバグがあったかもしれませんが、一部の人々お使いのバージョンのEclairで問題なく動作している場合、アップデートはありませんか?

UPDATE:onDestroyメソッドとエラーを見る-onDestroyを呼び出すと、ViewGroupの最後のイベントがトリガーされ、表示されていたグループ。これらのビューをAppMsg.cancelAll()またはSuperCardToast.cancelAllSuperCardToasts()で破棄できますか?あなたのonDestroyメソッドでsuper.onDestroy()をそれらの前に置くことができますか?

ただし、これが問題である場合、自分で複製できないのは奇妙です。 ViewGroupのユーザーと自分のユーザーの長さの問題である可能性もあります。 ViewGroupが非常に短い場合、問題を再現できますか?

表示するエラーログはEclairに関するものだけのようですが、問題はすべてのデバイスで発生すると言います。 Eclair以外のデバイスのエラーログを投稿できますか?

0
TTransmit