Search code examples
android-recyclerviewgoogle-cloud-firestorepositionitems

How to store items position in a RecyclerView after drag&drop


I have a simple todo list app with a RecyclerView/FirestoreRecyclerAdapter/ItemTouchHelper with items A, B, C, D (see picture attached). Now I would like to effectivly store the position of these items in Firestore, initially when I add an item and when ever I vertically drag & drop them. How can I do that conceptionally or with a existing/sample code. It's important to store it in the cloud so the items position stay the same if I look a it from another device.

Some ideas about it: The adapter positions (int) start from 0 (in this case D). When I add the item E, then this has adapter position 0, and the positions of all the other items change. So the stored position in Firestore should probably increase by 1 each time a new item is added which will be displayed at the top. But what if I have thousends of items (e.g. in a photo gallery app). Is it effective if I update the position for all the items each time I drag & drop an item?

I guess this should be a very common problem.

MainActivity of my Todo App (https://i.sstatic.net/o3jJ1.jpg)

Here is my code for the method ItemTouchHelper.Callback onMoved():

@Override
        public void onMoved(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, int fromPos, @NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
            super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);

            for (int maxItems = recyclerView.getChildCount(), i = 0; i < maxItems; ++i) {
                RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(recyclerView.getChildAt(i));
                int layoutPosition = holder.getLayoutPosition();
                int adapterPosition = holder.getAdapterPosition();
                TodoAdapter.TodoHolder h =  (TodoAdapter.TodoHolder)holder;
                String documentID = h.getDocumentID();
                TextView textViewTitle = (TextView)h.itemView.findViewById(R.id.todo_title);
                CharSequence title = textViewTitle.getText();

                DocumentReference docRef = mFirestore.collection("todos").document(documentID);
                docRef.update("position", adapterPosition);
            }
        }

Solution

  • Now I would like to effectivly store the position of these items in Firestore, initially when I add an item and when ever I vertically drag & drop them.

    While this is technically possible, I don't think that Firestore is the best option for this problem since everything in Firestore in about the number of reads and writes. So everytime you change the position of an item, you'll perfrom a number of write operations that is equal to the number of remaining items. Try to take a look also at Firebase realtime database. Both work together very well.

    How can I do that conceptionally

    Simply by adding an order number property for each element, representing the position in the list and then order them (ascending or descending) according to that property. Once you move an element from a location to another, update the position of every remaining obejct by one.

    It's important to store it in the cloud so the items position stay the same if I look a it from another device.

    If you'll keep all elements ordered, then every user will be able to see the same arrangement.

    So the stored position in Firestore should probably increase by 1 each time a new item is added

    Right, the position will be increased by one, every time you add a new item.

    Is it effective if I update the position for all the items each time I drag & drop an item?

    It will definitely be very costly to update the position of an item at the beginning of a list. Let's take an example. Let's say you have a collection of 1000 items and you want to add a new item as the second item in the list. This means that you be charged with one write operation for the adding of the item plus another 999 write operations to update the position of the remaining 999 items. So in total you'll be charged with 1000 write operation. It's up to you to decide if this feet your needs or not.