이번 포스팅에선 리사이클러뷰에 간단하게 페이징을 적용해 보겠습니다.
먼저 의존성 문구를 앱 수준 gradle 파일에 추가해줍니다.
레트로핏으로 네트워크 통신을 한 다음, 이미지를 받아와 리사이클러뷰로 보여줄 것이기 때문에 아래와 같은 의존성 문구들을 넣어주면 됩니다.
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.6.4'
implementation 'com.squareup.retrofit2:converter-scalars:2.6.4'
implementation 'com.github.bumptech.glide:glide:4.10.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
그리고 레트로핏을 쓸 것이기 때문에 매니페스트에 인터넷 태그는 꼭 넣어줘야 합니다.
<uses-permission android:name="android.permission.INTERNET"/>
이제 리사이클러뷰에 붙일 어댑터를 만들어 보겠습니다.
먼저 어댑터에서 사용할 아이템 xml입니다. 이름은 list_row_main.xml입니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="4dp"
app:cardCornerRadius="4dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/image_view"
android:layout_width="150dp"
android:layout_height="80dp"
android:scaleType="centerCrop"/>
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:gravity="center"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
다음으로 모델 클래스 코드입니다.
public class MainData
{
private String image, name;
public String getImage()
{
return image;
}
public void setImage(String image)
{
this.image = image;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
다음으로 어댑터 코드입니다.
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import java.util.ArrayList;
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder>
{
private ArrayList<MainData> dataArrayList;
private Activity activity;
public MainAdapter(Activity activity, ArrayList<MainData> dataArrayList)
{
this.activity = activity;
this.dataArrayList = dataArrayList;
}
@NonNull
@Override
public MainAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_row_main, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MainAdapter.ViewHolder holder, int position)
{
MainData data = dataArrayList.get(position);
Glide.with(activity)
.load(data.getImage())
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(holder.imageView);
holder.textView.setText(data.getName());
}
@Override
public int getItemCount()
{
return dataArrayList.size();
}
public class ViewHolder extends RecyclerView.ViewHolder
{
ImageView imageView;
TextView textView;
public ViewHolder(@NonNull View view)
{
super(view);
imageView = view.findViewById(R.id.image_view);
textView = view.findViewById(R.id.text_view);
}
}
}
다음은 레트로핏을 사용할 때 필요한 인터페이스 클래스입니다.
GET 메서드를 쓰기 때문에 아래와 같이 만들었습니다.
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface MainInterface
{
@GET("v2/list")
Call<String> string_call(
@Query("page") int page,
@Query("limit") int limit
);
}
이제 메인 액티비티의 xml부터 만들어 보겠습니다.
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scroll_view"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="4dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:nestedScrollingEnabled="false"
tools:listitem="@layout/list_row_main"/>
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
아래에서 위로 스크롤 할 때마다 모든 데이터를 다 보여주면 제일 하단 부분에 둥글게 돌아가는 프로그레스 바를 보여줄 겁니다.
이 프로그레스 바는 다음에 보여줄 데이터들을 모두 가져와 리사이클러뷰에 들어가게 되면 사용자의 눈에 보이지 않게 됩니다.
더 자세한 내용은 아래 자바 코드를 확인해 주세요.
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.widget.NestedScrollView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
public class MainActivity extends AppCompatActivity
{
NestedScrollView nestedScrollView;
RecyclerView recyclerView;
ProgressBar progressBar;
ArrayList<MainData> dataArrayList = new ArrayList<>();
MainAdapter adapter;
// 1페이지에 10개씩 데이터를 불러온다
int page = 1, limit = 10;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nestedScrollView = findViewById(R.id.scroll_view);
recyclerView = findViewById(R.id.recycler_view);
progressBar = findViewById(R.id.progress_bar);
adapter = new MainAdapter(MainActivity.this, dataArrayList);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
getData(page, limit);
nestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener()
{
@Override
public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)
{
if (scrollY == v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())
{
page++;
progressBar.setVisibility(View.VISIBLE);
getData(page, limit);
}
}
});
}
private void getData(int page, int limit)
{
// 레트로핏 초기화
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://picsum.photos/")
.addConverterFactory(ScalarsConverterFactory.create())
.build();
MainInterface mainInterface = retrofit.create(MainInterface.class);
Call<String> call = mainInterface.string_call(page, limit);
call.enqueue(new Callback<String>()
{
@Override
public void onResponse(Call<String> call, Response<String> response)
{
if (response.isSuccessful() && response.body() != null)
{
progressBar.setVisibility(View.GONE);
try
{
JSONArray jsonArray = new JSONArray(response.body());
parseResult(jsonArray);
}
catch (JSONException e)
{
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<String> call, Throwable t)
{
Log.e("에러 : ", t.getMessage());
}
});
}
private void parseResult(JSONArray jsonArray)
{
for (int i = 0; i < jsonArray.length(); i++)
{
try
{
JSONObject jsonObject = jsonArray.getJSONObject(i);
MainData data = new MainData();
data.setImage(jsonObject.getString("download_url"));
data.setName(jsonObject.getString("author"));
dataArrayList.add(data);
}
catch (JSONException e)
{
e.printStackTrace();
}
adapter = new MainAdapter(MainActivity.this, dataArrayList);
recyclerView.setAdapter(adapter);
}
}
}
1페이지마다 10개씩 데이터를 불러옵니다. 이제 위 예제를 실행해 보면 아래와 같이 작동하는 걸 볼 수 있습니다.
한 페이지에 모든 데이터를 담기 힘들 때 생각해볼 수 있는 것 중 하나가 리사이클러뷰인데, 리사이클러뷰로도 표현하기엔 너무 많은 데이터들을 보여줄 경우 위와 같은 페이징 처리를 생각해보는 것도 좋을 것 같습니다.
스틱코드에서 이 포스팅에 쓰인 코드를 확인해 보시려면 아래 링크를 확인해 보세요.
stickode.com/detail.html?no=2024
Glide가 아닌 다른 이미지 라이브러리를 쓰고 싶다면 아래 링크(Picasso)를 참고해 보세요.
stickode.com/detail.html?no=1157
'안드로이드 자바' 카테고리의 다른 글
[Java][Android] Swipe Refresh 레이아웃 적용 (0) | 2021.04.12 |
---|---|
[Java][Android] 모바일 네트워크 연결 상태 확인 (0) | 2021.04.10 |
[Java][Android] 주소검색 API(kakao) 이용하기 (3) | 2021.04.05 |
[Java][Android] 마이크 녹음(record) 기능 구현하기 (0) | 2021.04.04 |
[Java][Android] 정규표현식 알아보기 (0) | 2021.04.02 |