본문 바로가기

Android Studio

파이어베이스 - 쿼리 커서로 데이터 페이지화

반응형

Cloud Firestore 데이터 베이스의 쿼리 커서로 데이터 페이지화 처리 내용 입니다.

데이터 페이지화의 필요성

 

파이어베이스의 DataBase 안의 사용량을 보시면 

무료 버전에서 하루에 읽기 가능한 수가 50,000번 입니다.

하루에 5만번 많아 보이지만 데이터의 양이 많아지면 금방 없어 지겠죠?

그래서 데이터의 페이지화를 해두면 데이터가 100개가 있어도 10개씩 읽어 오게 한다면 굳이 100개를 처음부터 다 가져올 필요가 없어 읽기의 낭비를 예방할수 있습니다. 

 

이 코드는 Cloud Firestore 와 Java를 사용합니다.

 

limit = 15 는 한번에 읽어올 데이터의 양 

private int limit = 15; 
private boolean isScrolling = false; 
private boolean isLastItemReached = false; 
private DocumentSnapshot lastVisible;RecyclerView recycler

RecyclerView와 Adapter 설정

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
List<PostInfo> postlist = new ArrayList<>();
ProductAdapter productAdapter = new ProductAdapter(postlist);
recyclerView.setAdapter(productAdapter);

 

데이터 모델과 어댑터는 자신의 코드 삽입을 위한 위치 확인용

public class PostInfo {}

public class ProductAdapter extends RecyclerView.Adapter {}

 

private void firebaseDataList() {
	// 자신의 컬렉션 명으로 수정
    CollectionReference productsRef = firebaseFirestore.collection("posts");
    // 필드명 수정  
    Query query = productsRef.orderBy("createdAt", Query.Direction.DESCENDING).limit(limit);

    query.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
        @Override
        public void onComplete(@NonNull Task<QuerySnapshot> task) {
            if (task.isSuccessful()) {
                if (task.getResult().size() <= 0) {
                    // 표시할 데이터가 없음 나가기
                } else {
                    //파이어 베이스에서 데이터 읽어 오기 위에 설정된 limit 값만큼 가져 옴
                    for (DocumentSnapshot document : task.getResult()) {
                    	// 본인 데이터 모델 수정
                        postList.add(new PostInfo(
                                document.getData().get("count").toString(),
                                document.getData().get("title").toString(),
                                document.getData().get("name").toString(),
                                document.getData().get("userPhoto").toString(),
                                document.getId()));
                    }
                    // 어댑터 수정
                    productAdapter.notifyDataSetChanged();
                    lastVisible = task.getResult().getDocuments().get(task.getResult().size() - 1);

                    // 리사이클러뷰 스크롤 리스너
                    RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
                        @Override
                        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                            super.onScrollStateChanged(recyclerView, newState);
                            if (newState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
                                isScrolling = true;
                            }
                        }

                        // 스크롤이 limit 만큼 내려오면 다음 데이터를 limit 만큼 읽어 화면에 표시한다.
                        @Override
                        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                            super.onScrolled(recyclerView, dx, dy);

                            LinearLayoutManager linearLayoutManager = ((LinearLayoutManager) recyclerView.getLayoutManager());
                            int firstVisibleItemPosition = linearLayoutManager.findFirstVisibleItemPosition();
                            int visibleItemCount = linearLayoutManager.getChildCount();
                            int totalItemCount = linearLayoutManager.getItemCount();

                            if (isScrolling && (firstVisibleItemPosition + visibleItemCount == totalItemCount) && !isLastItemReached) {
                                    isScrolling = false;
                                   	// 필드명 수정
                                    Query nextQuery = productsRef.orderBy("createdAt", Query.Direction.DESCENDING).startAfter(lastVisible).limit(limit);
                                    nextQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
                                        @Override
                                        public void onComplete(@NonNull Task<QuerySnapshot> t) {
                                            if (t.getResult().size() > 0) {
                                                if (t.isSuccessful()) {
                                                    for (DocumentSnapshot d : t.getResult()) {
                                                   		// 데이터 모델 수정
                                                        postList.add(new PostInfo(
                                                                d.getData().get("count").toString(),
                                                                d.getData().get("title").toString(),
                                                                d.getData().get("name").toString(),
                                                                d.getData().get("userPhoto").toString(),
                                                                d.getId()));
                                                    }
                                                    // 어댑터 수정
                                                    productAdapter.notifyDataSetChanged();
                                                    lastVisible = t.getResult().getDocuments().get(t.getResult().size() - 1);

                                                    if (t.getResult().size() < limit) {
                                                        isLastItemReached = true;
                                                    }
                                                }
                                            } 
                                        }
                                    });
                            }
                        }
                    };
                    recyclerView.addOnScrollListener(onScrollListener);
                }

            }
        }
    });
}

코드에서 수정이라고 되어 있는 부분은 자신의 것으로 교체 하시면 됩니다.

 

limit 에 설정된 값 만큼 처음 데이터를 불러오며 스크롤이 limit 만큼 내려오면 다시 limit 만큼 데이터를 불러오는 

형식입니다. 

 

만약 limit 가 너무 적어 스크롤이 되지 않는다면 다음 데이터가 있어도 이벤트 발생 조건이 않되기 때문에 데이터를 

불러오지 못하는 경우가 발생하니 limit에 적당한 값을 주셔야 합니다.

 

마지막으로....

하단 스크롤 되고 이벤트가 발생하여 다음 데이터를 가져오는 동안 잠깐의 딜레이가 생기는데 그때

progress bar를 넣어 화면에 표시 해 주시면 되겠네요.

 

 

 

반응형