https://pub.dev/packages/shared_preferences
shared_preferences는 Flutter 개발에서 로컬 데이터를 간편하게 저장하고 검색할 수 있도록 도와주는 패키지 중 하나입니다. 이 패키지는 앱의 설정, 상태 유지, 사용자 기본 설정 등을 저장하고 관리할 때 유용합니다. 주로 간단한 키-값 쌍의 데이터를 저장하는 데 사용됩니다.
사용 이유
쉬운 로컬 데이터 저장: shared_preferences를 사용하면 SQLite 또는 파일 시스템과 같은 복잡한 저장소를 구현하지 않고도 간단하게 로컬 데이터를 저장할 수 있습니다.
앱 설정 관리: 앱 설정이나 사용자의 환경 설정과 같은 간단한 정보를 로컬에 저장할 수 있습니다.
앱 상태 유지: 사용자가 앱을 종료하고 다시 실행할 때 이전 상태를 복원하기 위해 사용됩니다.
주의할 점
SharedPreferences는 간단한 로컬 데이터 저장 용도로 사용되지만, 보안적인 이슈가 있는 중요한 데이터나 사용자 인증 토큰과 같은 항목을 저장하기에는 적합하지 않습니다. 민감한 정보는 flutter_secure_storage과 같은 패키지를 사용하여야 합니다.
사용해 보기
https://pub.dev/packages/shared_preferences/install
pubspec.yaml파일에 해당 패키지를 설치하고 Pub get 해주세요.
WirteData
shared_preferences에 저장할 수 있는 자료형은 int, bool, double, String, List <String> 총 5개를 저장할 수 있습니다.
Key-Value 형태로 저장이 가능하고 저장할 형태에 따라서 int형 이면 setInt, bool형이면 setBool.. 이런 식으로 가져온 shared_preferences의 메서드로 write저장할 수 있습니다.
// SharedPreferences 인스턴스를 받아옵니다.
final SharedPreferences prefs = await SharedPreferences.getInstance();
// key - value 형태로 저장
// 'counter' key로 int 10 저장
await prefs.setInt('counter', 10);
// 'repeat' key로 bool true 저장
await prefs.setBool('repeat', true);
// 'decimal' key로 double 1.5 저장
await prefs.setDouble('decimal', 1.5);
// 'action' key로 String 'Start' 저장
await prefs.setString('action', 'Start');
// 'items' key로 List<String> 저장
await prefs.setStringList('items', <String>['Earth', 'Moon', 'Sun']);
shared_preferences의 인스턴스를 가져올 때 또한 wirte(저장)할 때 await이 붙는다는 것을 보면 비동기로 이루어진다는 것을 알 수 있습니다.
ReadData
write와 동일하게 가지고 올 수 있는 자료형에 따라 getInt, getBool, getDouble 등등 shared_preferences의 인스턴스 메서드를 통해 write로 사용한 key값을 넣으면 해당 key에 저장된 값이 있으면 해당값을 반환하고 없으면 null을 반환합니다.
그냥 get을 하게 되면 타입을 신경 쓰지 않고 해당 key에 값이 있으면 Object형으로 넘겨줍니다. key에 값이 없다면 null을 반환하기에 Object?로 받게 됩니다.
// SharedPreferences 인스턴스를 받아옵니다.
final SharedPreferences prefs = await SharedPreferences.getInstance();
final int? counter = prefs.getInt('counter');
final bool? repeat = prefs.getBool('repeat');
final double? decimal = prefs.getDouble('decimal');
final String? action = prefs.getString('action');
final List<String>? items = prefs.getStringList('items');
final Object? data = prefs.get('items');
주의할 점은 read를 할 때는 write와는 다르게 await을 하지 않습니다. 동기적으로 작업이 이루어진다는 뜻입니다. 그래서 write로 값을 저장할 때 await을 하지 않고 바로 read를 하게 되면 오류가 발생할 수 도 있습니다. 이런 경우에는 write를 할 때 꼭 await를 하도록 해야 합니다.
//set은 비동기, get은 동기 라서
//오류 발생 할 수 있음.
prefs.setInt('counter', 10);
prefs.getInt('counter');
//저장하자마자 값을 read하려면 await을 붙여야한다.
await prefs.setInt('counter', 10);
prefs.getInt('counter');
RemoveData
비동기로 동작하고 해당하는 key의 값을 지웁니다.
// SharedPreferences 인스턴스를 받아옵니다.
final SharedPreferences prefs = await SharedPreferences.getInstance();
// 'counter' key로 저장된 값을 제거합니다.
await prefs.remove('counter');
편하게 사용하기
제가 편하게 사용하기 위해 만든 코드입니다. 사용하실 분은 사용하세요.
class SharedPreferencesService {
static late SharedPreferences _sharedPreferences;
static Future<void> initialize() async {
_sharedPreferences = await SharedPreferences.getInstance();
}
static Future<bool> setData<T>({required String key, T? value}) async {
if (value is int) {
return await _sharedPreferences.setInt(key, value);
}
if (value is bool) {
return await _sharedPreferences.setBool(key, value);
}
if (value is String) {
return await _sharedPreferences.setString(key, value);
}
if (value is double) {
return await _sharedPreferences.setDouble(key, value);
}
if (value is List<String>) {
return await _sharedPreferences.setStringList(key, value);
}
return false;
}
static T? getData<T>({required String key}) {
final data = _sharedPreferences.get(key);
return data as T?;
}
static Future<bool> removeData({required String key}) async {
return await _sharedPreferences.remove(key);
}
}
write, read, remove 등을 작업할 때에 shared_preferences의 인스턴스를 받아와야 하는 번거로움이 있습니다. 여러 곳에서 shared_preferences를 사용한다면 인스턴스도 계속 새로 받아와서 작업해야 합니다. 그리고 set을 할 때 일일이 데이터유형에 맞는 setInt, setBool 등 맞는 메서드를 호출해야 하는 번거로움과 get을 할 때에도 비슷한 번거로움이 발생합니다.
위와 같이 발생하는 번거로움을 해결하기 위해서 SharedPreferencesService의 initialize() 한 번만 호출해 주면 shared_preferences 인스턴스를 SharedPreferencesService의 static 변수에 인스턴스를 저장해두고 있기 때문에 매번 인스턴스를 생성하는 번거로움을 줄였습니다. 그리고 해당 인스턴스를 외부에서 직접 참조하지 않게 하기 위해서 private 하게 선언해 두었습니다. 왜냐하면 우리는 write, read, remove만 사용하면 되거든요!
await SharedPreferencesService.setData(key: 'counter', value: 5);
await SharedPreferencesService.setData(key: 'repeat', value: true);
await SharedPreferencesService.setData(key: 'decimal', value: 1.5);
await SharedPreferencesService.setData(key: 'action', value: "action");
await SharedPreferencesService.setData(key: 'items', value: ["hello", "world"]);
외부 어디에서든 write를 하고 싶으면 이렇게 사용하면 타입에 맞게 setInt, setBool 등등.. 호출되면서 타입에 맞게 저장이 되면서 true를 반환하게 됩니다.
await SharedPreferencesService.setData(key: 'items', value: [true, false]);
만약 이렇게 저장하지 못하는 타입을 넣었을 때는 false를 return 하도록 되어 있습니다.
SharedPreferencesService.getData(key: 'counter');
SharedPreferencesService.getData(key: 'repeat');
SharedPreferencesService.getData(key: 'decimal');
SharedPreferencesService.getData(key: 'action');
SharedPreferencesService.getData(key: 'items');
값을 가져오고 싶을 때는 이렇게 사용하면 됩니다.
await SharedPreferencesService.removeData(key: 'counter');
await SharedPreferencesService.removeData(key: 'repeat');
await SharedPreferencesService.removeData(key: 'decimal');
await SharedPreferencesService.removeData(key: 'action');
await SharedPreferencesService.removeData(key: 'items');
삭제하고 싶을 때는 이렇게 사용하면 됩니다.
주의할 점은 꼭 SharedPreferencesService의 initialize()를 호출해서 인스턴스를 가져오는 작업을 해야 합니다.
예시 사용 코드
코드를 실행시켜 사용법을 익혀보세요!.
void main() async {
//runApp전에 await을 하기 위한 코드
WidgetsFlutterBinding.ensureInitialized();
//필요 초기화 작업 await 사용
await SharedPreferencesService.initialize();
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("read : ${SharedPreferencesService.getData(key: 'data')}"),
SizedBox(height: 30),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
onTap: () async {
await SharedPreferencesService.setData(key: 'data', value: "Hello Jutole");
setState(() {
});
},
child: Container(
width: 60,
height: 50,
color: Colors.red,
alignment: Alignment.center,
child: Text("write"),
),
),
SizedBox(width: 30),
GestureDetector(
onTap: () async {
await SharedPreferencesService.removeData(key: 'data');
setState(() {
});
},
child: Container(
width: 60,
height: 50,
color: Colors.green,
alignment: Alignment.center,
child: Text("remove"),
),
),
],
),
SizedBox(height: 30),
Text("재 시작 해도 값은 유지되어 있어요!"),
],
),
),
),
);
}
}
class SharedPreferencesService {
static late SharedPreferences _sharedPreferences;
static Future<void> initialize() async {
_sharedPreferences = await SharedPreferences.getInstance();
}
static Future<bool> setData<T>({required String key, T? value}) async {
if (value is int) {
return await _sharedPreferences.setInt(key, value);
}
if (value is bool) {
return await _sharedPreferences.setBool(key, value);
}
if (value is String) {
return await _sharedPreferences.setString(key, value);
}
if (value is double) {
return await _sharedPreferences.setDouble(key, value);
}
if (value is List<String>) {
return await _sharedPreferences.setStringList(key, value);
}
return false;
}
static T? getData<T>({required String key}) {
final data = _sharedPreferences.get(key);
return data as T?;
}
static Future<bool> removeData({required String key}) async {
return await _sharedPreferences.remove(key);
}
}
중요한 데이터를 저장할 때는 위의 패키지를 이용해 보세요.
'Flutter > 기본' 카테고리의 다른 글
[Flutter] 프로덕션 환경 vs 개발 환경 구별 방법 (0) | 2024.03.28 |
---|---|
[Flutter] 웹 플랫폼 구별 방법 (0) | 2024.02.13 |
[Flutter] TextScale fix (텍스트 크기 고정) (0) | 2024.01.08 |
[Flutter] Clipboard 사용해서 복사 / 가져오기 (2) | 2024.01.04 |
[Flutter] CustomPaint 디자인 모음 (코드있음) (0) | 2023.12.04 |