ViewGroup在dispatchDragEvent中引发NullPointerException [英] ViewGroup throwing NullPointerException in dispatchDragEvent

查看:83
本文介绍了ViewGroup在dispatchDragEvent中引发NullPointerException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为GridViews的拖放库编码.我几乎完成了...但是,我时不时地在ACTION_DROP上收到一个令人讨厌的NullPointerException.它指向ViewGroup源代码第1147和1153行,并表示在尝试回收拖动事件时获取了空指针.

I am in the process of coding a drag and drop library for GridViews. I am almost complete...however, I am getting an annoying NullPointerException upon ACTION_DROP every now and then. It points to the ViewGroup source code, lines 1147 and 1153, saying it is getting a null pointer when trying to recycle the drag event.

我的过程的某些背景:我基本上是将OnDragListener嵌入到GridView的自定义适配器中.当用户(程序员)设置GridView适配器时,我让用户(程序员)实现OnGetViewListener,以便他们可以选择要填充的视图,要包含的图像等.然后,在DragDropAdapter(这是GridView的适配器)中,调用getView时,它将调用指定的OnGetViewListener来获取用户所需的View.它创建一个空的LinearLayout来作为拖放的容器.将用户的View添加到容器中,将拖动侦听器设置为容器,将容器的标签设置为GridView的相应数据集合,然后容器为getView()返回的View.

Some background on my process: I am basically embedding an OnDragListener into a custom adapter for a GridView. I have the user (programmer) implement an OnGetViewListener, when they set the GridView adapter so they can choose what Views to inflate, what images to include, etc. Then, in the DragDropAdapter (which is the GridView's adapter), when getView is called, it calles the designated OnGetViewListener to get the View the user wants. It creates an empty LinearLayout to stand as a container for the drag and drop. The user's View is added to the container, a drag listener is set to the container, the container's tag is set to the corresponding data collection for the GridView, and then the container is the View returned for getView().

拖放GridView项的整个过程基于容器及其标签.交换两个GridView项时(当用户拖动项目时),它基本上从悬停的单元格中删除视图,并将其添加到拖动视图刚离开的单元格中.这提供了视觉上的项目交换".

The whole process of the drag and dropping GridView items is based off the container and its tags. When two GridView items are swapped (as a user is dragging an item), it basically removes the view from the cell being hovered over and adds it to the cell that the dragged view just left. This provides a visual "swapping" of items.

public class DragDropAdapter extends BaseAdapter {
...
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LinearLayout containerView = new LinearLayout(mContext);
        containerView.setLayoutParams(new GridView.LayoutParams(
                GridView.LayoutParams.MATCH_PARENT,
                GridView.LayoutParams.MATCH_PARENT));
        View itemView = mGetViewListener.getView(position, convertView, parent);

        itemView.setTag(mItems.get(position));
        containerView.setTag(mItems.get(position));
        containerView.addView(itemView);
        containerView.setOnDragListener(new ItemDragListener());

        return containerView;
    }

    ...

    View mExitedView = null;

    public class ItemDragListener implements OnDragListener {

        public ItemDragListener() {

        }

        private void swapCards(int startPosition, View viewToSwap) {
            if (mExitedView == null) {
                mExitedView = mGridView.getChildAt(startPosition);
            }

            ViewGroup viewToSwapContainer = (ViewGroup) viewToSwap;
            ViewGroup exitedViewContainer = (ViewGroup) mExitedView;

            View childViewToSwap = viewToSwapContainer.getChildAt(0);
            View childViewExited = exitedViewContainer.getChildAt(0);

            int enteredPosition = ItemCoordinatesHelper
                    .getGridPosition(viewToSwap);
            int exitedPosition = ItemCoordinatesHelper
                    .getGridPosition(mExitedView);

            Object itemToSwap = viewToSwap.getTag();
            Object exitedItem = mExitedView.getTag();

            viewToSwapContainer.setVisibility(View.INVISIBLE);
            viewToSwapContainer.setTag(exitedItem);
            viewToSwapContainer.removeAllViews();
            if (childViewExited.getParent() != null)
                ((ViewGroup) childViewExited.getParent()).removeAllViews();
            viewToSwapContainer.addView(childViewExited);

            exitedViewContainer.setTag(itemToSwap);
            exitedViewContainer.removeAllViews();
            if (childViewToSwap.getParent() != null)
                ((ViewGroup) childViewToSwap.getParent()).removeAllViews();
            exitedViewContainer.addView(childViewToSwap);
            exitedViewContainer.setVisibility(View.VISIBLE);
        }

            ...

        @Override
        public boolean onDrag(View v, DragEvent event) {
            // TODO Auto-generated method stub

            View heldView = (View) event.getLocalState();
            int startPosition = ItemCoordinatesHelper.getGridPosition(heldView);

            switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                break;
            case DragEvent.ACTION_DRAG_ENTERED:
                swapCards(startPosition, v);
                break;
            case DragEvent.ACTION_DRAG_EXITED:
                mExitedView = v;
                break;
            case DragEvent.ACTION_DROP:
                View view = (View) event.getLocalState();
                v.setVisibility(View.VISIBLE);
                view.setVisibility(View.VISIBLE);
                break;
            case DragEvent.ACTION_DRAG_ENDED:
                commitChangesToAdapter();
                mExitedView = null;
                break;
            default:
                break;
            }

            return true;
        }
    }
}

