320x100
Room 사용을 배제한 rawQuery()를 이용하여 SQL을 직접 작성해서 사용하는 방식으로 코드 구현한 내용을 정리해 봅니다.
옛날 프로젝트는 이런 환경에서 개발했기 때문에 별도 정리해 봅니다.
1. SQLiteOpenHelper 설정
먼저, SQLiteOpenHelper 클래스를 설정합니다.
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "mydatabase.db";
private static final int DATABASE_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE my_table (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, " +
"age INTEGER)";
db.execSQL(createTable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS my_table");
onCreate(db);
}
}
2. 데이터 삽입
데이터를 삽입하는 메서드를 작성합니다.
import android.content.ContentValues;
import android.database.sqlite.SQLiteDatabase;
public void insertData(String name, int age) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
db.insert("my_table", null, values);
}
3. 페이징 데이터 조회 (rawQuery 사용)
페이징을 적용하여 데이터를 조회하는 메서드를 작성합니다.
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public Cursor getPagedData(int offset, int limit) {
SQLiteDatabase db = getReadableDatabase();
String query = "SELECT * FROM my_table LIMIT ? OFFSET ?";
Cursor cursor = db.rawQuery(query, new String[]{String.valueOf(limit), String.valueOf(offset)});
return cursor;
}
4. RecyclerView 어댑터 설정
RecyclerView 어댑터를 설정합니다.
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<MyData> dataList;
private Context context;
public MyAdapter(Context context) {
this.context = context;
this.dataList = new ArrayList<>();
}
public void addData(List<MyData> data) {
int startPosition = dataList.size();
dataList.addAll(data);
notifyItemRangeInserted(startPosition, data.size());
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
MyData data = dataList.get(position);
holder.nameTextView.setText(data.getName());
holder.ageTextView.setText(String.valueOf(data.getAge()));
}
@Override
public int getItemCount() {
return dataList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView nameTextView, ageTextView;
ViewHolder(View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.nameTextView);
ageTextView = itemView.findViewById(R.id.ageTextView);
}
}
}
5. MainActivity에서 페이징 설정
MainActivity에서 페이징을 설정하고 데이터를 로드합니다.
import android.database.Cursor;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
private MyAdapter adapter;
private RecyclerView recyclerView;
private boolean isLoading = false;
private int currentPage = 0;
private static final int PAGE_SIZE = 20;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this);
adapter = new MyAdapter(this);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
// 데이터 삽입 (테스트용)
for (int i = 1; i <= 1000; i++) {
dbHelper.insertData("Name " + i, 20 + (i % 10));
}
loadMoreData();
// 스크롤 리스너 설정
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!isLoading && layoutManager != null && layoutManager.findLastCompletelyVisibleItemPosition() == adapter.getItemCount() - 1) {
// 리스트의 끝에 도달했을 때 더 많은 데이터 로드
loadMoreData();
}
}
});
}
private void loadMoreData() {
isLoading = true;
int offset = currentPage * PAGE_SIZE;
Cursor cursor = dbHelper.getPagedData(offset, PAGE_SIZE);
List<MyData> data = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndexOrThrow("id"));
String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));
int age = cursor.getInt(cursor.getColumnIndexOrThrow("age"));
data.add(new MyData(id, name, age));
} while (cursor.moveToNext());
}
cursor.close();
adapter.addData(data);
isLoading = false;
currentPage++;
}
}
6. 데이터 모델 클래스
MyData 클래스를 정의합니다.
public class MyData {
private int id;
private String name;
private int age;
public MyData(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
7. XML 레이아웃 파일
activity_main.xml
MainActivity의 레이아웃 파일을 작성합니다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:scrollbars="vertical" />
</RelativeLayout>
item_layout.xml
RecyclerView의 각 아이템 레이아웃 파일을 작성합니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="@android:color/black" />
<TextView
android:id="@+id/ageTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/darker_gray" />
</LinearLayout>
8. 최종 코드 구조
이제 모든 코드를 종합하여 최종 구조를 확인해보겠습니다.
- MyDatabaseHelper.java
- MainActivity.java
- MyAdapter.java
- MyData.java
- activity_main.xml
- item_layout.xml
모든 코드를 종합하면 다음과 같습니다.
MyDatabaseHelper.java
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "mydatabase.db";
private static final int DATABASE_VERSION = 1;
public MyDatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE my_table (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
"name TEXT, " +
"age INTEGER)";
db.execSQL(createTable);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS my_table");
onCreate(db);
}
public void insertData(String name, int age) {
SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
db.insert("my_table", null, values);
}
public Cursor getPagedData(int offset, int limit) {
SQLiteDatabase db = getReadableDatabase();
String query = "SELECT * FROM my_table LIMIT ? OFFSET ?";
Cursor cursor = db.rawQuery(query, new String[]{String.valueOf(limit), String.valueOf(offset)});
return cursor;
}
}
MainActivity.java
import android.database.Cursor;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private MyDatabaseHelper dbHelper;
private MyAdapter adapter;
private RecyclerView recyclerView;
private boolean isLoading = false;
private int currentPage = 0;
private static final int PAGE_SIZE = 20;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dbHelper = new MyDatabaseHelper(this);
adapter = new MyAdapter(this);
recyclerView = findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
// 데이터 삽입 (테스트용)
for (int i = 1; i <= 1000; i++) {
dbHelper.insertData("Name " + i, 20 + (i % 10));
}
loadMoreData();
// 스크롤 리스너 설정
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!isLoading && layoutManager != null && layoutManager.findLastCompletelyVisibleItemPosition() == adapter.getItemCount() - 1) {
// 리스트의 끝에 도달했을 때 더 많은 데이터 로드
loadMoreData();
}
}
});
}
private void loadMoreData() {
isLoading = true;
int offset = currentPage * PAGE_SIZE;
Cursor cursor = dbHelper.getPagedData(offset, PAGE_SIZE);
List<MyData> data = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
int id = cursor.getInt(cursor.getColumnIndexOrThrow("id"));
String name = cursor.getString(cursor.getColumnIndexOrThrow("name"));
int age = cursor.getInt(cursor.getColumnIndexOrThrow("age"));
data.add(new MyData(id, name, age));
} while (cursor.moveToNext());
}
cursor.close();
adapter.addData(data);
isLoading = false;
currentPage++;
}
}
MyAdapter.java
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private List<MyData> dataList;
private LayoutInflater inflater;
public MyAdapter(Context context) {
this.dataList = new ArrayList<>();
this.inflater = LayoutInflater.from(context);
}
public void addData(List<MyData> newData) {
int startPosition = dataList.size();
dataList.addAll(newData);
notifyItemRangeInserted(startPosition, newData.size());
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.item_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
MyData data = dataList.get(position);
holder.nameTextView.setText(data.getName());
holder.ageTextView.setText(String.valueOf(data.getAge()));
}
@Override
public int getItemCount() {
return dataList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView nameTextView;
TextView ageTextView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
nameTextView = itemView.findViewById(R.id.nameTextView);
ageTextView = itemView.findViewById(R.id.ageTextView);
}
}
}
이제 모든 파일이 준비되었습니다. 요약하면, 각 파일의 역할은 다음과 같습니다:
- MyDatabaseHelper.java: 데이터베이스 생성, 데이터 삽입, 페이징된 데이터 가져오기.
- MainActivity.java: RecyclerView 설정 및 데이터 로드 관리.
- MyAdapter.java: RecyclerView 어댑터로서 데이터를 표시.
- MyData.java: 데이터 모델 클래스.
- activity_main.xml: MainActivity의 레이아웃 파일.
- item_layout.xml: RecyclerView의 각 아이템 레이아웃 파일.
이제 이 코드를 실행하면 데이터베이스에서 페이징을 통해 데이터를 로드하고 RecyclerView에 표시할 수 있습니다.
반응형
'개발 이야기 > Android (안드로이드)' 카테고리의 다른 글
Jetpack Compose 초보자 가이드 (0) | 2024.12.23 |
---|---|
Android DataBinding과 ViewModel 적용하기 (6) | 2024.12.12 |
Fragment 효율적인 코딩 방법에 대한 정리 (0) | 2024.12.12 |
Java8 Stream API 찍먹하기 (2) | 2024.12.11 |
Android App 개발에 많이 사용하는 디자인패턴 (0) | 2024.06.04 |
Android | Java | 특정 소수점까지 잘라서 계산 후 반올림 하기 (0) | 2024.01.31 |
Android | 앱 화면 구성 중에 DB에서 Data 읽어올때 코딩 가이드 (0) | 2023.12.28 |
Android | 스마트폰 설치한 앱의 APK 추출방법 (0) | 2023.12.13 |