2016-05-02 4 views
4

Ich werde den Code und nach den Schritten zeigen, um das Problem zu bekommen.RecyclerView.Adapter onBindViewHolder() bekommt falsche Position

Ich habe einen recyclerview in einem mit Registerkarten-Fragmente, das die Datenmenge aus einem benutzerdefinierten Objekt nimmt:

mRecyclerView = (RecyclerView) v.findViewById(R.id.recyclerview); 

mRecyclerView.setLayoutManager(mLayoutManager); 

mRecyclerAdapter = new MyRecyclerAdapter(mMes.getListaItens(), this, getActivity()); 

mRecyclerView.setAdapter(mRecyclerAdapter); 

I das longclick Verhalten der Listenelemente in onBindViewHolder() des Adapters eingestellt:

@Override 
public void onBindViewHolder(final ViewHolder holder, final int position) { 

    ItemMes item = mListaItens.get((position)); 

    holder.descricao.setText(item.getDescrição()); 
    holder.valor.setText(MainActivity.decimalFormatWithCod.format(item.getValor())); 

    ... 

    holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 

      new MaterialDialog.Builder(mContext) 
        .title(holder.descricao.getText().toString()) 
        .items(R.array.opcoes_longclick_item) 
        .itemsCallbackSingleChoice(-1, new MaterialDialog.ListCallbackSingleChoice() { 
         @Override 
         public boolean onSelection(MaterialDialog dialog, View view, int which, CharSequence text) { 

          switch (which) { 
           case 0: 
            mParentFragment.showUpdateItemDialog(position); 
            return true; 

           case 1: 
            mParentFragment.showDeleteItemDialog(position); 
            return true; 
          } 

          return false; 
         } 
        }) 
        .show(); 

      return true; 
     } 
    }); 

} 

Dann werden die Methoden in dem Fragment, das aufpasse löschen Sie den Artikel selbst:

public void showDeleteItemDialog(int position) { 

    final ItemMes item = mMes.getListaItens().get(position); 

    new MaterialDialog.Builder(getActivity()) 
      .title("Confirmar Remoção") 
      .content("Tem certeza que deseja remover " + item.getDescrição() + "?") 
      .positiveText("Sim") 
      .negativeText("Cancelar") 
      .onPositive(new MaterialDialog.SingleButtonCallback() { 
       @Override 
       public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { 
        deleteItem(item); 
       } 
      }) 
      .show(); 

} 

public void deleteItem(ItemMes item) { 

    getMainActivity().deleteItemFromDatabase(item.getID()); 

    int position = mMes.getListaItens().indexOf(item); 

    mMes.getListaItens().remove(position); 

    mRecyclerAdapter.notifyItemRemoved(position); 

    atualizaFragment(); 

} 

Und schließlich das Verfahren in Aktivität, die den DB-Betrieb tun:

public int deleteItemFromDatabase(long id) { 

    SQLiteDatabase db = dataBaseHelper.getWritableDatabase(); 

    String where = DBHelper.COLUNA_ID + " = ?"; 

    String[] args = {String.valueOf(id)}; 

    int rowsAffected = db.delete(DBHelper.TABELA_ITEM, where, args); 

    db.close(); 

    return rowsAffected; 

} 

Jetzt werde ich die Schritte reproduzieren: Ich zeige 3 itens in der Listenansicht. Dann versuche ich das zu entfernen, zuerst:

1 - Die longclick ist vorbei abgefangen den richtigen Index: enter image description here

2 - Das Element korrekt aus der Datenbank gelöscht wird: enter image description here

3 - Schließlich dies, wie erwartet, ist der Adapter speichert und zeigt 2 Artikel ... enter image description here

sO, wenn ich versuche, das erste Element dieser 2 Artikelliste löschen ich die falsche Posi bekommen tion (sollte 0 sein, ist 1): The position = 1

Und auch, wenn ich das letzte Element dieser 2 Artikelliste löschen versuche ich die falsche Position erhalten (sollte 1, 2): enter image description here

Die Frage ist: Wenn ich einen Datensatz der Größe 2 habe (und der Adapter weiß es), wie kann es anrufen onBindViewHolder (ViewHolder Inhaber, Int [letzten Index +1])? enter image description here

Ich habe keine Ahnung, was könnte falsch sein. Also frage ich Hilfe, weil ich darüber nachdenke, dieses Projekt aufzugeben, weil ich alles richtig mache, aber immer etwas nicht funktioniert, und ich bin müde. Vielen Dank im Voraus.

+0

Sie müssen auch Ihren Adapter-Code einfügen. Dies geschieht höchstwahrscheinlich, weil Ihr Adapter das Löschen nicht korrekt verarbeitet. Es müsste seine Gesamtzahl reduzieren. Wenn Sie eine einfache Liste verwenden, in der die IDs die Position sind, tritt ein Problem auf, bei dem auch Ihre Ansichten neu erstellt werden müssen. –

+0

Ohne den vollständigen Code zu sehen, ist es schwer zu sagen. –

+0

Sagen Sie, welchen Teil Sie wollen, und ich poste, wenn ich alles einstelle, wird schlecht sein. Vielleicht könnte ich eine Datei-URL auf den bitbucket einfügen ... – Informatheus

Antwort

2

Wirf einen Blick auf den Adapter-Code, den du im Kommentar angegeben hast, und es ist ziemlich einfach. Versuchen Sie Folgendes: Rufen Sie statt notifyItemRemoved()notifyDataSetChanged() an. Das ist ziemlich teuer, da Ihr Adapter den Datensatz neu bindet (und ViewHolders neu erstellt), aber da Sie ein ArrayList verwenden, wo Sie ein Element entfernen, ist es wirklich der einfachste Weg, es zu tun. Andernfalls müssen Sie die Position der Elemente verfolgen. Wenn ein Objekt entfernt wird, kann es die Position anderer Objekte nicht ändern - oder den Fall behandeln, bei dem Objekte ihre Position im Datensatz verschieben.

+0

Ich habe vielleicht ein ähnliches Problem hier: http://StackOverflow.com/Questions/43531900/android-how-to-fix-recyclerview-onbindviewholder. Ich würde mich über irgendwelche Gedanken oder Ideen freuen, wie man das beheben kann. – AJW

5

Ich habe festgestellt, dass in der Methode OnBindViewHolder (VH Halter, int Position), während die Position falsch war, die holder.getAdapterPosition() gibt mir immer die richtige Position.

Also änderte ich meinen Code aus:

ItemMes item = mListaItens.get((position)); 

... 

mParentFragment.showUpdateItemDialog(position); 

... 

mParentFragment.showDeleteItemDialog(position); 

.... 

An:

ItemMes item = mListaItens.get((holder.getAdapterPosition())); 

... 

mParentFragment.showUpdateItemDialog(holder.getAdapterPosition()); 

... 

mParentFragment.showDeleteItemDialog(holder.getAdapterPosition()); 

.... 

Und alles funktioniert gut. Das ist sehr seltsam, aber ... Danke an alle.

0

Versuchen Sie diesen Code in onBindViewHolder()

int adapterPos=holder.getAdapterPosition(); 
     if (adapterPos<0){ 
      adapterPos*=-1; 
     } 

ItemMes item = mListaItens.get((adapterPos)); 
mParentFragment.showUpdateItemDialog(adapterPos); 

Verwenden adapterPos statt Position variabel.