2013-12-09 11 views
5

Non sono sicuro che si tratti di un problema di dispositivo o di un problema con il mio codice, ma ho creato un elenco ordinabile trascinabile semplice utilizzando un layout relativo e visualizzazioni di immagine. Ho ragioni molto specifiche per farlo in questo modo e questa non è la mia domanda.Android/kindle drag drop congelamento occasionalmente

Il problema che sto avendo a volte bloccherà completamente la mia app. L'oggetto si bloccherà nello stato di trascinamento. Se alzo il dito, l'ombra (trascinando) l'oggetto è ancora sullo schermo e se tocco lo schermo si sposterà in quel punto. Questo andrà avanti per circa un minuto e poi avrò un errore dicendo che l'app non è reattiva con l'opzione di ucciderlo o aspettare. L'unica parte utile nel logcat è la seguente:

12-09 14:23:13.157: W/WindowManager(16415): Drag is in progress but there is no drag window handle. 

Poi, quando i tempi di app fuori ottengo questo come un errore

12-09 14:59:09.782: E/ActivityManager(16415): ANR in com.appname.appname (com.appname.appname/.MainActivity) 
12-09 14:59:09.782: E/ActivityManager(16415): Reason: keyDispatchingTimedOut 

Ho cercato su google questo messaggio di errore e l'unica Info E 'stato qualcuno senza trascina l'ascoltatore e un'altra persona che dice che è il sensore tattile del dispositivo a non tenere il passo.

Idealmente, mi piacerebbe risolvere questo errore e impedire che accada in primo luogo. Sembra che succeda soprattutto se trascino velocemente, ma non posso chiedere ai miei utenti di non trascinarsi velocemente ... giusto?

In alternativa, c'è un modo per rilevare che il trascinamento ha bloccato l'app e interrotto il trascinamento. Come impostare un timer sull'ascoltatore touch e se non ci sono messaggi di tipo drag_location come un secondo o due interrompe il trascinamento? Le cose del timer che so come fare, ma non so come forzerei la resistenza a fermarsi mentre è congelata. Qualche idea?

Ecco il codice:

configurazione

//happens once when the app loads 
RelativeLayout trackList = (RelativeLayout) findViewById(R.id.nsTrackList1);  
trackList.setOnDragListener(new MyTrackDragListener(this)); 

//happens in a loop for each "track" (image view) 
trackButton = new ImageView(this); 
trackButton.setImageDrawable(nsPackages[trackId].banner[bannerSizeSelector]); 
trackButton.setOnTouchListener(new MyTrackTouchListener()); 

sul touch

public class MyTrackTouchListener implements OnTouchListener { 
    boolean isDragging=false; 
    float prevX, prevY; 
    public boolean onTouch(View view, MotionEvent motionEvent) { 
     if(motionEvent.getPointerCount() < 2 && !isDragging) return false; 
     if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { 
      isDragging=false; 
      prevX=0; 
      prevY=0; 
      return true; 
     } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) { 
      if(isDragging) return true; 
      boolean wasFirst = (prevX == 0 || prevY == 0); 
      float theTotalDiff = Math.abs(prevX - motionEvent.getX()) + Math.abs(prevY - motionEvent.getY()); 
      prevX=motionEvent.getX(); 
      prevY=motionEvent.getY(); 
      if(wasFirst) return true; 
      if(theTotalDiff <3) return true; 
      ClipData data = ClipData.newPlainText("", ""); 
      DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(view); 

      view.startDrag(data, shadowBuilder, view, 0); 
      int thisViewId = view.getId(); 
      //hide view 
      view.setVisibility(View.GONE); 

      isDragging=true;  
      return true; 
     } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { 
      isDragging=false; 
      return true; 
     }else { 

      Integer thisAction = motionEvent.getAction(); 
      Log.d("looper","Motion action: "+thisAction.toString()); 
      return false; 
     } 
    } 
} 

Al trascinamento

