페이징 처리란? 어떤 데이터를 검색했을 때, 100개의 데이터가 검색되었다면
한번에 다 보여주는것이 아니고 10개씩 20개씩 나누어 보여주는 것을 의미한다.
다음 페이지로 넘어가기위해서 번호로 다음 페이지를 넣어주는 방법 또한 있지만
스크롤하여 콘텐츠를 열람하는 Recyclerview 는 보통 페이지를 끝까지 내렸을 때
다음 페이지를 더 불러오는 방식을 채택한다.
Recyclerview에서 페이징 처리하는 방법에 대해 알아보자.
예제는 검색 키워드로 youtube API 를 이용해 데이터를 불러와 페이지에 20개씩 나열하는 앱이다.
아래는 일반적인 예제로 페이징 처리가 되지 않고 데이터를 불러오는 시점까지만 구현된 코드이다.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editSearch = findViewById(R.id.editSearch);
imgSearch = findViewById(R.id.imgSearch);
progressBar = findViewById(R.id.progressBar);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
// 리스트를 맨 밑에까지 가면, 알수 있는 방법!
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
// todo 이제 기존 키워드를 지우고 새로운 키워드를 검색했을 때의 처리를 해주어야한다.
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
int totalCount = recyclerView.getAdapter().getItemCount();
// 스크롤을 맨 끝까지 한것!
if(lastPosition + 1 == totalCount){
// 네트워크를 통해서 데이터를 가져온다.
if (pageToken == null) {
return;
}
// 1. 프로그레스바를 돌린다.
progressBar.setVisibility(View.VISIBLE);
// 2. URL을 조합한다.
// ?part=snippet&key=[자신의 API KEY]&q=축구&maxResults=20
String url = Config.BASE_URL + "?part=snippet&key="+
Config.GOOGLE_API_KEY + "&q="+keyword+"&maxResults=20&pageToken="+pageToken;
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
try {
if (response.has("nextPageToken")){
pageToken = response.getString("nextPageToken");
} else {
pageToken = null;
}
JSONArray dataList = response.getJSONArray("items");
for(int i = 0; i < dataList.length(); i++){
String title = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("title");
String description = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("description");
String imgUrl = dataList.getJSONObject(i)
.getJSONObject("snippet").getJSONObject("thumbnails")
.getJSONObject("medium").getString("url");
String videoId = dataList.getJSONObject(i)
.getJSONObject("id").getString("videoId");
Video video = new Video(title, description, imgUrl, videoId);
videoList.add(video);
}
} catch (JSONException e) {
e.printStackTrace();
}
adapter.notifyDataSetChanged();
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
}
}
);
queue.add(request);
}
}
});
progressBar.setVisibility(View.INVISIBLE);
imgSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 검색 버튼 누르면, 네트워크로 데이터 요청해서
// 정보를 받아온다.
// 1. 에디트텍스트로부터 검색어를 가져온다.
keyword = editSearch.getText().toString().trim();
// 2. 검색어가 없으면, 검색어를 넣으라고 한다.
if(keyword.isEmpty()){
Toast.makeText(MainActivity.this, "검색어를 입력하세요.", Toast.LENGTH_SHORT).show();
return;
}
// 3. 프로그레스바를 돌린다.
progressBar.setVisibility(View.VISIBLE);
videoList.clear();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
// 4. URL을 조합한다.
// ?part=snippet&key=[자신의 API KEY]&q=축구&maxResults=20
String url = Config.BASE_URL + "?part=snippet&key="+
Config.GOOGLE_API_KEY + "&q="+keyword+"&maxResults=20";
// 5. 네트워크 통신한다.
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
try {
if (response.has("nextPageToken")){
pageToken = response.getString("nextPageToken");
} else {
pageToken = null;
}
JSONArray dataList = response.getJSONArray("items");
for(int i = 0; i < dataList.length(); i++){
String title = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("title");
String description = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("description");
String imgUrl = dataList.getJSONObject(i)
.getJSONObject("snippet").getJSONObject("thumbnails")
.getJSONObject("medium").getString("url");
String videoId = dataList.getJSONObject(i)
.getJSONObject("id").getString("videoId");
Video video = new Video(title, description, imgUrl, videoId);
videoList.add(video);
}
} catch (JSONException e) {
e.printStackTrace();
}
adapter = new VideoAdapter(MainActivity.this, videoList);
recyclerView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
}
}
);
queue.add(request);
}
});
}
}
이 때 Recyclerview 뷰의 메소드를 오버라이드 하기 위해
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
});
을 입력하여
맨 위 두 개의 메소드를 오버라이드 해주자.
이 때 오버라이드 하는 위치는 onCreate 바로 아래에서 Recyclerview 를 불러오자마자이다.
두 개 중 위의 함수는 당장 사용하지 않고
아래의
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
함수에 코드를 작성한다.
int lastPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
int totalCount = recyclerView.getAdapter().getItemCount();
// 스크롤을 맨 끝까지 한것!
if(lastPosition + 1 == totalCount){
// 네트워크를 통해서 데이터를 가져온다.
if (pageToken == null) {
return;
}
스크롤을 맨 끝까지 내렸을 때의 수치와 item 갯수를 비교해 서로 맞았을 때
(페이지를 끝까지 내려서 모든 아이템이 노출되었을 때)
함수를 작동시키며 youtube api에선 pageToken 제공하므로 이를 이용하였다.
(없을 땐 멤버변수에 int count 를 만들어 사용)
그 후 먼저 네트워크와 통신해 데이터를 가져왔던 코드를 붙여넣어 몇 가지 코드를 수정해준다.
수정하여 추가된 코드는 다음과 같다.
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
int totalCount = recyclerView.getAdapter().getItemCount();
// 스크롤을 맨 끝까지 한것!
if(lastPosition + 1 == totalCount){
// 네트워크를 통해서 데이터를 가져온다.
if (pageToken == null) {
return;
}
// 1. 프로그레스바를 돌린다.
progressBar.setVisibility(View.VISIBLE);
// 2. URL을 조합한다.
// ?part=snippet&key=[자신의 API KEY]&q=축구&maxResults=20
String url = Config.BASE_URL + "?part=snippet&key="+
Config.GOOGLE_API_KEY + "&q="+keyword+"&maxResults=20&pageToken="+pageToken;
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
try {
if (response.has("nextPageToken")){
pageToken = response.getString("nextPageToken");
} else {
pageToken = null;
}
JSONArray dataList = response.getJSONArray("items");
for(int i = 0; i < dataList.length(); i++){
String title = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("title");
String description = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("description");
String imgUrl = dataList.getJSONObject(i)
.getJSONObject("snippet").getJSONObject("thumbnails")
.getJSONObject("medium").getString("url");
String videoId = dataList.getJSONObject(i)
.getJSONObject("id").getString("videoId");
Video video = new Video(title, description, imgUrl, videoId);
videoList.add(video);
}
} catch (JSONException e) {
e.printStackTrace();
}
adapter.notifyDataSetChanged();
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
}
}
);
queue.add(request);
}
}
});
전체 코드는 다음과 같다.
public class MainActivity extends AppCompatActivity {
EditText editSearch;
ImageView imgSearch;
ProgressBar progressBar;
// 리사이클러뷰 관련 멤버변수
RecyclerView recyclerView;
// 어댑터, 어레이리스트 필요
VideoAdapter adapter;
ArrayList<Video> videoList = new ArrayList<Video>();
// 페이징에 필요한 변수
String pageToken;
String keyword;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editSearch = findViewById(R.id.editSearch);
imgSearch = findViewById(R.id.imgSearch);
progressBar = findViewById(R.id.progressBar);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this));
// 리스트를 맨 밑에까지 가면, 알수 있는 방법!
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int lastPosition = ((LinearLayoutManager)recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition();
int totalCount = recyclerView.getAdapter().getItemCount();
// 스크롤을 맨 끝까지 한것!
if(lastPosition + 1 == totalCount){
// 네트워크를 통해서 데이터를 가져온다.
if (pageToken == null) {
return;
}
// 1. 프로그레스바를 돌린다.
progressBar.setVisibility(View.VISIBLE);
// 2. URL을 조합한다.
// ?part=snippet&key=[자신의 API KEY]&q=축구&maxResults=20
String url = Config.BASE_URL + "?part=snippet&key="+
Config.GOOGLE_API_KEY + "&q="+keyword+"&maxResults=20&pageToken="+pageToken;
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
try {
if (response.has("nextPageToken")){
pageToken = response.getString("nextPageToken");
} else {
pageToken = null;
}
JSONArray dataList = response.getJSONArray("items");
for(int i = 0; i < dataList.length(); i++){
String title = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("title");
String description = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("description");
String imgUrl = dataList.getJSONObject(i)
.getJSONObject("snippet").getJSONObject("thumbnails")
.getJSONObject("medium").getString("url");
String videoId = dataList.getJSONObject(i)
.getJSONObject("id").getString("videoId");
Video video = new Video(title, description, imgUrl, videoId);
videoList.add(video);
}
} catch (JSONException e) {
e.printStackTrace();
}
adapter.notifyDataSetChanged();
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
}
}
);
queue.add(request);
}
}
});
progressBar.setVisibility(View.INVISIBLE);
imgSearch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 검색 버튼 누르면, 네트워크로 데이터 요청해서
// 정보를 받아온다.
// 1. 에디트텍스트로부터 검색어를 가져온다.
keyword = editSearch.getText().toString().trim();
// 2. 검색어가 없으면, 검색어를 넣으라고 한다.
if(keyword.isEmpty()){
Toast.makeText(MainActivity.this, "검색어를 입력하세요.", Toast.LENGTH_SHORT).show();
return;
}
// 3. 프로그레스바를 돌린다.
progressBar.setVisibility(View.VISIBLE);
videoList.clear();
if (adapter != null) {
adapter.notifyDataSetChanged();
}
// 4. URL을 조합한다.
// ?part=snippet&key=[자신의 API KEY]&q=축구&maxResults=20
String url = Config.BASE_URL + "?part=snippet&key="+
Config.GOOGLE_API_KEY + "&q="+keyword+"&maxResults=20";
// 5. 네트워크 통신한다.
RequestQueue queue = Volley.newRequestQueue(MainActivity.this);
JsonObjectRequest request = new JsonObjectRequest(
Request.Method.GET,
url,
null,
new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject response) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
try {
if (response.has("nextPageToken")){
pageToken = response.getString("nextPageToken");
} else {
pageToken = null;
}
JSONArray dataList = response.getJSONArray("items");
for(int i = 0; i < dataList.length(); i++){
String title = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("title");
String description = dataList.getJSONObject(i)
.getJSONObject("snippet").getString("description");
String imgUrl = dataList.getJSONObject(i)
.getJSONObject("snippet").getJSONObject("thumbnails")
.getJSONObject("medium").getString("url");
String videoId = dataList.getJSONObject(i)
.getJSONObject("id").getString("videoId");
Video video = new Video(title, description, imgUrl, videoId);
videoList.add(video);
}
} catch (JSONException e) {
e.printStackTrace();
}
adapter = new VideoAdapter(MainActivity.this, videoList);
recyclerView.setAdapter(adapter);
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// 데이터를 받아오면, 프로그레스바를 안보이게 한다.
progressBar.setVisibility(View.INVISIBLE);
}
}
);
queue.add(request);
}
});
}
}
'Android' 카테고리의 다른 글
Android Studio - Retrofit 라이브러리를 사용하기 위한 환경설정 (0) | 2022.07.21 |
---|---|
Android Studio - 기기의 카메라 / 앨범 사용하기 (0) | 2022.07.21 |
Android Studio - 이미지 처리를 위한 Glide 사용법 (0) | 2022.07.20 |
Android Studio - Trust project, 신뢰하는 프로젝트 눌러도 반응 없을 때 / 안전모드에서 멈출 때 해결법 (0) | 2022.07.20 |
Android Studio - Floating Action Button 사용하는 방법 (0) | 2022.07.19 |
댓글