Je suis en train de coder une bibliothèque glisser-déposer pour GridViews. Je suis presque complet ... cependant, je reçois de temps en temps une NullPointerException agaçante sur ACTION_DROP. Il pointe vers le code source ViewGroup, lignes 1147 et 1153, indiquant qu'il obtient un pointeur null lors de la tentative de recyclage de l'événement de déplacement. Quelques informations sur mon processus: Je suis en train d'incorporer un OnDragListener dans un adaptateur personnalisé pour un GridView. J'ai l'utilisateur (programmeur) implémenter un OnGetViewListener, quand ils définissent l'adaptateur GridView afin qu'ils puissent choisir quelles vues gonfler, quelles images à inclure, etc. Ensuite, dans le DragDropAdapter (qui est l'adaptateur de GridView), quand getView est appelé , il appelle le OnGetViewListener désigné pour obtenir la vue que l'utilisateur veut. Il crée un LinearLayout vide pour servir de conteneur pour le glisser-déposer. La vue de l'utilisateur est ajoutée au conteneur, un écouteur de drag est défini sur le conteneur, la balise du conteneur est définie sur la collection de données correspondante pour GridView, puis le conteneur est la vue renvoyée pour getView().Lancer ViewGroup NullPointerException dans dispatchDragEvent
L'ensemble du processus de glisser-déposer des éléments GridView est basé sur le conteneur et ses balises. Lorsque deux éléments GridView sont échangés (lorsqu'un utilisateur fait glisser un élément), il supprime essentiellement la vue de la cellule survolée et l'ajoute à la cellule que la vue déplacée vient de quitter. Ceci fournit un "échange" visuel d'articles.
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;
}
}
}
Maintenant, ACTION_DRAG_ENDED, le NullPointerException est être jeté parce que, pour une raison quelconque, il ne peut pas recycler l'événement de déplacement, si je comprends bien le code source.
Mise à jour: Voici la source où il jette l'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 }
Les experts là-bas ont des idées?
Pouvez-vous publier plus de code, en particulier comment mContext est défini et défini? – nmw
mContext est simplement passé dans le constructeur de l'adaptateur à partir de l'activité qui définit l'adaptateur. – dennisdrew