Sort a RecyclerView from a value that is generated in the Adapter and not an Object variable?

+1 vote
asked Sep 12, 2017 by florian-walther

Sorting an ArrayList from a value in the ArrayList is no problem, but I have an int that gets calculated directly in the Adapter and I prefer to keep it there, because it seems like a clean solution.

timeLeftinMinutes is the value I want to sort the RecyclerView for, but I don't know how to get it into the Activity (The exact calculation is not so important):

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    int dueHour = mTaskList.get(position).getDueHour();
    int dueMinute = mTaskList.get(position).getDueMinute();
    Calendar calendar = Calendar.getInstance();
    int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
    int currentMinute = calendar.get(Calendar.MINUTE);

    //correcting values to over 24 if necessary
    int mBedHourPlus24IfNecessary;
    if (mBedHour < mWakeUpHour || mBedHour == mWakeUpHour && mBedMinute < mWakeUpMinute) mBedHourPlus24IfNecessary = mBedHour + 24;
    else mBedHourPlus24IfNecessary = mBedHour;
    int mDueHourPlus24IfNecessary;
    if (dueHour < mWakeUpHour ) mDueHourPlus24IfNecessary = dueHour + 24;
    else mDueHourPlus24IfNecessary = dueHour;


    int timeLeftInMinutes;
    if (mDueHourPlus24IfNecessary > mBedHourPlus24IfNecessary || mDueHourPlus24IfNecessary == mBedHourPlus24IfNecessary && dueMinute > mBedMinute) {
        holder.mTimeLeft.setText(mContext.getResources().getString(R.string.while_sleeping));
        holder.mCardContainer.setCardBackgroundColor(ContextCompat.getColor(mContext, R.color.task_blue));
        timeLeftInMinutes = 999999999;
    } else {
        timeLeftInMinutes = (mDueHourPlus24IfNecessary * 60 + dueMinute) - (currentHour * 60 + currentMinute);
}

1 Answer

+2 votes
answered Sep 12, 2017 by xiaomi

It is not a good idea to use onBindViewHolder because it is called only for the object that are going to appear on the screen and therefore you won't know the timeLeftInMinutes for all item.

A better solution would be to add, into your adapter, a method that would go through your array, computer the time for each item, save it into the item, notify the adapter that the list is ready

public void updateAndSort(List<MyObject> list) {
    //Go through all your item and computer their time left.
    for (int i = 0; i < list.size(); i++) {
        //Compute the value you need to compare for each item
        list.get(i).timeLeftInMinute = timeComputed...
    }

    //Then you order your list, for example ascendant
    Collections.sort(list, new Comparator<MyObject>() {
        @Override
        public int compare(MyObject o1, MyObject o2) {
            if (o1.timeLeftInMinute > o2.timeLeftInMinute) {
                return 1;
            } else {
                return -1;
            }
        }
    });

    //replace your mTaskList the sorted list to your adapter
    mTaskList = list;

    //notify the adapter to correctly display the times
    notifyDataSetChanged()

}
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
...