idiotme
idiotme

Reputation: 63

After deleting item, RecyclerView does not update

I'm implementing a RecyclerView to show a list of Transactions. In one of its two ViewHolders, there is a button to delete transaction. The problem is, after clicking the button, nothing happened to the RecyclerView. I'm using Realm and MVP pattern, and have tried all solutions I could find, but nothing seems to work.

Here's TransactionListActivity, where the RecyclerView will be shown:

public class TransactionListActivity extends BaseActivity implements TransactionListView {

private static final String TAG = "TransactionListActivity";

@Inject
TransactionListPresenterInterface<TransactionListView> mPresenter;

TransactionListAdapter transactionListAdapter;

@BindView(R.id.transaction_list_recyclerview)
RecyclerView transactionListRecyclerView;

@Override
public void onPrepareTransactionListAdapter() {
    LinearLayoutManager layoutManager
            = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);

    transactionListRecyclerView.setLayoutManager(layoutManager);

    List<TransactionListItem> transactionListItems = mPresenter.getAllTransactionItems();

    transactionListAdapter = new TransactionListAdapter(this, transactionListItems);
    transactionListAdapter.setOnDeleteTransactionClickListener(this::onDeleteTransaction);

    transactionListRecyclerView.setAdapter(transactionListAdapter);

}

@Override
public void onDeleteTransaction(String id) {
    mPresenter.onDeleteTransactionClick(String id);
}

@Override
public void refresh() {
    transactionListAdapter.notifyDataSetChanged();
}


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_transaction_list);

    getActivityComponent().inject(this);

    setUnBinder(ButterKnife.bind(this));
    ButterKnife.bind(this);

    mPresenter.onAttach(this);

    onPrepareTransactionListAdapter();
}

Here's my adapter:

public class TransactionListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private static final String TAG = "TransactionListAdapter";

private Context context;
public List<TransactionListItem> transactionListItems;
private OnDeleteTransactionClickListener mOnDeleteTransactionClickListener;

public TransactionListAdapter(Context context, List<TransactionListItem> transactionListItems) {
    this.context = context;
    this.transactionListItems = transactionListItems;
}

class TransactionItemViewHolder extends RecyclerView.ViewHolder {

    ...

    @BindView(R.id.delete_transaction_button)
    Button deleteTransactionButton;

    ...

    public TransactionItemViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
    }
}

class TransactionDateViewHolder extends RecyclerView.ViewHolder {
    ...
}

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

    RecyclerView.ViewHolder viewHolder = null;
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());

    switch(viewType) {

        case TransactionListItem.TYPE_DATE:
            //inflate TransactionDateViewHolder here

        case TransactionListItem.TYPE_TRANSACTION:
            //inflate TransactionItemViewHolder here
    }

    return viewHolder;
}

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {

    switch(viewHolder.getItemViewType()) {

        case TransactionListItem.TYPE_TRANSACTION:

            ProductStockRecord productStockRecord = (ProductStockRecord) transactionListItems.get(position);
            TransactionItemViewHolder transactionItemViewHolder = (TransactionItemViewHolder) viewHolder;
            // populate view with data here
            ((TransactionItemViewHolder) viewHolder).deleteTransactionButton.setOnClickListener(v -> {
                if (mOnDeleteTransactionClickListener != null) {
                    mOnDeleteTransactionClickListener.onDeleteTransactionClick(productStockRecord.getId());
                }
            });
            break;

        case TransactionListItem.TYPE_DATE:

            //populate view with data here
            break;

    }

}

@Override
public int getItemCount() {
    return transactionListItems.size();
}

@Override
public int getItemViewType(int position) { return transactionListItems.get(position).getType(); }

public void setOnDeleteTransactionClickListener(final OnDeleteTransactionClickListener onDeleteTransactionClickListener) {
    mOnDeleteTransactionClickListener = onDeleteTransactionClickListener;
}

public interface OnDeleteTransactionClickListener {
    void onDeleteTransactionClick(String id);
}

}

And here's my presenter:

public class TransactionListPresenter<V extends TransactionListView> extends BasePresenter<V> implements TransactionListPresenterInterface<V>, RealmDataManager.OnTransactionCallback {

private static final String TAG = "TransaxListPresenter";

@Inject
public TransactionListPresenter(final RealmDataManager realmDataManager) { super(realmDataManager); }

@Override
public List<TransactionListItem> getAllTransactionItems() {
    List<ProductStockRecord> productStockRecordList = getRealmDataManager().getAllProductStockRecords();

    List<TransactionListItem> transactionListItems = new ArrayList<>();
    // preprocess transactions here

    return transactionListItems;
}

@Override
public void onDeleteTransactionClick(String id) {
    getRealmDataManager().deleteProductStockRecord(id, this);
    getView().refresh();
    Log.d(TAG,"deleteTransaction() performed");
}

}

Here's the updated (and working) version of RealmService, and all codes above have been fixed accordingly:

public void deleteProductStockRecord(final String id, final OnTransactionCallback onTransactionCallback) {
    mRealm.executeTransactionAsync(realm -> {
        ProductStockRecord productStockRecord = realm.where(ProductStockRecord.class).equalTo("id", id).findFirst();
        productStockRecord.deleteFromRealm();
    }, () -> {
        if (onTransactionCallback != null) {
            onTransactionCallback.onRealmSuccess();
        }
    }, error -> {
        if (onTransactionCallback != null) {
            onTransactionCallback.onRealmError(error);
        }
    });
}

I believe I make some mistakes somewhere in my adapter implementation. I would be really thankful if anyone could help me fix the problem, point my mistake, or point me in the right direction. Thanks in advance

Upvotes: 1

Views: 2530

Answers (2)

In case you meant "recyclerview visibly does not change":

If you delete an item from a recyclerview, you can use mAdapter.notifyDataSetChanged();. Doing this updates the contents of the visible recyclerview to the items in the list of the adapter at the moment of calling.

Upvotes: 0

Bazinga
Bazinga

Reputation: 499

I think the issue might be the reference to List<TransactionListItem> is not updated in your adapter.

If you look at this code in your presenter:

@Override
public List<TransactionListItem> getAllTransactionItems() {
    List<ProductStockRecord> productStockRecordList = getRealmDataManager().getAllProductStockRecords();

    List<TransactionListItem> transactionListItems = new ArrayList<>();
    // preprocess transactions here

    return transactionListItems;
}

You're creating a new List<TransactionListItem> which is what your adapter is pointing to. So in your onDeleteTransactionClick method, you have to make sure you pass the updated list to your adapter before calling getView().refresh(). Because otherwise, the list in the adapter won't change and you will see that the item is not being deleted.

Ideally though, I would recommend using something like DiffUtil (or calculate manually) to get the position of the deleted item and call notifyItemRemoved instead of refreshing the entire RecyclerView.

Upvotes: 1

Related Questions