Как убрать дублирование данных в RecyclerView
Есть RecyclerView который берет данные с сервера, дальше сохраняет их в кэш телефона, и после отображает на устройстве. Проблема в том что у меня отображается в RecyclerView данные, которые берутся с интернета и те который уже сохранились в кэш и вывелись в RecyclerView,то есть происходит дублирование, как его убрать?
Визуально это выглядит так
Fragment где все это происходит
public class FragmentRink extends Fragment {
List<ItemSkatingRinkSchedule_2> mSkatingRinkScheduleList;
RecyclerView recyclerView;
RecyclerView.LayoutManager recyclerViewlayoutManager;
RecyclerView.Adapter recyclerViewadapter;
String URL = "";
String GET_JSON_FROM_SERVER_NUMBER = "session_number";
String GET_JSON_FROM_SERVER_START = "session_start";
String GET_JSON_FROM_SERVER_END = "session_end";
String GET_JSON_FROM_SERVER_WEEKDAYS = "weekdays";
String GET_JSON_FROM_SERVER_WEEKDAYS_AND_HOLIDAYS = "weekends_and_holidays";
RequestQueue requestQueue;
private SwipeRefreshLayout mSwipeRefreshLayout;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(homeIntent);
}
};
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_rink, container, false);
}
@Override
public void onViewCreated(@NonNull final View view, @Nullable Bundle savedInstanceState) {
recyclerView = requireView().findViewById(R.id.recy_srs);
mSkatingRinkScheduleList = new ArrayList<>();
recyclerViewadapter = new AdapterSkatingRinkSchedule_2((ArrayList<ItemSkatingRinkSchedule_2>) mSkatingRinkScheduleList);
recyclerViewlayoutManager = new LinearLayoutManager(getContext());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(recyclerViewlayoutManager);
recyclerView.setAdapter(recyclerViewadapter);
JSON_DATA_WEB_CALL();
mSwipeRefreshLayout = requireView().findViewById(R.id.ref);
mSwipeRefreshLayout.setColorSchemeResources(R.color.color_8);
mSwipeRefreshLayout.setOnRefreshListener(() -> {
mSkatingRinkScheduleList.clear();
JSON_DATA_WEB_CALL();
mSwipeRefreshLayout.setRefreshing(false);
});
}
public void JSON_DATA_WEB_CALL() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(URL, response ->
{
for (int i = 0; i < response.length(); i++) {
try {
ItemSkatingRinkSchedule_2 item = new ItemSkatingRinkSchedule_2();
JSONObject json;
json = response.getJSONObject(i);
item.set_session_number(json.getString(GET_JSON_FROM_SERVER_NUMBER));
item.set_session_start(json.getString(GET_JSON_FROM_SERVER_START));
item.set_session_end(json.getString(GET_JSON_FROM_SERVER_END));
item.set_weekdays(json.getString(GET_JSON_FROM_SERVER_WEEKDAYS));
item.set_weekends_and_holidays(json.getString(GET_JSON_FROM_SERVER_WEEKDAYS_AND_HOLIDAYS));
mSkatingRinkScheduleList.add(item);
}
catch (JSONException e) {
e.printStackTrace();
}
}
recyclerViewadapter.notifyDataSetChanged();
}, error ->
Log.e("Volley", error.toString())) {
@Override
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
try {
Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
if (cacheEntry == null) {
cacheEntry = new Cache.Entry();
}
final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely
long now = System.currentTimeMillis();
final long ttl = now + cacheExpired;
cacheEntry.data = response.data;
cacheEntry.softTtl = now;
cacheEntry.ttl = ttl;
String headerValue;
headerValue = response.headers.get("Date");
if (headerValue != null) {
cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
headerValue = response.headers.get("Last-Modified");
if (headerValue != null) {
cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
cacheEntry.responseHeaders = response.headers;
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONArray(jsonString), cacheEntry);
} catch (UnsupportedEncodingException | JSONException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(JSONArray response) {
super.deliverResponse(response);
}
@Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
@Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
};
requestQueue = Volley.newRequestQueue(requireContext());
requestQueue.add(jsonArrayRequest);
}
}
Мой Аdapter
public class AdapterSkatingRinkSchedule_2 extends RecyclerView.Adapter<AdapterSkatingRinkSchedule_2.SkatingRinkScheduleViewHolder> {
public List<ItemSkatingRinkSchedule_2> mSkatingRinkScheduleList;
public AdapterSkatingRinkSchedule_2(ArrayList<ItemSkatingRinkSchedule_2> SkatingRinkScheduleList) {
mSkatingRinkScheduleList = SkatingRinkScheduleList;
}
@NonNull
@Override
public SkatingRinkScheduleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_srs, parent, false);
return new SkatingRinkScheduleViewHolder(v);
}
public static class SkatingRinkScheduleViewHolder extends RecyclerView.ViewHolder {
public TextView number_srs, start_time_srs, end_time_srs, cost_1_srs, cost_2_srs;
public LinearLayout ll_main;
public SkatingRinkScheduleViewHolder(View itemView) {
super(itemView);
ll_main = itemView.findViewById(R.id.ll_main);
number_srs = itemView.findViewById(R.id.number_srs);
start_time_srs = itemView.findViewById(R.id.start_time_srs);
end_time_srs = itemView.findViewById(R.id.end_time_srs);
cost_1_srs = itemView.findViewById(R.id.cost_1_srs);
cost_2_srs = itemView.findViewById(R.id.cost_2_srs);
}
}
@SuppressLint("LongLogTag")
@Override
public void onBindViewHolder(SkatingRinkScheduleViewHolder holder, int position) {
ItemSkatingRinkSchedule_2 currentItem = mSkatingRinkScheduleList.get(position);
holder.number_srs.setText(currentItem.get_session_number());
holder.start_time_srs.setText(currentItem.get_session_start());
holder.end_time_srs.setText(currentItem.get_session_end());
holder.cost_1_srs.setText(currentItem.get_weekdays());
holder.cost_2_srs.setText(currentItem.get_weekends_and_holidays());
holder.ll_main.setOnClickListener(v -> {
DialogSkatingRinkSchedule dialogSRS = new DialogSkatingRinkSchedule();
dialogSRS.show(((AppCompatActivity) v.getContext()).getSupportFragmentManager(), "item");
Bundle bundle = new Bundle();
bundle.putString("number", currentItem.get_session_number());
bundle.putString("start", currentItem.get_session_start());
bundle.putString("end", currentItem.get_session_end());
bundle.putString("w", currentItem.get_weekdays());
bundle.putString("wah", currentItem.get_weekends_and_holidays());
dialogSRS.setArguments(bundle);
});
holder.getAdapterPosition();
}
@Override
public int getItemCount() {
return mSkatingRinkScheduleList.size();
}
}
Добавил List< ItemSkatingRinkSchedule_2> newArr = mSkatingRinkScheduleList.stream().distinct().collect(Collectors.toList());
@RequiresApi(api = Build.VERSION_CODES.N)
public void JSON_DATA_WEB_CALL() {
JsonArrayRequest jsonArrayRequest = new JsonArrayRequest(URL, response ->
{
for (int i = 0; i < response.length(); i++)
{
try
{
ItemSkatingRinkSchedule_2 item = new ItemSkatingRinkSchedule_2();
JSONObject json;
json = response.getJSONObject(i);
item.set_session_number(json.getString(GET_JSON_FROM_SERVER_NUMBER));
item.set_session_start(json.getString(GET_JSON_FROM_SERVER_START));
item.set_session_end(json.getString(GET_JSON_FROM_SERVER_END));
item.set_weekdays(json.getString(GET_JSON_FROM_SERVER_WEEKDAYS));
item.set_weekends_and_holidays(json.getString(GET_JSON_FROM_SERVER_WEEKDAYS_AND_HOLIDAYS));
mSkatingRinkScheduleList.add(item);
}
catch (JSONException e) {
e.printStackTrace();
}
}
List< ItemSkatingRinkSchedule_2> newArr = mSkatingRinkScheduleList.stream().distinct().collect(Collectors.toList());
recyclerViewadapter.notifyDataSetChanged();
Ответы (2 шт):
Насколько я понял вы используете этот массив mSkatingRinkScheduleList добавляя в него элементы. Это у вас List судя по коду. Чтобы убрать дубликаты можно использовать кучу примочек типа таких. Но я бы вам советовал уйти от List в сторону ArrayList< ItemSkatingRinkSchedule_2>. У данного типа массивов есть замечательный метод как distinct:
List< ItemSkatingRinkSchedule_2> newArr = list.stream().distinct().collect(Collectors.toList());
этот вызов можно разместить перед обновлением адаптера. Так же как вариант обновлять адаптер когда цикл достигает последнего элемента:
if(i== response.lastIndex()){
//update adapter
}
так же я бы вам советовал через логгирование или дебаг посмотреть на сам размер ответа от сервера, потому что я допускаю две причины такого поведения:
- В ответе и правда 4 элемента
- Вы неправильно обновляете ваш адаптер
Так же стоит посмотреть и на ваш адаптер в целом, потому что там тоже могут быть какие-то ошибки приведшие к такому неправильному поведению.
UPDATE
я думаю так - вы грузите данные из кэша и потом дополнительно грузите данные с сервера, и по итогу получается 2+2. Попробуйте переподвязывать к виджету списка адаптер с данными. Если мое первое предложение верно, то это поведение вполне нормальное. То есть вам нужно проверить если есть кэш то запрос не слать, если запрос послали то привяжите заново новый адаптер к списку с полученными данными.
Я смог реализовать задуманное следующим образом, ранее я создал метод JSON_DATA_WEB_CALL на который ссылался в onViewCreated. В JSON_DATA_WEB_CALL у меня всё шло подряд, сначала я хотел просто очищать ненужную часть списка и оставлять ту которая сохраняется в кэш. Итак, как же сделал я, в первую очередь разделил на 2 части JSON_DATA_WEB_CALL2 и JSON_PARSE_DATA_AFTER_WEBCALL, таким образом у меня запускается нужная часть. Надеюсь кому-то поможет.
JSON_PARSE_DATA_AFTER_WEBCALL
public void JSON_PARSE_DATA_AFTER_WEBCALL(JSONArray array) {
mSkatingRinkScheduleList.clear();
for (int i = 0; i < array.length(); i++) {
ItemSkatingRinkSchedule_2 GetDataAdapter2 = new ItemSkatingRinkSchedule_2();
JSONObject json;
try {
json = array.getJSONObject(i);
GetDataAdapter2.set_session_number(json.getString(GET_JSON_FROM_SERVER_NUMBER));
GetDataAdapter2.set_session_start(json.getString(GET_JSON_FROM_SERVER_START));
GetDataAdapter2.set_session_end(json.getString(GET_JSON_FROM_SERVER_END));
GetDataAdapter2.set_weekdays(json.getString(GET_JSON_FROM_SERVER_WEEKDAYS));
GetDataAdapter2.set_weekends_and_holidays(json.getString(GET_JSON_FROM_SERVER_WEEKDAYS_AND_HOLIDAYS));
} catch (JSONException e) {
e.printStackTrace();
}
mSkatingRinkScheduleList.add(GetDataAdapter2);
}
recyclerViewadapter = new AdapterSkatingRinkSchedule_2((ArrayList<ItemSkatingRinkSchedule_2>) mSkatingRinkScheduleList);
recyclerView.setAdapter(recyclerViewadapter);
}
JSON_DATA_WEB_CALL2
public void JSON_DATA_WEB_CALL2() {
jsonArrayRequest = new JsonArrayRequest(URL,
this::JSON_PARSE_DATA_AFTER_WEBCALL,
error ->
Log.e("Volley", error.toString())) {
@Override
protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {
try {
Cache.Entry cacheEntry = HttpHeaderParser.parseCacheHeaders(response);
if (cacheEntry == null) {
cacheEntry = new Cache.Entry();
}
final long cacheExpired = 24 * 60 * 60 * 1000; // in 24 hours this cache entry expires completely
long now = System.currentTimeMillis();
final long ttl = now + cacheExpired;
cacheEntry.data = response.data;
cacheEntry.softTtl = now;
cacheEntry.ttl = ttl;
String headerValue;
headerValue = response.headers.get("Date");
if (headerValue != null) {
cacheEntry.serverDate = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
headerValue = response.headers.get("Last-Modified");
if (headerValue != null) {
cacheEntry.lastModified = HttpHeaderParser.parseDateAsEpoch(headerValue);
}
cacheEntry.responseHeaders = response.headers;
final String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
return Response.success(new JSONArray(jsonString), cacheEntry);
} catch (UnsupportedEncodingException | JSONException e) {
return Response.error(new ParseError(e));
}
}
@Override
protected void deliverResponse(JSONArray response) {
super.deliverResponse(response);
}
@Override
public void deliverError(VolleyError error) {
super.deliverError(error);
}
@Override
protected VolleyError parseNetworkError(VolleyError volleyError) {
return super.parseNetworkError(volleyError);
}
};
requestQueue = Volley.newRequestQueue(getContext());
requestQueue.add(jsonArrayRequest);
}
