2013-08-19 15 views
9

Sto utilizzando un ArrayAdapter per un elenco del mio tipo di oggetti (un solo tipo) e offro all'utente un'opzione per creare più elementi (creando così più visualizzazioni per questi articoli). Ad un certo punto, getView ha inviato un nuovo indice "posizione" con un "convertView" non nullo. Quindi mostra la prima vista nell'ultima posizione. Dopodiché, quando scorri le viste, tutto si confonde. Suppongo che questo significhi che ho manipolato le opinioni in modi che non avrei dovuto, ma non vedo dove. Ecco alcuni codici:Parametro Getview "convertview" non null sul nuovo parametro "position"

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View v; 
    PreviewItemHolder holder = null; 

    // Initialize view if convertview is null 
    if (convertView == null) { 
     v = newView(parent, position); 
    } 
    // Populate from previously saved holder 
    else { 
     // Use previous item if not null 
     v = convertView; 
    } 

    // Populate if the holder is null (newly inflated view) OR 
    // if current view's holder's flag is true and requires populating 
    if ((holder == null) || (holder.readPopulateFlag())) { 
     bindView(position, v); 
    } 

    return v; 
} 

    private View newView(ViewGroup parent, int position) { 
    // Getting view somehow... 
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    View inflatedView = inflater.inflate(R.layout.preview_element_set, parent, false); 
    PreviewItemHolder holder = new PreviewItemHolder(); 

    holder.set = (Set) mSets.get(position); 
    holder.previewElementHolders = new ArrayList<PreviewElementHolder>(); 
    holder.expandArea = (View) inflatedView.findViewById(R.id.expandArea); 
    holder.repetitionsLabel = (TextView) inflatedView.findViewById(R.id.previewRepetitionsInput); 
    holder.endlessInput = (CheckBox) inflatedView.findViewById(R.id.previewSetEndlessInput); 
    holder.nameLabel = (TextView) inflatedView.findViewById(R.id.previewSetNameLabel); 
    holder.commentInput = (EditText) inflatedView.findViewById(R.id.previewSetCommentInput); 
    holder.soundInput = (EditText) inflatedView.findViewById(R.id.previewSetSoundInput); 
    holder.addElementButton = (Button) inflatedView.findViewById(R.id.previewSetAddElements); 
    holder.expand = (View) inflatedView.findViewById(R.id.infoArea); 
    holder.collapse = (View) inflatedView.findViewById(R.id.collapse); 

    final int setsLength = holder.set.getElements().size(); 

    for (int i = 0; i < setsLength; i++) { 
     AElement currElement = holder.set.getElements().get(i); 

     // Creating new element holder according to the type 
     if (currElement instanceof Rest) { 
      holder.previewElementHolders.add(new PreviewRestHolder()); 
     } 
     else if (currElement instanceof TimeExercise) { 
      holder.previewElementHolders.add(new PreviewTimeExerciseHolder()); 
     } 
     else if (currElement instanceof RepetitionExercise) { 
      holder.previewElementHolders.add(new PreviewRepetitionExerciseHolder()); 
     } 

     View currLayout = inflateElement(currElement, inflater, i, holder.previewElementHolders.get(i)); 

     // Add the child before the hairline, collapse image and the add 
     // button 
     // (3 last children of the expandArea view 
     ((ViewGroup) holder.expandArea).addView(currLayout, ((ViewGroup) holder.expandArea).getChildCount() - CHILDREN_INDEX_AFTER_PHASES_LABEL); 
    } 

    inflatedView.setTag(holder); 

    return inflatedView; 
} 

