問題を取得するためのコードと手順の後に表示します
カスタムオブジェクトからデータセットを取得するタブ付きフラグメント内にrecyclerviewがあります。
mRecyclerView = (RecyclerView) v.findViewById(R.id.recyclerview);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerAdapter = new MyRecyclerAdapter(mMes.getListaItens(), this, getActivity());
mRecyclerView.setAdapter(mRecyclerAdapter);
アダプターのonBindViewHolder()でリスト項目のロングクリック動作を設定します。
@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;
}
});
}
次に、フラグメント自体のメソッドがアイテム自体を削除します。
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();
}
そして最後に、DB操作を行うアクティビティ内のメソッド:
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;
}
次に、手順を再現します。リストビューに3つのアイテムを表示しています。それから私は最初のものを削除しようとします:
1-longclickは正しいインデックスを渡して傍受されます:
3-結局のところ、予想通り、アダプターは2つのアイテムを格納して表示しています...
SO、この2項目リストの最初の項目を削除しようとすると、間違った位置が表示されます(0である必要があり、1です):
また、この2つのアイテムリストの最後のアイテムを削除しようとすると、間違った位置が表示されます(1である必要があります2です):
問題は、私がサイズ2のデータセットを持っている(そしてアダプターがそれを知っている)場合、onBindViewHolder(ViewHolderholder、int [last index +1])を呼び出すにはどうすればよいですか?
何が悪いのか私にはわかりません。だから私はこのプロジェクトをあきらめることを考えているので助けを求めます私はすべてを正しく行いますが常に何かがうまくいかないので、私は疲れています。 よろしくお願いします。
位置が間違っていたときにメソッドonBindViewHolder(VHholder、int position)で、holder.getAdapterPosition()が常に正しい位置を提供していることに気付きました。
だから私は私のコードを次のように変更しました:
ItemMes item = mListaItens.get((position));
...
mParentFragment.showUpdateItemDialog(position);
...
mParentFragment.showDeleteItemDialog(position);
....
に:
ItemMes item = mListaItens.get((holder.getAdapterPosition()));
...
mParentFragment.showUpdateItemDialog(holder.getAdapterPosition());
...
mParentFragment.showDeleteItemDialog(holder.getAdapterPosition());
....
そして、すべてがうまくいきます。これは非常に奇妙ですが...みんなありがとう。
コメントで提供したアダプターコードを見てみると、かなり簡単です。これを試してください:notifyItemRemoved()
を呼び出すのではなく、notifyDataSetChanged()
を呼び出します。アダプターがデータセットを再バインドする(そしてViewHolders
を再作成する)ため、これはかなりコストがかかりますが、要素を削除する場所でArrayList
を使用しているため、それは本当にそれを行う最も簡単な方法です。それ以外の場合は、アイテムの位置を追跡する必要があります。アイテムが削除されると、他のアイテムの位置を変更できません。または、アイテムがデータセット内で位置をシフトする場合に対処できます。
RecyclerView
のgetAdapterPosition
ドキュメントによると:
RecyclerViewは、次のレイアウトトラバーサルまでアダプターの更新を処理しません。これにより、ユーザーが画面に表示するものとアダプタの内容との間に一時的な不整合が生じる可能性があります。この不整合は16ms未満になるため重要ではありませんが、ViewHolder位置を使用してアダプターにアクセスする場合は問題になる可能性があります。 ユーザーイベントに応じてアクションを実行するために、正確なアダプター位置を取得する必要がある場合があります。その場合、ViewHolderのアダプター位置を計算するこのメソッドを使用する必要があります。
したがって、ユーザーイベントを実装する場合は、getAdapterPosition
を使用することをお勧めします。
このコードをonBindViewHolder()で試してください
int adapterPos=holder.getAdapterPosition();
if (adapterPos<0){
adapterPos*=-1;
}
ItemMes item = mListaItens.get((adapterPos));
mParentFragment.showUpdateItemDialog(adapterPos);
位置変数の代わりにadapterPosを使用します。