2

I have a RecyclerView with Drag/Drop Capabilities. Drop/Drop is done in Custom Adapter. Using Room for Database, and Entities will not save in "dropped" order.

I have tried about a dozen different methods/githubs:

...and the list goes on...

I've cobbled together code from a bunch of different sources:

My Custom Adapter:

public class SwipeAdapt extends OmegaRecyclerView.Adapter<SwipeAdapt.ViewHolder> {

    public void onItemDismiss(int position) {
        accountList.remove(position);
        notifyItemRemoved(position);
    }
    public boolean onItemMove(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(accountList, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(accountList, i, i - 1);
            }
        }

        notifyItemMoved(fromPosition, toPosition);

        return true;
    }

    public void onItemClear() {
        for (int count = 0; count < accountList.size(); count++) {
            Account u = accountList.get(count);
            u.setId(count);
            upAccount(u);
        }
        notifyDataSetChanged();
    }

My Main Activity (Java):

    OmegaRecyclerView RVMain;
    Account crossOver;

    private ItemTouchHelper itemTouchHelper;


        RVMain = (OmegaRecyclerView) findViewById(R.id.theRV);
        RVMain.setLayoutManager(new LinearLayoutManager(this));
        getAccounts();
    }

    private void getAccounts() {
        class GetAccounts extends AsyncTask<Void,Void,List<Account>> {

            @Override
            protected List<Account> doInBackground(Void... voids) {
                List<Account> aList = DataClient.getInstance(getApplicationContext()).getAppDB().theDao().getAll();
                return aList;
            }

            @Override
            protected void onPostExecute(List<Account> accounts) {
                super.onPostExecute(accounts);
                SwipeAdapt adapter = new SwipeAdapt(MainActivity.this, accounts);
                RVMain.setAdapter(adapter);
                DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(RVMain.getContext(), new LinearLayoutManager(getApplicationContext()).getOrientation());
                RVMain.addItemDecoration(dividerItemDecoration);
                ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
                itemTouchHelper = new ItemTouchHelper(callback);
                itemTouchHelper.attachToRecyclerView(RVMain);
            }
        }

        GetAccounts ga = new GetAccounts();
        ga.execute();
    }
}

Callback for Drag/Drop

public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
    private final SwipeAdapt mAdapter;

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        //int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, 0);
    }

    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
        mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
        return true;
    }

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder instanceof ItemTouchHelperViewHolder) {
                ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
                itemViewHolder.onItemSelected();
            }
        }

        super.onSelectedChanged(viewHolder, actionState);
    }
    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
            mAdapter.onItemClear();
    }
}

Hopefully, that wasn't too much. I can put the whole thing up on GitHub, if anyone wants. I don't get any errors. Everything looks fine. According to all those sources, I'm doing it correctly. I'm 'notify'ing everything, and such. Yet, every time the activity changes, the RecyclerView order is back to what it was before the Drag/Drop. Any help is greatly appreciated. TIA!

NethCoder
  • 23
  • 4

2 Answers2

0

In the bottom of method onItemMove update all data on database with new position.

  • If you wish to preserve the order of your items once you close your app or move to another activity, you will need to add a property to your entity files which will server as an order value for it. Once added, you could access your dao and run an UPDATE SQL in the method onItemMove after reorder items and than on every load of the list, return the items ordered by that property. – Welbert Moreira Jul 30 '19 at 16:02
  • I don't suppose you have code to back up your assertion? – NethCoder Aug 08 '19 at 22:02
0

Just hoping it may help someone...

"every time the activity changes, the RecyclerView order is back to what it was before the Drag/Drop" - the problem of this behavior is in this line of code:

List<Account> aList = DataClient.getInstance(getApplicationContext()).getAppDB().theDao().getAll();

Every time "the activity changes" = everytime new unsorted aList is created. So if you want your order to be saved. You need to each of your "Account" in your DataBase add a new property such as "recyclerViewPosition". In that "recyclerViewPosition" you will save the NEW position after DragAndDrop.

Example:

Firstly, we sort every account by their recyclerViewPosition.

In Main Activity:

@Override
        protected List<Account> doInBackground(Void... voids) {
            List<Account> aList = DataClient.getInstance(getApplicationContext()).getAppDB().theDao().getAll();
            aList.sort(new Comparator<Account>() {
        @Override
        public int compare(Account a1, Account a2) {
            return Integer.compare(a1.getRecyclerViewPosition(),a1.getRecyclerViewPosition());
        }
    });
            return aList;
        }

Then in your Custom Adapter you are saving new recyclerViewPosition for the account. So when the "activity changes" a new sorted list would appear.

In Custom Adapter:

public boolean onItemMove(int fromPosition, int toPosition) {
    if (fromPosition < toPosition) {
        for (int i = fromPosition; i < toPosition; i++) {
            Collections.swap(accountList, i, i + 1);
        }
    } else {
        for (int i = fromPosition; i > toPosition; i--) {
            Collections.swap(accountList, i, i - 1);
        }
    }

    **DataClient.changeRecyclerViewPositionForTheAccount(accountDataBaseID, toPosition)**
    notifyItemMoved(fromPosition, toPosition);

    return true;
}

After that do not forget to add new functions in:

DataClient class - changeRecyclerViewPositionForTheAccount(int accountDataBaseID, int toPosition)

Account class - getRecyclerViewPosition()

Hoping you will be able to do it on your own ;)

Mistakes? - write them all and we will fix them!

pumawo
  • 11
  • 3