안드로이드 데이터 저장: SharedPreferences와 Room 🗄️📱
안드로이드 앱 개발에서 데이터 저장은 핵심적인 부분입니다. 사용자 설정, 게임 점수, 캐시된 네트워크 응답 등 다양한 종류의 데이터를 효율적으로 관리해야 하죠. 이를 위해 안드로이드는 여러 가지 데이터 저장 옵션을 제공하는데, 그 중에서도 SharedPreferences와 Room은 가장 널리 사용되는 두 가지 방식입니다.
이 글에서는 SharedPreferences와 Room에 대해 깊이 있게 살펴보겠습니다. 각각의 특징, 사용 방법, 장단점을 비교하고, 실제 프로젝트에서 어떻게 활용할 수 있는지 상세히 알아볼 것입니다. 또한, 성능 최적화 팁과 보안 고려사항도 다룰 예정이니, 안드로이드 개발자 여러분께 실질적인 도움이 될 것입니다.
재능넷(https://www.jaenung.net)과 같은 플랫폼에서 안드로이드 앱 개발 재능을 공유하고 계신다면, 이 글을 통해 얻은 지식으로 더 효율적이고 안정적인 앱을 만드는 데 도움을 받으실 수 있을 것입니다. 그럼 지금부터 안드로이드의 데이터 저장 세계로 깊이 들어가 보겠습니다! 🚀
1. SharedPreferences 개요 🔑
SharedPreferences는 안드로이드에서 제공하는 가장 간단한 형태의 데이터 저장 방식입니다. 키-값 쌍으로 구성된 작은 데이터를 저장하고 검색하는 데 적합합니다.
1.1 SharedPreferences의 특징
- 간단한 키-값 쌍 저장 방식
- XML 파일 형태로 데이터 저장
- 앱의 private 디렉토리에 저장되어 보안성 확보
- 비동기적 읽기/쓰기 지원
- 프리미티브 타입(int, long, float, boolean, String) 저장 가능
1.2 SharedPreferences 사용 시나리오
- 사용자 설정 저장 (예: 다크 모드 설정, 알림 설정)
- 로그인 상태 유지
- 앱 최초 실행 여부 확인
- 간단한 캐시 데이터 저장
1.3 SharedPreferences의 장단점
장점:
- 사용이 간단하고 직관적
- 작은 데이터 세트에 대해 빠른 읽기/쓰기 성능
- 안드로이드 프레임워크에 내장되어 있어 추가 라이브러리 불필요
단점:
- 복잡한 데이터 구조 저장에 부적합
- 대용량 데이터 처리 시 성능 저하
- 트랜잭션 지원 부족
이제 SharedPreferences의 기본적인 개념을 이해했으니, 다음 섹션에서는 실제 사용 방법과 고급 기술에 대해 자세히 알아보겠습니다. 🧠💡
2. SharedPreferences 사용 방법 🛠️
SharedPreferences를 사용하는 방법은 크게 데이터 저장(쓰기)과 데이터 검색(읽기)으로 나눌 수 있습니다. 각각의 과정을 상세히 살펴보겠습니다.
2.1 SharedPreferences 인스턴스 얻기
SharedPreferences를 사용하기 위해서는 먼저 SharedPreferences 객체를 얻어야 합니다. 이를 위해 두 가지 방법이 있습니다:
// 방법 1: getSharedPreferences() 사용
SharedPreferences sharedPref = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
// 방법 2: getPreferences() 사용 (Activity 내에서만 사용 가능)
SharedPreferences sharedPref = getPreferences(Context.MODE_PRIVATE);
2.2 데이터 저장 (쓰기)
데이터를 저장하기 위해서는 SharedPreferences.Editor 객체를 사용합니다:
SharedPreferences sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("username", "JohnDoe");
editor.putInt("age", 30);
editor.putBoolean("isLoggedIn", true);
// 변경사항 저장
editor.apply(); // 비동기적 저장
// 또는
editor.commit(); // 동기적 저장
2.3 데이터 검색 (읽기)
저장된 데이터를 읽어오는 방법은 다음과 같습니다:
SharedPreferences sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
String username = sharedPref.getString("username", ""); // 기본값: ""
int age = sharedPref.getInt("age", 0); // 기본값: 0
boolean isLoggedIn = sharedPref.getBoolean("isLoggedIn", false); // 기본값: false
2.4 데이터 삭제
특정 키의 데이터를 삭제하거나 모든 데이터를 지우는 방법은 다음과 같습니다:
SharedPreferences.Editor editor = sharedPref.edit();
// 특정 키 삭제
editor.remove("username");
// 모든 데이터 삭제
editor.clear();
editor.apply();
2.5 SharedPreferences 사용 시 주의사항
- apply() vs commit(): apply()는 비동기적으로 동작하여 UI 스레드를 차단하지 않지만, commit()은 동기적으로 동작하여 저장 완료를 보장합니다. 대부분의 경우 apply()를 사용하는 것이 좋습니다.
- 타입 안전성: SharedPreferences는 타입 안전성을 보장하지 않습니다. 잘못된 타입으로 데이터를 읽으려 하면 ClassCastException이 발생할 수 있으므로 주의해야 합니다.
- 대용량 데이터 저장 지양: SharedPreferences는 작은 데이터 세트에 최적화되어 있습니다. 대용량 데이터나 복잡한 객체를 저장할 때는 다른 방법(예: Room)을 고려해야 합니다.
- 키 관리: 키 이름을 상수로 관리하여 오타로 인한 오류를 방지하고 코드의 가독성을 높이는 것이 좋습니다.
이제 SharedPreferences의 기본적인 사용법을 익혔습니다. 다음 섹션에서는 SharedPreferences를 더 효율적으로 사용하기 위한 고급 기술과 패턴에 대해 알아보겠습니다. 계속해서 안드로이드 데이터 저장의 세계를 탐험해 봅시다! 🕵️♂️🔍
3. SharedPreferences 고급 기술 및 패턴 🚀
SharedPreferences를 더욱 효과적으로 사용하기 위한 고급 기술과 패턴들을 살펴보겠습니다. 이를 통해 코드의 품질을 높이고, 유지보수성을 개선할 수 있습니다.
3.1 싱글톤 패턴 적용
SharedPreferences 인스턴스를 싱글톤으로 관리하면 메모리 사용을 최적화하고 일관된 접근을 보장할 수 있습니다.
public class PreferenceManager {
private static PreferenceManager instance;
private SharedPreferences sharedPreferences;
private PreferenceManager(Context context) {
sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);
}
public static synchronized PreferenceManager getInstance(Context context) {
if (instance == null) {
instance = new PreferenceManager(context.getApplicationContext());
}
return instance;
}
public void setString(String key, String value) {
sharedPreferences.edit().putString(key, value).apply();
}
public String getString(String key, String defaultValue) {
return sharedPreferences.getString(key, defaultValue);
}
// 다른 타입에 대한 메서드도 유사하게 구현
}
3.2 암호화 적용
민감한 정보를 저장할 때는 암호화를 적용하는 것이 좋습니다. Android Keystore System과 함께 AES 암호화를 사용할 수 있습니다.
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import java.security.KeyStore;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import android.util.Base64;
public class EncryptedPreferences {
private static final String TRANSFORMATION = "AES/GCM/NoPadding";
private static final String ANDROID_KEYSTORE = "AndroidKeyStore";
private static final String ALIAS = "MyKeyAlias";
private SecretKey secretKey;
private Cipher cipher;
public EncryptedPreferences() throws Exception {
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
if (!keyStore.containsAlias(ALIAS)) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEYSTORE);
keyGenerator.init(new KeyGenParameterSpec.Builder(ALIAS,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build());
secretKey = keyGenerator.generateKey();
} else {
secretKey = (SecretKey) keyStore.getKey(ALIAS, null);
}
cipher = Cipher.getInstance(TRANSFORMATION);
}
public String encrypt(String plaintext) throws Exception {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes("UTF-8"));
String encryptedBase64 = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
String iv = Base64.encodeToString(cipher.getIV(), Base64.DEFAULT);
return encryptedBase64 + ":" + iv;
}
public String decrypt(String encryptedData) throws Exception {
String[] parts = encryptedData.split(":");
byte[] encryptedBytes = Base64.decode(parts[0], Base64.DEFAULT);
byte[] iv = Base64.decode(parts[1], Base64.DEFAULT);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, iv));
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, "UTF-8");
}
}
3.3 리액티브 프로그래밍 적용
RxJava나 Kotlin Flow를 사용하여 SharedPreferences의 변경사항을 관찰할 수 있습니다. 이를 통해 반응형 UI 업데이트를 구현할 수 있습니다.
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.subjects.BehaviorSubject;
public class RxPreferences {
private SharedPreferences preferences;
private Map<string behaviorsubject>> subjects = new HashMap<>();
public RxPreferences(SharedPreferences preferences) {
this.preferences = preferences;
preferences.registerOnSharedPreferenceChangeListener(this::onPreferenceChanged);
}
private void onPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (subjects.containsKey(key)) {
subjects.get(key).onNext(sharedPreferences.getAll().get(key));
}
}
public Observable<string> observeString(String key, String defaultValue) {
return getSubject(key, defaultValue).map(Object::toString);
}
private BehaviorSubject<object> getSubject(String key, Object defaultValue) {
if (!subjects.containsKey(key)) {
Object value = preferences.getAll().get(key);
BehaviorSubject<object> subject = BehaviorSubject.createDefault(value != null ? value : defaultValue);
subjects.put(key, subject);
}
return subjects.get(key);
}
// 다른 타입에 대한 메서드도 유사하게 구현
}
</object></object></string></string>
3.4 타입 안전성 개선
Kotlin의 위임 속성(Delegated Properties)을 사용하여 타입 안전성을 개선할 수 있습니다.
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class TypeSafePreferences(private val preferences: SharedPreferences) {
var username by StringPreference(preferences, "username", "")
var age by IntPreference(preferences, "age", 0)
var isLoggedIn by BooleanPreference(preferences, "isLoggedIn", false)
}
class StringPreference(
private val preferences: SharedPreferences,
private val name: String,
private val defaultValue: String
) : ReadWriteProperty<any string> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return preferences.getString(name, defaultValue) ?: defaultValue
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
preferences.edit().putString(name, value).apply()
}
}
// IntPreference와 BooleanPreference도 유사하게 구현
</any>
3.5 마이그레이션 전략
앱 업데이트 시 SharedPreferences의 구조가 변경될 경우, 마이그레이션 전략이 필요합니다.
public class PreferenceMigration {
private static final String PREF_VERSION_KEY = "pref_version";
private static final int CURRENT_VERSION = 2;
public static void migrateIfNeeded(SharedPreferences preferences) {
int savedVersion = preferences.getInt(PREF_VERSION_KEY, 0);
if (savedVersion < CURRENT_VERSION) {
SharedPreferences.Editor editor = preferences.edit();
if (savedVersion < 1) {
migrateToVersion1(preferences, editor);
}
if (savedVersion < 2) {
migrateToVersion2(preferences, editor);
}
editor.putInt(PREF_VERSION_KEY, CURRENT_VERSION);
editor.apply();
}
}
private static void migrateToVersion1(SharedPreferences preferences, SharedPreferences.Editor editor) {
// 버전 1로의 마이그레이션 로직
}
private static void migrateToVersion2(SharedPreferences preferences, SharedPreferences.Editor editor) {
// 버전 2로의 마이그레이션 로직
}
}
이러한 고급 기술과 패턴들을 적용하면 SharedPreferences를 더욱 강력하고 안전하게 사용할 수 있습니다. 다음 섹션에서는 SharedPreferences의 성능 최적화와 보안에 대해 더 자세히 알아보겠습니다. 계속해서 안드로이드 데이터 저장의 깊이 있는 세계를 탐험해 봅시다! 💡🔒
4. SharedPreferences 성능 최적화 및 보안 🛡️
SharedPreferences는 간단하고 효율적인 데이터 저장 방식이지만, 대규모 앱에서는 성능 이슈가 발생할 수 있습니다. 또한, 민감한 정보를 저장할 때는 보안에 각별히 신경 써야 합니다. 이 섹션에서는 SharedPreferences의 성능을 최적화하고 보안을 강화하는 방법에 대해 알아보겠습니다.
4.1 성능 최적화
1. 불필요한 commit() 호출 줄이기
commit()은 동기적으로 동작하여 메인 스레드를 차단할 수 있습니다. 가능한 한 apply()를 사용하고, 여러 변경사항을 한 번에 적용하세요.
// 비효율적인 방법
editor.putString("key1", "value1").commit();
editor.putString("key2", "value2").commit();
editor.putString("key3", "value3").commit();
// 효율적인 방법
editor.putString("key1", "value1");
editor.putString("key2", "value2");
editor.putString("key3", "value3");
editor.apply();
2. 대량의 데이터 처리 최적화
대량의 데이터를 처리할 때는 트랜잭션 패턴을 사용하여 성능을 향상시킬 수 있습니다.
public void applyBatchUpdates(Map<string> updates) {
SharedPreferences.Editor editor = sharedPreferences.edit();
for (Map.Entry<string> entry : updates.entrySet()) {
if (entry.getValue() instanceof String) {
editor.putString(entry.getKey(), (String) entry.getValue());
} else if (entry.getValue() instanceof Integer) {
editor.putInt(entry.getKey(), (Integer) entry.getValue());
}
// 다른 타입에 대해서도 유사하게 처리
}
editor.apply();
}
</string></string>
3. 백그라운드 스레드 활용
대량의 데이터를 읽거나 쓸 때는 백그라운드 스레드를 활용하여 메인 스레드의 부하를 줄이세요.
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
Map<string> allEntries = sharedPreferences.getAll();
// 데이터 처리 로직
runOnUiThread(() -> {
// UI 업데이트
});
});
</string>
4. 캐싱 전략 사용
자주 접근하는 값들은 메모리에 캐싱하여 디스크 I/O를 줄일 수 있습니다.
public class CachedPreferences {
private final SharedPreferences preferences;
private final Map<string object> cache = new ConcurrentHashMap<>();
public CachedPreferences(SharedPreferences preferences) {
this.preferences = preferences;
}
public String getString(String key , String defaultValue) {
if (cache.containsKey(key)) {
return (String) cache.get(key);
}
String value = preferences.getString(key, defaultValue);
cache.put(key, value);
return value;
}
public void putString(String key, String value) {
preferences.edit().putString(key, value).apply();
cache.put(key, value);
}
// 다른 타입에 대해서도 유사하게 구현
}
</string>
4.2 보안 강화
1. 암호화 사용
민감한 정보를 저장할 때는 반드시 암호화를 사용해야 합니다. 앞서 소개한 EncryptedPreferences 클래스를 활용할 수 있습니다.
2. Android Keystore System 활용
암호화 키를 안전하게 저장하기 위해 Android Keystore System을 사용하세요. 이는 하드웨어 수준의 보안을 제공합니다.
private SecretKey getOrCreateSecretKey(String keyAlias) throws Exception {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
if (!keyStore.containsAlias(keyAlias)) {
KeyGenerator keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
keyGenerator.init(new KeyGenParameterSpec.Builder(keyAlias,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(false)
.setRandomizedEncryptionRequired(true)
.build());
return keyGenerator.generateKey();
} else {
return (SecretKey) keyStore.getKey(keyAlias, null);
}
}
3. 최소 권한 원칙 적용
SharedPreferences 파일의 권한을 최소화하여 다른 앱에서의 접근을 방지합니다.
SharedPreferences sharedPreferences = context.getSharedPreferences(
"SecurePreferences", Context.MODE_PRIVATE);
4. 민감한 정보 관리
가능한 한 민감한 정보(예: 암호, 토큰)를 SharedPreferences에 저장하지 마세요. 대신 Android Keystore나 더 안전한 저장소를 사용하세요.
5. 데이터 유효성 검사
저장된 데이터를 읽을 때 항상 유효성을 검사하여 데이터 변조를 방지합니다.
public String getValidatedString(String key, String defaultValue) {
String value = sharedPreferences.getString(key, defaultValue);
if (isValid(value)) {
return value;
} else {
// 로그 기록 또는 오류 처리
return defaultValue;
}
}
private boolean isValid(String value) {
// 유효성 검사 로직 구현
return value != null && value.length() > 0 && value.length() < 100;
}
이러한 성능 최적화 및 보안 강화 기법을 적용하면 SharedPreferences를 더욱 안전하고 효율적으로 사용할 수 있습니다. 하지만 대규모 데이터나 복잡한 관계를 가진 데이터를 다룰 때는 Room과 같은 더 강력한 데이터베이스 솔루션을 고려해야 합니다.
다음 섹션에서는 Room에 대해 자세히 알아보고, SharedPreferences와 Room을 비교하여 각각의 사용 사례를 살펴보겠습니다. 안드로이드 데이터 저장의 여정을 계속 이어가 봅시다! 🚀📊
5. Room 데이터베이스 소개 🏠
Room은 안드로이드의 Jetpack 라이브러리 중 하나로, SQLite 데이터베이스를 더 쉽고 효율적으로 사용할 수 있게 해주는 ORM(Object-Relational Mapping) 라이브러리입니다. Room은 데이터베이스 작업을 추상화하고, 컴파일 시점에 SQL 쿼리의 유효성을 검사하여 런타임 오류를 방지합니다.
5.1 Room의 주요 구성 요소
- Entity: 데이터베이스 테이블을 나타내는 클래스
- DAO (Data Access Object): 데이터베이스 작업을 정의하는 인터페이스
- Database: 데이터베이스 홀더를 포함하고 DAO의 주요 접근점 역할을 하는 추상 클래스
5.2 Room 설정
Room을 사용하기 위해 먼저 프로젝트의 build.gradle 파일에 다음 종속성을 추가해야 합니다:
dependencies {
def room_version = "2.4.3"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
// Kotlin 사용 시
kapt "androidx.room:room-compiler:$room_version"
// 코루틴 지원을 위해
implementation "androidx.room:room-ktx:$room_version"
}
5.3 Room 사용 예제
간단한 사용자 정보를 저장하는 Room 데이터베이스를 구현해 보겠습니다.
1. Entity 정의
@Entity(tableName = "users")
data class User(
@PrimaryKey val id: Int,
@ColumnInfo(name = "name") val name: String,
@ColumnInfo(name = "email") val email: String
)
2. DAO 정의
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAll(): List<user>
@Query("SELECT * FROM users WHERE id IN (:userIds)")
fun loadAllByIds(userIds: IntArray): List<user>
@Query("SELECT * FROM users WHERE name LIKE :name LIMIT 1")
fun findByName(name: String): User
@Insert
fun insertAll(vararg users: User)
@Delete
fun delete(user: User)
}
</user></user>
3. Database 클래스 정의
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
private var instance: AppDatabase? = null
fun getInstance(context: Context): AppDatabase {
return instance ?: synchronized(this) {
instance ?: buildDatabase(context).also { instance = it }
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"app_database"
).build()
}
}
}
4. Room 데이터베이스 사용
class UserRepository(private val userDao: UserDao) {
suspend fun insertUser(user: User) {
userDao.insertAll(user)
}
suspend fun getAllUsers(): List<user> {
return userDao.getAll()
}
}
class UserViewModel(application: Application) : AndroidViewModel(application) {
private val repository: UserRepository
init {
val userDao = AppDatabase.getInstance(application).userDao()
repository = UserRepository(userDao)
}
suspend fun insertUser(user: User) {
repository.insertUser(user)
}
suspend fun getAllUsers(): List<user> {
return repository.getAllUsers()
}
}
</user></user>
Room은 복잡한 데이터 구조와 관계를 효율적으로 관리할 수 있게 해주며, 대규모 데이터셋을 다루는 데 적합합니다. 또한 비동기 쿼리, 데이터 변경 관찰, 데이터 마이그레이션 등 다양한 기능을 제공하여 안드로이드 앱의 데이터 관리를 크게 개선합니다.
다음 섹션에서는 SharedPreferences와 Room을 비교하고, 각각의 사용 사례를 살펴보겠습니다. 안드로이드 데이터 저장의 세계를 더욱 깊이 탐험해 봅시다! 🌟📊
6. SharedPreferences vs Room: 비교 및 사용 사례 🔍
SharedPreferences와 Room은 모두 안드로이드에서 데이터를 저장하는 방법이지만, 각각의 특징과 장단점이 있습니다. 이 섹션에서는 두 방식을 비교하고 적절한 사용 사례를 살펴보겠습니다.
6.1 특징 비교
특징 | SharedPreferences | Room |
---|---|---|
데이터 구조 | 키-값 쌍 | 관계형 테이블 |
데이터 타입 | 기본 타입 (int, long, float, boolean, String) | 모든 자바/코틀린 객체 |
쿼리 기능 | 제한적 (키를 통한 직접 접근) | 강력한 SQL 쿼리 지원 |
성능 | 소량의 데이터에 최적화 | 대량의 데이터 처리에 효율적 |
동시성 처리 | 기본적인 지원 (apply() 메서드) | 강력한 동시성 지원 |
데이터 변경 관찰 | 제한적 (OnSharedPreferenceChangeListener) | LiveData, Flow 등과 통합 가능 |
설정 복잡도 | 간단함 | 상대적으로 복잡함 |
6.2 사용 사례
SharedPreferences 사용이 적합한 경우:
- 사용자 설정 저장 (예: 테마 설정, 알림 설정)
- 로그인 상태나 세션 정보 유지
- 앱의 첫 실행 여부 확인
- 간단한 플래그 또는 카운터 저장
- 소량의 구조화되지 않은 데이터 저장
Room 사용이 적합한 경우:
- 복잡한 데이터 구조 저장 (예: 사용자 프로필, 게시물, 댓글)
- 대량의 데이터 처리 (예: 채팅 메시지, 로그 데이터)
- 데이터 간의 관계 관리가 필요한 경우
- 복잡한 쿼리가 필요한 경우 (예: 필터링, 정렬, 집계)
- 데이터의 일관성과 무결성이 중요한 경우
6.3 선택 기준
- 데이터의 복잡성: 데이터 구조가 복잡하고 관계가 있다면 Room을 선택하세요.
- 데이터의 양: 대량의 데이터를 다루어야 한다면 Room이 더 적합합니다.
- 쿼리 요구사항: 복잡한 쿼리가 필요하다면 Room을 사용하세요.
- 성능 요구사항: 대규모 데이터 처리에서는 Room이 더 나은 성능을 제공합니다.
- 개발 시간: 빠른 구현이 필요하고 데이터가 단순하다면 SharedPreferences가 좋은 선택일 수 있습니다.
- 앱의 복잡성: 간단한 앱이라면 SharedPreferences로 충분할 수 있지만, 복잡한 앱에서는 Room의 기능이 유용합니다.
결론적으로, SharedPreferences와 Room은 각각의 장단점과 적합한 사용 사례가 있습니다. 앱의 요구사항을 신중히 고려하여 적절한 데이터 저장 방식을 선택하는 것이 중요합니다. 때로는 두 방식을 함께 사용하는 것도 좋은 전략이 될 수 있습니다. 예를 들어, 간단한 설정은 SharedPreferences에 저장하고, 복잡한 사용자 데이터는 Room에 저장하는 방식으로 말이죠.
다음 섹션에서는 실제 프로젝트에서 SharedPreferences와 Room을 효과적으로 사용하는 방법과 베스트 프랙티스에 대해 알아보겠습니다. 안드로이드 데이터 저장의 마스터가 되는 여정을 계속해봅시다! 🚀💾