class MyTrackDragListener implements OnDragListener { 
    public static boolean isDragging=false; 
private MainActivity parent; 

public MyTrackDragListener(MainActivity myAct){ 
    parent=myAct; 
}  
    @Override 
    public boolean onDrag(View v, DragEvent event) { 
     int action = event.getAction(); 
     switch (event.getAction()) { 
     case DragEvent.ACTION_DRAG_STARTED: 
      isDragging=true; 
      // do nothing 
      return true; 
     case DragEvent.ACTION_DROP: 
      View view = (View) event.getLocalState(); 
      parent.doDropSort(view,(int) event.getY()); 
      return true; 
     case DragEvent.ACTION_DRAG_ENDED: 
      if(isDragging && event.getResult()==false){ 
       View view2 = (View) event.getLocalState(); 
       parent.doDropSort(view2,(int) event.getY(),true); 
       return true; 
      } 
      isDragging=false; 
      break; 
     case DragEvent.ACTION_DRAG_LOCATION: 
      parent.doDragHover((int) event.getY()); 
      return true; 
     default: 
      Log.d("looper","drag other... "+String.valueOf(event.getAction())); 
     } 
     return false; 
    } 
} 

Alcune cose che già provato

  • Rimozione l'ascoltatore di trascinamento del tutto
  • tornare sempre vero dal onDrag
  • Riportare sempre falso dal onDrag
  • In pratica ogni combinazione di rendimento vero/falso nella resistenza e toccare
  • Rimuovere la parte 2 dita e Action_Move e attivare il trascinamento su Action_down invece

Stessi risultati. Drag and drop funziona perfettamente circa il 70% delle volte e poi improvvisamente fa il comportamento di congelamento descritto sopra. A volte è la prima volta che si trascina, dopo diversi anni. Ho notato un pattern coerente tranne possibilmente velocità di trascinamento. Sembra che in genere si verifichi quando sto trascinando velocemente, ma la direzione di trascinamento o il punto in cui trascino non sembra avere importanza.

+0

Come un ex dipendente di Amazon Kindle e sviluppatore, mi piacerebbe vedere se si puoi ottenerlo in modo coerente con una piccola app di prova e quindi inviare una segnalazione di errore. –

+0

@CarlAnderson Grazie, ho provato con i test manuali da alcuni giorni e non riesco a vedere alcun motivo. Hai qualche consiglio su come costruire un'app di test per questo tipo di comportamento? C'è un modo per simulare l'input touch/drag-drop? – Lenny

+0

Nessuno di ciò che conosco e, sfortunatamente, se non riesci a riprodurlo in modo coerente, probabilmente non lo guarderanno. –

risposta

2

YAY! L'avevo capito.Ecco la risposta nel caso in cui aiuti qualcuno in futuro.

fine ho ristretto la scelta a solo l'elemento top list (non so come ho perso che) e poi ha iniziato commentando le linee fino a quando non ha rotto che ristretto la scelta a questa linea:

view.setVisibility(View.GONE); 

Il modo in cui il mio elenco è stato impostato per ciascun elemento utilizzava la Proprietà layout SOTTO in un layout relativo (tranne l'elemento superiore). Una volta rimosso l'elemento superiore dalla vista, il secondo elemento in cima era sotto un oggetto che era visibile, quindi non sapeva cosa fare. La soluzione era impostare il parametro dell'elemento successivo nella vista. Fortunatamente ho impostato manualmente gli ID di visualizzazione dei miei pulsanti di traccia (ci sono altre viste che scorrono anche ... etichette e così via) in modo che siano sequenziali. Così la mia correzione è stata semplicemente trovare l'elemento con id + 1 e facendola diventare la prima voce impostando SOTTO a zero in questo modo ...

// the top item in my list is ALWAYS view id 1 
if(thisViewId == 1){ 
    ImageView nextTrackButton = (ImageView) trackList.findViewById(thisViewId+1); 
    LayoutParams ntLP = (LayoutParams) nextTrackButton.getLayoutParams(); 
    ntLP.addRule(RelativeLayout.BELOW,0); 
    nextTrackButton.setLayoutParams(ntLP); 
}   

//hide view 
view.setVisibility(View.GONE);