现在,在ACTION_DRAG_ENDED上,将抛出NullPointerException,因为如果出于某种原因,如果我正确地理解了源代码,它将无法回收拖动事件.

Now, on ACTION_DRAG_ENDED, the NullPointerException is being thrown because for some reason it cannot recycle the drag event, if I'm understanding the source code correctly.

更新:这是引发异常的来源:

Update: Here is the source where it throws the exception:

@Override
1100    public boolean dispatchDragEvent(DragEvent event) {
1101        boolean retval = false;
1102        final float tx = event.mX;
1103        final float ty = event.mY;
1104
1105        ViewRootImpl root = getViewRootImpl();
1106
1107        // Dispatch down the view hierarchy
1108        switch (event.mAction) {
1109        case DragEvent.ACTION_DRAG_STARTED: {
1110            // clear state to recalculate which views we drag over
1111            mCurrentDragView = null;
1112
1113            // Set up our tracking of drag-started notifications
1114            mCurrentDrag = DragEvent.obtain(event);
1115            if (mDragNotifiedChildren == null) {
1116                mDragNotifiedChildren = new HashSet<View>();
1117            } else {
1118                mDragNotifiedChildren.clear();
1119            }
1120
1121            // Now dispatch down to our children, caching the responses
1122            mChildAcceptsDrag = false;
1123            final int count = mChildrenCount;
1124            final View[] children = mChildren;
1125            for (int i = 0; i < count; i++) {
1126                final View child = children[i];
1127                child.mPrivateFlags2 &= ~View.DRAG_MASK;
1128                if (child.getVisibility() == VISIBLE) {
1129                    final boolean handled = notifyChildOfDrag(children[i]);
1130                    if (handled) {
1131                        mChildAcceptsDrag = true;
1132                    }
1133                }
1134            }
1135
1136            // Return HANDLED if one of our children can accept the drag
1137            if (mChildAcceptsDrag) {
1138                retval = true;
1139            }
1140        } break;
1141
1142        case DragEvent.ACTION_DRAG_ENDED: {
1143            // Release the bookkeeping now that the drag lifecycle has ended
1144            if (mDragNotifiedChildren != null) {
1145                for (View child : mDragNotifiedChildren) {
1146                    // If a child was notified about an ongoing drag, it's told that it's over
1147                    child.dispatchDragEvent(event); //<-- NULL POINTER HERE
1148                    child.mPrivateFlags2 &= ~View.DRAG_MASK;
1149                    child.refreshDrawableState();
1150                }
1151
1152                mDragNotifiedChildren.clear();
1153                mCurrentDrag.recycle(); //<-- NULL POINTER HERE
1154                mCurrentDrag = null;
1155            }

外面的专家有什么想法吗?

Any experts out there have any ideas?

推荐答案

我有一个相同的例外,因为在处理案例DragEvent.ACTION_DRAG_ENDED时,我删除了一个包含可拖动视图的ViewGroup.

I have the same exception, because I'm removing a ViewGroup which contains draggable views when I handle case DragEvent.ACTION_DRAG_ENDED.

我的解决方案:使用post(runnable)方法延迟执行removeView方法.

My solution: delay the execution of removeView method by using post(runnable) method.

这篇关于ViewGroup在dispatchDragEvent中引发NullPointerException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