java.lang.IndexOutOfBoundsException: Index: 1, Size: 2

在日常使用ArrayList时,相信大家都有遇到过IndexOutOfBoundsException 这样的错误,但是往往遇到的情况是index 大于或者等于 Size的情况,而今天我这里说的却是Index 小于 Size的情况,这是在手机使用过程中突然出现了异常而导致了手机重启,具体报错堆栈如下:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 2
    at java.util.ArrayList.get(ArrayList.java:411)
    at com.android.server.wm.DisplayContent.findTaskForControlPoint(DisplayContent.java:359)
    at com.android.server.wm.TaskTapPointerEventListener.onPointerEvent(TaskTapPointerEventListener.java:109)
    at com.android.server.wm.PointerEventDispatcher.onInputEvent(PointerEventDispatcher.java:53)
    at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:191)
    at android.view.InputEventReceiver.nativeConsumeBatchedInputEvents(Native Method)
    at android.view.InputEventReceiver.consumeBatchedInputEvents(InputEventReceiver.java:182)
    at android.view.InputEventReceiver.onBatchedInputEventPending(InputEventReceiver.java:133)
    at android.view.InputEventReceiver.dispatchBatchedInputEventPending(InputEventReceiver.java:197)
    at android.os.MessageQueue.nativePollOnce(Native Method)
    at android.os.MessageQueue.next(MessageQueue.java:323)
    at android.os.Looper.loop(Looper.java:136)
    at android.os.HandlerThread.run(HandlerThread.java:61)
    at com.android.server.ServiceThread.run(ServiceThread.java:46)

先说下出现Index 小于Size的情况的原因是因为多线程访问导致的。

大致看了下最后的执行过程,是在调用TaskTapPointerEventListener类的onPointerEvent()方法时出现问题的:

@Override
public void onPointerEvent(MotionEvent motionEvent) {
   ....

        case MotionEvent.ACTION_HOVER_MOVE: {
            final int x = (int) motionEvent.getX();
            final int y = (int) motionEvent.getY();
            final Task task = mDisplayContent.findTaskForControlPoint(x, y);
            InputDevice inputDevice = motionEvent.getDevice();
            if (task == null || inputDevice == null) {
                mPointerIconType = TYPE_NOT_SPECIFIED;
                break;
            }
            task.getDimBounds(mTmpRect);

而在里面调用DisplayContent类的findTaskForControlPoint()方法中会去访问mStacks,看过框架的人知道调用此类方法是需要加锁的,因为框架里面还有很多其他地方对mStacks进行添加或者删除,如果不加锁就会出现由于多线程访问导致的异常问题。

    Task findTaskForControlPoint(int x, int y) {
        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            TaskStack stack = mStacks.get(stackNdx);
            if (!StackId.isTaskResizeAllowed(stack.mStackId)) {
                break;
            }
            final ArrayList<Task> tasks = stack.getTasks();
            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                final Task task = tasks.get(taskNdx);
                if (task.isFullscreen()) {
                    return null;
                }

                // We need to use the task's dim bounds (which is derived from the visible
                // bounds of its apps windows) for any touch-related tests. Can't use
                // the task's original bounds because it might be adjusted to fit the
                // content frame. One example is when the task is put to top-left quadrant,
                // the actual visible area would not start at (0,0) after it's adjusted
                // for the status bar.
                task.getDimBounds(mTmpRect);
                mTmpRect.inset(-delta, -delta);
                if (mTmpRect.contains(x, y)) {
                    mTmpRect.inset(delta, delta);
                    if (!mTmpRect.contains(x, y)) {
                        return task;
                    }
                    // User touched inside the task. No need to look further,
                    // focus transfer will be handled in ACTION_UP.
                    return null;
                }
            }
        }
        return null;
    }

解决此类问题,要么就是给循环加锁,要么就改成用foreach的方式,这样如果出现同步访问会抛出异常,方便查找问题。
另外在Stack Overflow也搜到了类似问题,可以参考下:https://stackoverflow.com/questions/10474612/another-java-lang-indexoutofboundsexception-but-index-size

本来想本地模拟下这种情况,无奈这个线程同步问题确实不好复现出来,如果有同学遇到过类似问题,欢迎在评论区一起讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值