I load data from Firebase Firestore into the recycle view and try to load the data gradually when I reach the end of the list.
It seems to work, but it does not work correctly:
1) when moving to another fragment and returning back to this one, not all records are displayed and the upload does not work
2) when you try to update the list using swipeRefreshLayout, it is updated, but only the last 4 entries are shown, the upload also stops working
3) periodically when scrolling (for example, when there are fewer records than the limit itself) it may crash with an error in the 194 line lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1);
writes length = 0; index = -1
How to solve these problems? Help me please
HomeFragment.java
public class HomeFragment extends Fragment { private final int LIMIT_ITEM_LOAD = 4; private View item_1, item_2, item_3, item_4, item_5; private SwipeRefreshLayout swipeRefresh; private RecyclerView recyclerView; private LinearLayoutManager linearLayoutManager; private DocumentSnapshot lastVisible; private boolean isScrolling; private boolean isLastItemReached; private List<Meeting> list; private MeetingAdapter adapter; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); item_1 = getActivity().findViewById(R.id.item_1); item_2 = getActivity().findViewById(R.id.item_2); item_3 = getActivity().findViewById(R.id.item_3); item_4 = getActivity().findViewById(R.id.item_4); item_5 = getActivity().findViewById(R.id.item_5); BottomNavigationView navigation = getActivity().findViewById(R.id.navigation); navigation.getMenu().getItem(0).setChecked(true); setBorderItemSelected(item_1); Toolbar toolbar = view.findViewById(R.id.toolbar); ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar); ((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(false); toolbar.setTitle("Лента событий"); setHasOptionsMenu(true); recyclerView = view.findViewById(R.id.recyclerView); linearLayoutManager = new LinearLayoutManager(getContext()); recyclerView.setLayoutManager(linearLayoutManager); swipeRefresh = view.findViewById(R.id.swipeRefresh); swipeRefresh.setColorSchemeResources( R.color.orange_300, R.color.pink_300, R.color.green_300, R.color.blue_300); swipeRefresh.setOnRefreshListener(refreshListener); getLastKeyFromFirebase(); return view; } private SwipeRefreshLayout.OnRefreshListener refreshListener = new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new Handler().postDelayed(new Runnable() { @Override public void run() { swipeRefresh.setRefreshing(true); getLastKeyFromFirebase(); swipeRefresh.setRefreshing(false); } },1000); } }; private void getLastKeyFromFirebase() { Query query = FirebaseFirestore.getInstance() .collection("meetings") .orderBy("id", Query.Direction.DESCENDING) .limit(LIMIT_ITEM_LOAD); query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { if (task.isSuccessful()) { list = new ArrayList<>(); for (DocumentSnapshot document : task.getResult()) { Meeting meeting = document.toObject(Meeting.class); list.add(meeting); } adapter = new MeetingAdapter(list, getContext()); recyclerView.setAdapter(adapter); lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1); Toast.makeText(getContext(), "Основа загружена", Toast.LENGTH_SHORT).show(); recyclerView.addOnScrollListener(onScrollListener); } } }); } private RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) { isScrolling = true; } } @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int firstVisibleItem = linearLayoutManager.findFirstVisibleItemPosition(); int visibleItemCount = linearLayoutManager.getChildCount(); int totalItemCount = linearLayoutManager.getItemCount(); Log.d("Ok","firstVisibleItem = " + firstVisibleItem); Log.d("Ok","visibleItemCount = " + visibleItemCount); Log.d("Ok","totalItemCount = " + totalItemCount); if (isScrolling && (firstVisibleItem + visibleItemCount == totalItemCount) && !isLastItemReached) { isScrolling = false; Query nextQuery = FirebaseFirestore.getInstance() .collection("meetings") .orderBy("id", Query.Direction.DESCENDING) .startAfter(lastVisible) .limit(LIMIT_ITEM_LOAD); nextQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() { @Override public void onComplete(@NonNull Task<QuerySnapshot> task) { for (DocumentSnapshot document : task.getResult()) { Meeting meeting = document.toObject(Meeting.class); list.add(meeting); } adapter.notifyDataSetChanged(); lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1); Toast.makeText(getContext(), "Подгрузка завершена", Toast.LENGTH_SHORT).show(); if (task.getResult().size() < LIMIT_ITEM_LOAD) { isLastItemReached = true; } } }); } } }; @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_filtration: // break; default: break; } return true; } public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.toolbar_home, menu); super.onCreateOptionsMenu(menu, inflater); } }
MeetingAdapter.java
public class MeetingAdapter extends RecyclerView.Adapter<MeetingAdapter.MyViewHolder> { private List<Meeting> meetingsList; private Context context; public MeetingAdapter(List<Meeting> meetingsList, Context context) { this.meetingsList = meetingsList; this.context = context; } @NonNull @Override public MeetingAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(context).inflate(R.layout.item_meeting, parent, false); return new MeetingAdapter.MyViewHolder(itemView); } @Override public void onBindViewHolder(@NonNull MeetingAdapter.MyViewHolder holder, int position) { holder.date.setText(meetingsList.get(position).getDate()); holder.title.setText(meetingsList.get(position).getTitle()); } @Override public int getItemCount() { return meetingsList.size(); } class MyViewHolder extends RecyclerView.ViewHolder { private TextView date, title; MyViewHolder(View itemView) { super(itemView); date = itemView.findViewById(R.id.date); title = itemView.findViewById(R.id.title); } } }