2

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?

+0

Pouvez-vous publier plus de code, en particulier comment mContext est défini et défini? – nmw

+0

mContext est simplement passé dans le constructeur de l'adaptateur à partir de l'activité qui définit l'adaptateur. – dennisdrew

Répondre

3

J'ai la même exception, car je supprime un ViewGroup qui contient des vues déplaçables lorsque je gère le cas DragEvent.ACTION_DRAG_ENDED.

Ma solution: retarder l'exécution de la méthode removeView en utilisant la méthode post(runnable).

Questions connexes