Flutter

SharedPreferences

조충희 2025. 8. 13. 12:39

Flutter 앱에서 가볍고 간단한 데이터를 영구적으로 저장

앱의 개인 메모장
키-값으로 데이터 저장
사용자 경험 크게 향상
비동기(Asynchronous) 프로그래밍
Null Safety와 기본값 설정

사용하는 법

shared_preferences: ^2.5.3
import 'package:shared_preferences/shared_preferences.dart';

 

예제)

버튼을 누르면 카운터에 변수 반영

저장하면 현재 카운터값이 영구저장
영구저장값은 앱 실행시, 새로고침 클릭시 호출
삭제를 클릭하면 영구저장값 삭제

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  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(
      title: 'SharedPreferences 예제',
      debugShowCheckedModeBanner: false,
      home: CountStorage(),
    );
  }
}

class CountStorage extends StatefulWidget {
  const CountStorage({super.key});

  @override
  State<CountStorage> createState() => _CountStorageState();
}

class _CountStorageState extends State<CountStorage> {
  int _counter = 0;
  final String _counterKey = 'count_value';

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('예제 학습'),
        backgroundColor: Colors.orange[300],
        foregroundColor: Colors.white,
        actions: [
          IconButton(
            onPressed: _loadData,
            icon: Icon(Icons.refresh),
            tooltip: '데이터 새로고침',
          ),
          IconButton(
            onPressed: _deleteCounter,
            icon: Icon(Icons.delete_forever),
            tooltip: '모든 데이터 삭제',
          ),
        ],
      ),
      body: _buildBody(),
      bottomNavigationBar: Container(
        padding: EdgeInsets.all(16),
        color: Colors.green[400],
        child: Text(
          textAlign: TextAlign.center,
          '팁: 앱을 종료한뒤 다시 실행해보세요\n 저장한 값이 그대로 남게 됩니다',
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),
      ),
    );
  }

  Column _buildBody() {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Card(
          color: Colors.blue[100],
          child: Column(
            children: [
              const SizedBox(height: 16),
              Text(
                '카운터',
                style: TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                ),
              ),
              Container(
                width: 100,
                height: 100,
                decoration: BoxDecoration(
                  color: Colors.orange[100],
                  shape: BoxShape.circle,
                ),
                child: Center(
                  child: Text(
                    '${_counter}',
                    style: TextStyle(
                      fontSize: 32,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
              const SizedBox(height: 16),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  ElevatedButton(
                    onPressed: () {
                      setState(() {
                        if (_counter > 0) {
                          _counter -= 1;
                        }
                      });
                    },
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.red[300],
                    ),
                    child: Text(
                      '-1',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      setState(() {
                        _counter += 1;
                      });
                    },
                    style: ElevatedButton.styleFrom(
                      backgroundColor: Colors.blue[300],
                    ),
                    child: Text(
                      '+1',
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 16),
              Container(
                padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12),
                width: double.infinity,
                child: ElevatedButton.icon(
                  onPressed: _saveCounter,
                  label: Text('저장하기'),
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.green,
                    foregroundColor: Colors.white,
                  ),
                ),
              ),
            ],
          ),
        )
      ],
    );
  }

  //SharedPreference는 비동기로 동작한다
  Future<void> _saveCounter() async {
    try {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      //현재 카운터 값 저장 (await: 응답 올때까지 기다려)
      bool success = await prefs.setInt(_counterKey, _counter);
      if (success) {
        print('카운터 값 저장 성공: $_counter');
        _showMessage('카운터 값이 저장됐습니다');
      } else {
        _showMessage('카운터 값 저장중 오류발생');
      }
    } catch (e) {
      _showMessage('카운터 값 저장중 오류발생');
    }
  }

  //카운터값 날리기
  Future<void> _deleteCounter() async {
    try {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      bool success = await prefs.remove(_counterKey); // 특정 키 데이터 삭제
      if (success) {
        setState(() {
          _counter = 0; // UI 값도 바로 초기화
        });
        print('카운터 값 삭제 성공');
        _showMessage('카운터 값이 삭제됐습니다');
      } else {
        _showMessage('카운터 값 삭제 중 오류 발생');
      }
    } catch (e) {
      _showMessage('카운터 값 삭제 중 오류 발생');
    }
  }

  Future<void> _loadData() async {
    try {
      SharedPreferences prefs = await SharedPreferences.getInstance();

      final int savedCounter = prefs.getInt(_counterKey) ?? 0;
      setState(() {
        _counter = savedCounter;
      });
    } catch (e) {
      _showMessage('카운터 값 저장중 오류발생');
    }
  }

//사용자에게 메시지 보여주기
  void _showMessage(String message) {
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      content: Text(message),
      duration: const Duration(seconds: 2),
    ));
  }
} //end