0

I am using Recycler view to display a list of elements. Each row has a button on it when we click it status changes and its background color. I am calling notifyDataSetChanged() once the status is updated but recyclerView is not getting refreshed.

else if (allGoals.getStatus() == WorkoutCashConstants.GOALS_ACHIEVE) {
                        boolean networkStatus = checkNetworkStatus();
                        if (networkStatus) {
                            dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                            if (DATE_ACCESS == null) {
                                currentTimeStamp = dateFormat.format(new Date());
                            } else {
                                currentTimeStamp = DATE_ACCESS;
                            }
                            progDialog = ProgressDialog.show(CompanyGoals_AllGoals_Fragment.this.getActivity(), "", "Goal Progress Recorded");
                            progDialog.setCancelable(true);
                            AchieveGoals achieveGoals = new AchieveGoals(Integer.parseInt(allGoals.getGoalID()), currentTimeStamp);
                            Call<AchieveGoals> achieveGoalsCall = apiModule.achieveGoal(achieveGoals);
                            achieveGoalsCall.enqueue(new Callback<AchieveGoals>() {
                                @Override
                                public void onResponse(Response<AchieveGoals> response, Retrofit retrofit) {
                                    progDialog.dismiss();
                                    if (response.isSuccess()) {
                                        progDialog.dismiss();
                                        goalsAchieved = response.body();
                                        if (goalsAchieved.getAppStatusCode() == WorkoutCashConstants.SUCCESS_API) {
                                            realm = Realm.getInstance(getContext());
                                            realm.beginTransaction();
                                            AllGoalsDB goalsDB = realm.where(AllGoalsDB.class)
                                                    .equalTo("goalID", allGoals.getGoalID()).findFirst();

                                            CompeletedDatesDB compeletedDatesDB = realm.createObject(CompeletedDatesDB.class);
                                            compeletedDatesDB.setCompletedDate(currentTimeStamp);
                                            goalsDB.getCompeletedDatesDBs().add(compeletedDatesDB);
                                            realm.commitTransaction();


                                            UserInfoDB userInfoDB = realm.where(UserInfoDB.class)
                                                    .equalTo(WorkoutCashConstants.
                                                            COLUMN_USER_ID, userId)
                                                    .findFirst();

                                            if (userInfoDB != null) {
                                                realm.beginTransaction();
                                                userInfoDB.setSweatPoints(goalsAchieved.getData().getSweatPoints());
                                                realm.commitTransaction();
                                            }




                                            realm.close();



                                            notifyDataSetChanged();

                                        }
                                    }
Sutirth
  • 1,217
  • 4
  • 15
  • 26
  • Please Check this for better understanding the Update the RecycleView Android http://stackoverflow.com/questions/27070220/recycleview-notifydatasetchanged-illegalstateexception – Rajan Bhavsar Feb 03 '16 at 06:32
  • @RajanBhavsar How is viewing a checkbox example related to my issue over here. Should i call notifyDataSetChanged() on handler?? – Sutirth Feb 03 '16 at 06:41
  • Nop For that You should have to make Listener in ViewHolder Class and then need to handle that. same as CheckBox handled in above link – Rajan Bhavsar Feb 03 '16 at 06:42
  • @RajanBhavsar A still but unclear could you help me with say pseudoCode – Sutirth Feb 03 '16 at 06:45
  • 1
    I think you should place a method inside recyclerview adapter and update the data from there. and at the end of this method, put the statement this.notifyDataSetChanged(); – ishwor kafley Feb 03 '16 at 06:50
  • @RajanBhavsar I tried moving code in View Holder. still NotifyDataSetChanged() is not working. – Sutirth Feb 03 '16 at 07:03
  • @ishworkafley hows is it any different from now what I am doing?? – Sutirth Feb 03 '16 at 07:04
  • Adapter is responsible for providing data and appearance to each of the items of recyclerview.When you update recyclerview from a seperate method inside an adapter, the update gets reflected in view right? – ishwor kafley Feb 03 '16 at 07:12
  • @ishworkafley yep. So i am using the click listener in viewHolder and when I get desired result I call notifyDataSetChanged(). what am I missing here?? – Sutirth Feb 03 '16 at 07:23
  • Viewholder your talking about is an inner class of parent adapter class I presume.And the parent class is not so very aware of classes existing inside it . so Its not so very good idea updating adapter from inner class.Beside,How bout defining a seperate method in adapter, provide data to this method and at the end apply notifyDataSetChanged. once the adapter gets notified about the updated data, you can use the same data from viewholder and the whole change gets reflected in your recycler view. – ishwor kafley Feb 03 '16 at 07:37
  • @ishworkafley the If clause which I am using above it to pursue the same function I am using notifyDataSetChanged and its working fine whereas when I use here in this respect scenario its failing to update the recyclerView – Sutirth Feb 03 '16 at 07:42

1 Answers1

0

notifyDataSetChanged() checkes getItemCount() and if the item count in the list associated with the adapter is changed the notifyDataSetChanged() takes effect. In your case you might use a toggleSelection function inside your adapter. I'm attaching one of my example adapter so that, you can have an idea about how we can achieve this behaviour.

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

        private Cursor mCursor;
        private SparseBooleanArray selectedItems;

        public ToggleSelectionListAdapter(Cursor cursor) {
            mCursor = cursor;
            selectedItems = new SparseBooleanArray();
        }

        public void toggleSelection(int pos) {
            if (selectedItems.get(pos, false)) {
                selectedItems.delete(pos);
            } else {
                selectedItems.put(pos, true);
            }
            notifyItemChanged(pos);
        }

        public int getSelectedItemCount() {
            return selectedItems.size();
        }

        public void clearSelections() {
            selectedItems.clear();
            notifyDataSetChanged();
        }

        public class ViewHolder extends RecyclerView.ViewHolder {

            public ViewHolder(final View itemView) {
                super(itemView);

                // Initialize your items of each row here
            }

            public void bindView(int pos) {
                try {
                    if (mCursor.isClosed())
                        return;

                    mCursor.moveToPosition(pos);

                    // Maintain a checked item list so that you can have a track if the item is clicked or not
                    if (checkedItems.contains(number) itemView.setBackgroundResource(R.drawable.background_selected);
                    else itemView.setBackgroundResource(R.drawable.background_normal);

                    itemView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                                    if (checkedItems.contains(number)) {
                                        checkedItems.remove(number);
                                    } else {
                                        checkedItems.add(number);
                                    }

                                // Get the index of which item should toggle the background
                                int idx = mRecyclerView.getChildAdapterPosition(v);
                                toggleSelection(idx);
                            }
                        }
                    });
            }
        }


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

            View v;

            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_row, parent, false);

            ViewHolder vh = new ViewHolder(v);

            return vh;
        }

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

            if (holder instanceof ViewHolder) {
                ViewHolder vh = (ViewHolder) holder;

                vh.bindView(position);

            }
        }

        @Override
        public int getItemCount() {

            if (mCursor == null) {
                return 0;
            }

            int n = mCursor.getCount();
            return n;
        }

        @Override
        public int getItemViewType(int position) {
            return super.getItemViewType(position);
        }

        synchronized public void swapCursor(Cursor cursor) {
            mCursor = cursor;
            notifyDataSetChanged();
        }
    }
Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
  • toggle selection won't work for me because I am using realm database in my recycler view while deleting it and putting it back might give Object invalid index error which I have faced earlier. I am just confused why my notifyDataSetChanged() is not working when I am doing every correct I guess – Sutirth Feb 03 '16 at 07:39
  • Try setAdapter while you're reinitializing your database. – Reaz Murshed Feb 03 '16 at 08:07
  • Didn't quite got you?? – Sutirth Feb 03 '16 at 08:58
  • Try reinitializing the adapter with the new dataset and then call recylerview.setAdapter() again. This is not a very good approach, but might work in your case. – Reaz Murshed Feb 03 '16 at 09:37
  • Ohh ya that approach works but its kinda very bad say if you are changing the 6th item it refreshes the list and recycler view is back at top. User experience gets spoiled – Sutirth Feb 03 '16 at 10:45
  • You can save the scrolled position and can return to the last scrolled position again. `mLayoutManager.scrollToPositionWithOffset(savedPostion, 0)` – Reaz Murshed Feb 03 '16 at 10:55