private void bindView(int position, View inflatedView) { 
    final PreviewItemHolder holder = (PreviewItemHolder) inflatedView.getTag(); 
    holder.set.setId(position); 
    holder.endlessInput.setChecked(holder.set.getEndless()); 
    holder.soundInput.setText(holder.set.getSound()); 
    holder.nameLabel.setText(holder.set.getName()); 
    holder.commentInput.setText(holder.set.getComment()); 

    // Make sure there is a name. If none, put default 
    if (holder.nameLabel.getText().equals("")) { 
     holder.nameLabel.setText(R.string.default_set_name); 
    } 

    // Set repetitions value according to the endless flag 
    if (holder.set.getEndless()) { 
     holder.repetitionsLabel.setText(R.string.infinity); 
    } 
    else { 
     holder.repetitionsLabel.setText(String.valueOf(holder.set.getRepetitions())); 
    } 

    // Set click listeners 
    holder.endlessInput.setOnCheckedChangeListener(new OnCheckedChangeListener() { 

     @Override 
     public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 

      // Save endless flag 
      holder.set.setEndless(isChecked); 

      // If an endless set - Dropset 
      if (isChecked) { 
       holder.repetitionsLabel.setText(R.string.infinity); 
      } 
      else { 
       // Regular set 
       holder.repetitionsLabel.setText(String.valueOf(holder.set.getRepetitions())); 
      } 

      hideShowRepsWeights(holder); 
     } 

    }); 

    holder.repetitionsLabel.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 

      NumericDialog instance = NumericDialog.newInstance(holder, holder.set, NumericDialog.INTEGER_MODE, Consts.SET_REPETITIONS_METHOD_NAME); 
      instance.show(((Activity) getContext()).getFragmentManager(), null); 
     } 
    }); 

    holder.nameLabel.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      // Setting flag to true to allow populating this view 
      holder.rePopulateFlag = true; 
      SetNameDialog instance = SetNameDialog.newInstance(holder.set); 
      instance.show(((Activity) getContext()).getFragmentManager(), null); 
     } 
    }); 

    holder.commentInput.setOnFocusChangeListener(new OnFocusChangeListener() { 
     @Override 
     public void onFocusChange(View v, boolean hasFocus) { 
      if (!hasFocus) { 
       // After focus is lost, save the text into the set 
       holder.set.setComment(holder.commentInput.getText().toString()); 
      } 
     } 
    }); 

    // TODO Change that into a dialog that allows selection of sounds 
    holder.soundInput.setOnFocusChangeListener(new OnFocusChangeListener() { 
     @Override 
     public void onFocusChange(View v, boolean hasFocus) { 
      if (!hasFocus) { 
       // After focus is lost, save the text into the set 
       holder.set.setSound(holder.soundInput.getText().toString()); 
      } 
     } 
    }); 

    holder.expand.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      // Change visibility - Show expandArea and its data 
      holder.expandArea.setVisibility(View.VISIBLE); 
      holder.expand.setVisibility(View.GONE); 
      holder.collapse.setVisibility(View.VISIBLE); 
     } 
    }); 

    holder.collapse.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      // Change visibility - Hide expandArea and its data 
      holder.expandArea.setVisibility(View.GONE); 
      holder.collapse.setVisibility(View.GONE); 
      holder.expand.setVisibility(View.VISIBLE); 
     } 
    }); 

    holder.addElementButton.setOnClickListener(new OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      AddElementDialog instance = AddElementDialog.newInstance(holder); 
      instance.show(((Activity) getContext()).getFragmentManager(), null); 
     } 
    }); 

    // Populate elements 
    for (PreviewElementHolder elementHolder : holder.previewElementHolders) { 
     populateElement(elementHolder, holder); 
    } 

    // Finally hide/show if needed - Should this be put somewere else? 
    hideShowRepsWeights(holder); 
} 

Per favore dimmi se pensi che dovrei caricare più metodi per rendere le cose più chiare.

+0

Che cos'è holder.readPopulateFlag() ?? –

risposta

15

Un amico mi ha spiegato il problema e ora sembra funzionare. Fondamentalmente ListView contiene solo un piccolo numero di visualizzazioni e le ricicla tutto il tempo. Nel mio caso ho un Nexus 4 e quindi sembra che abbia 7 visualizzazioni totali perché l'8 era sempre quello che ha iniziato a causare problemi. Quello che mi mancava nel mio getView() era una condizione che verificava la correlazione tra la posizione e l'ID dell'elemento corrente all'interno dell'ArrayAdapter. Ecco come appare ora che funziona:

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View v; 
    PreviewItemHolder holder = null; 

    // Initialize view if convertview is null 
    if (convertView == null) { 
     v = newView(parent, position); 
    } 
    // Populate from previously saved holder 
    else { 
     // If position and id of set do not match, this view needs to be re-created, not recycled 
     if (((PreviewItemHolder) convertView.getTag()).set.getId() != position) { 
      v = newView(parent, position); 
     } 
     else { 
      // Use previous item if not null 
      v = convertView; 

      // Get holder 
      holder = (PreviewItemHolder) v.getTag(); 
     } 
    } 

    // Populate if the holder is null (newly inflated view) OR 
    // if current view's holder's flag is true and requires populating 
    if ((holder == null) || (holder.readPopulateFlag())) { 
    bindView(position, v); 
    } 

    return v; 
} 
+0

Ho avuto lo stesso identico problema con un BaseAdapter, ma il mio cervello non può sopportarlo ... Lo so che è stato tanto tempo fa, ma hai qualche spiegazione in più sul perché questo ha aiutato? Mi ha anche aiutato, semplicemente non capisco ... – keybee

+0

Questo è eccellente. Lo stesso problema è successo con me quando stavo usando 3 diversi tipi di layout nel mio 'ListView'. Non appena la vista superiore è di tipo 1 e la vista successiva per entrare sullo schermo è di un altro tipo, 'convertView' non è nullo e la vista errata è stata riciclata usando' getTag'. –

1

È necessario chiamare bindView()sempre. L'idea o il riutilizzo è il seguente. Se convertView è null, si crea e inizializza una nuova vista. Se convertView non è nullo, si ottiene questa vista e convertire in una nuova visualizzazione, ovvero si chiama bindView() con istanza convertView.

Acquista this Javadoc per ulteriori dettagli.

+0

Ho provato ma non ha risolto il problema. Anche quando chiamo bindView() ogni volta, il problema si verifica ancora come prima. Non penso che sia necessario reimpostare i dati in converView ogni volta per risolvere il problema. –

0

Quando si dispone di diversi tipi di punti di vista che devono essere riciclate dovete dire la visualizzazione elenco quanti tipi avete per implementare il metodo

@Override 
    public int getViewTypeCount() { 
     return 7; 
    } 
Problemi correlati