안드로이드 RecyclerView 무한스크롤, load more 방법


어제는 recyclerview를 이용한 firebase database 역순으로 가져오기는 방법을 포스팅했었죠? 오늘은 20개씩 가져오면서 스크롤을 맨 아래로 내렸을 때 20개를 추가로 더 가져오는 방법을 알아보겠습니다. 



이것도 그리 어렵지 않습니다. 우선 결과물을 볼게요! 

RecyclerView load more

로딩이 너무 빨리 되서, 처음에만 프로그레스 바가 뜨고 다음 로딩때부터는 뜨지 않았네요 ㅎㅎ.. 


전체 코드를 먼저 본 다음에 하나하나 알려드릴게요. 

ListActivity.java

//firebase database
//firebase database 불러오기
Dbref = FirebaseDatabase.getInstance().getReference().child("article");
Dbref.limitToLast(20).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

        for(DataSnapshot item : dataSnapshot.getChildren()){
            contents.add(0,item.getValue(Article.articledata.class));
            contents_get.add(0,item.getValue(Article.articledata.class));
            oldPost_get.add(item.getKey());
        }
        oldestPostId = oldPost_get.get(0);
        adapter = new RecyclerViewAdapter(contents);
        list_recyclerview.setAdapter(adapter);
    }
    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        Toast.makeText(ListActivity_ex.this, "예상치 못한 오류가 발생했습니다. 다시 실행해주세요.", Toast.LENGTH_SHORT).show();
    }
});
//스크롤 관련
list_recyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        //마지막 체크
        if(!list_recyclerview.canScrollVertically(1)){
            if(contents_get.size()==20){
                pd.setMessage("더 불러오는 중...");
                pd.show();
            }
            Dbref.orderByKey().endAt(oldestPostId).limitToLast(20).addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
                    contents_get.clear(); //임시저장 위치
                    oldPost_get.clear();

                    for (DataSnapshot item : dataSnapshot.getChildren()) {
                        contents_get.add(0,item.getValue(Article.articledata.class));
                        oldPost_get.add(item.getKey());
                    }
                    //불러오는 중인지, 전부 불러왔는지 if문
                    if(contents_get.size() > 1) {//1개라도 있으면 불러옴
                        //마지막 중복되는 부분 삭제
                        contents_get.remove(0);
                        //contents 뒤에 추가
                        contents.addAll(contents_get);
                        oldestPostId = oldPost_get.get(0);
                        //메시지 갱신 위치
                        adapter.notifyDataSetChanged();
                    } else {
                        Snackbar.make(getWindow().getDecorView().getRootView(), "마지막 이슈입니다.", Snackbar.LENGTH_SHORT)
                                .setAction("닫기", new View.OnClickListener() {@Override public void onClick(View view) {}}).show();
                    }
                }
                @Override
                public void onCancelled(@NonNull DatabaseError databaseError) {
                }
            });
        }
    }
    @Override
    public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
        super.onScrollStateChanged(recyclerView, newState);
    }
});

자 그럼 코드를 하나하나 살펴볼게요.

 

주요 기능

RecyclerView load more

contents_getoldPost_get이라는 ListArray를 두개 더 만든 다음 

contents_get에는 contents와 동일하게 add해주시고

oldPost_get에는 item.getKey를 해줍니다. 


contents_get은 20개씩 불러올때마다 40개, 60개 되는 게 아닌 20개씩만 담을 임시 array이고,

oldPost_get마지막에 불러온 item이 무엇인지 찾기 위한 임시 array입니다. 

그리고 oldestPostId라는 String을 만들어서 oldPost_get의 가장 첫번째(0) 항목을 get해줍니다. 


RecyclerView load more

그리고 아래쪽에 recyclerview에 OnScroll리스너를 만들어줍니다. 여기서 스크롤 시 이벤트를 제어할 수 있습니다^^


RecyclerView load more

처음 if는 스크롤이 마지막에 도달했는지를 체크해주는 코드입니다. 다른 이벤트를 넣고 싶다면 이 안에 원하시는 코드를 작성하시면 됩니다!


두번째 if는 contents_get의 사이즈가 20개인지 확인하는 코드입니다. 이게 왜 필요하냐면 예를 들어 총 데이터가 84개가 있다고 하면 스크롤이 마지막에 도달할 경우 20, 20, 20, 20, 4개를 불러와야겠죠. 이때 4개를 불러왔다면 모든 데이터를 불러온 것이기 때문에 20개 미만이 된다면 더이상 프로그레스 바를 불러오지 않도록 해주는 역할을 합니다. 


RecyclerView load more


처음에 불러왔을 때랑 조금 다르죠? orderByKey().endAt(***)이라는게 생겼습니다. 아까 저장해둔 20번째 item부터 최신 순으로 20개를 또 불러옵니다. 


RecyclerView load more

임시저장 array들을 clear해줍니다. 빈통으로 만들어놓은 뒤에 for 문에서 받아오는 새로운 데이터들을 추가할겁니다. 

RecyclerView load more

그런데, 왜 바로 contents에 추가안할까요? 

저만 그런지 몰라도 이상하게 20번째 항목들이 중복이 되는 현상이 있었습니다. 그.래.서.

RecyclerView load more

이를 해결하기 위해 if문을 만들어줍니다. 

contents_get.size()는 항상 1이상입니다. 왜냐하면 마지막 20번째 데이터가 포함되어있기 때문이죠. size가 2이상이 되어야 새로운 데이터를 불러 온 것이므로,

우선 중복되는 0번째 데이터를 삭제해준 뒤 contents에 추가해줍니다. 


생각보다는 어렵지 않죠?! 


요약하자면 

1. contents 에는 {1,2,3, ... ,18,19,20}이 들어가고 contents_get에는 {20,21,22, ... , 38,39,40}이 들어가기 때문에 중복되는 {20}을 삭제해주고 content.addAll(contents_get)을 해주는 겁니다.


2. oldPost_get은 마지막 데이터의 Key를 찾을 수 있도록 해주는 역할입니다. for문에서 string를 돌리면 항상 1번 데이터의 key만 알 수 있기 때문이죠. 

댓글

Designed by JB FACTORY