-2

I want to update the views of my RecyclerView view every 30 seconds. I use the this statement:

adapter.notifyItemRangeChanged(0, channelsInGroup.size());

and it does not work. I could get it working by copying the contents to a new arraylist, passing the new arraylist to the adapter, and then emptying the new arraylist and repopulating it after the update, and finally calling notifyItemRangeChanged:

channelsInGroup.clear();

g = channelsLab.getGroupByTitle(mGroupTitle)
List<Channel> channelListNew = new ArrayList<Channel>();
for (Channel c : g.getChannels()) {
    channelListNew.add(c);
}

channelsInGroup.addAll(channelListNew);
adapter.notifyItemRangeChanged(0, channelsInGroup.size());

How can I update the views in the RecyclerView without having to pass a copy of the arraylist? I want to use the original g.getChannels() which gets updated periodically.

Related code snippets:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    mRootView = inflater.inflate(R.layout.fragment_channel_epg, container, false);

    RecyclerView recyclerView = mRootView.findViewById(R.id.recyclerView);
    LinearLayoutManager horizontalLayoutManagaer
            = new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false);
    recyclerView.setLayoutManager(horizontalLayoutManagaer);

    adapter = new MyRecyclerViewAdapter(getContext(), channelsInGroup);
    recyclerView.setAdapter(adapter);

    return mRootView;
}

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

    private List<Channel> mChannelsList;
    private LayoutInflater mInflater;

    MyRecyclerViewAdapter(Context context, List<Channel> channelList) {
        this.mInflater = LayoutInflater.from(context);
        this.mChannelsList = channelList;
    }

    @Override
    @NonNull
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.epg_row_of_playing_channel, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        if (mChannelsList.get(position).getProgrammeListNext24Hours() != null) {
           holder.myTextView.setText(mChannelsList.get(position).getProgrammeListNext24Hours().get(0).getTitle().get(0));
        }
        else {
            holder.myTextView.setText("yok");
        }
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myTextView = itemView.findViewById(R.id.programme_description_in_epg_bar);
        }
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    channelsLab = ChannelsLab.get(BKD_ChannelEPGFragment.this.getContext());
    g = channelsLab.getGroupByTitle(mGroupTitle);
    channelsInGroup = g.getChannels();

}
burakk
  • 1,231
  • 2
  • 22
  • 45

2 Answers2

1

If you want to animate the changes between both the old and new list then you could use DiffUtil without needing to call any notify methods. Create a class that extends DiffUtil.Callback like below.

public class MyDiffCallback extends DiffUtil.Callback {

    List<Channel> oldList;
    List<Channel> newList;

    MyDiffCallback(List<Channel> oldList, List<Channel> newList) {
        oldList = this.oldList;
        newList = this.newList;
    }

    public int getOldListSize() {
        return oldList.size;
    }

    public int getNewListSize() {
        return newList.size;
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        // If you have an id for the data then it should be used here.
        return oldList.get(oldItemPosition).id == newList.get(newItemPosition).id;
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        // Replace id with whatever is appropriate to check if the contents are the same.
        return oldList.get(oldItemPosition).id  == newList.get(newItemPosition).id;
    }
}

Then create a method inside the adapter to calculate the differences and swap the data.

public void swap(List<Channel> channelList) {
    MyDiffCallback diffCallback = new MyDiffCallback(mChannelsList, channelList);
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
    mChannelsList.clear();
    mChannelsList.addAll(channelList);
    diffResult.dispatchUpdatesTo(this);
}

Now you can do adapter.swap(newList), where newList should include the old and new data.

To add new items to the list without including the old data, just remove the mChannelsList.clear() from swap() and give it the new data you want added to the list.

Tohu
  • 151
  • 2
  • 4
  • Thank you for the answer, but my question is whether I have to supply an updated copy of the data to to the adapter every time. Why does it not work when passing the data itself (arraylist in my case)? – burakk Aug 17 '18 at 11:40
0

Just call adapter.notifyDataSetChanged()

nishant
  • 2,526
  • 1
  • 13
  • 19
  • It freezes when scrolling. I suspect that the reason is that the data is being updated at the same time... – burakk Aug 17 '18 at 00:01