본문 바로가기
카테고리 없음

💾 Flutter 로컬 데이터 저장하기 – SharedPreferences로 할 일 저장하기

by holybag 2025. 8. 9.

지금까지 만든 To-do 앱은 앱을 종료하면 데이터가 사라지는 단점이 있었습니다.
이를 해결하기 위해 Flutter에서 가장 간단하게 사용할 수 있는 저장 방법,
바로 SharedPreferences를 사용해봅니다.


🔍 SharedPreferences란?

안드로이드/IOS에서 제공하는 키-값 저장 방식의 간단한 로컬 DB입니다.

  • 앱 내 간단한 설정값, 문자열 리스트 등을 저장할 수 있음
  • 파일 기반으로 동작하며, 앱 삭제 전까지 데이터가 유지됨

🧩 목표 기능

✅ 할 일을 추가하면 로컬에 저장
✅ 앱을 껐다 켜도 목록 유지
✅ 삭제, 체크 등 변경 시에도 자동 저장


📦 SharedPreferences 설치

1️⃣ pubspec.yaml에 패키지 추가

dependencies:
  flutter:
    sdk: flutter
  shared_preferences: ^2.2.2

2️⃣ 설치 명령 실행

flutter pub get

🛠️ 구조 변경 – Map을 JSON으로 변환

SharedPreferences는 단순한 자료형만 저장할 수 있어서
List<Map> → JSON 문자열로 변환해서 저장해야 합니다.

우리는 아래 형태를 사용합니다:

 

List<Map<String, dynamic>> → List<String> (JSON으로 변환)


💻 전체 코드 예제 (로컬 저장 포함)

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

void main() => runApp(MaterialApp(home: TodoStorageApp()));

class TodoStorageApp extends StatefulWidget {
  @override
  _TodoStorageAppState createState() => _TodoStorageAppState();
}

class _TodoStorageAppState extends State<TodoStorageApp> {
  final TextEditingController _controller = TextEditingController();
  List<Map<String, dynamic>> _todoList = [];

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

  // 저장
  Future<void> _saveTodos() async {
    final prefs = await SharedPreferences.getInstance();
    List<String> jsonList =
        _todoList.map((item) => jsonEncode(item)).toList();
    await prefs.setStringList('todos', jsonList);
  }

  // 불러오기
  Future<void> _loadTodos() async {
    final prefs = await SharedPreferences.getInstance();
    List<String>? jsonList = prefs.getStringList('todos');
    if (jsonList != null) {
      setState(() {
        _todoList =
            jsonList.map((item) => jsonDecode(item) as Map<String, dynamic>).toList();
      });
    }
  }

  void _addTodo() {
    String text = _controller.text.trim();
    if (text.isNotEmpty) {
      setState(() {
        _todoList.add({'title': text, 'done': false});
        _controller.clear();
      });
      _saveTodos();
    }
  }

  void _toggleDone(int index) {
    setState(() {
      _todoList[index]['done'] = !_todoList[index]['done'];
    });
    _saveTodos();
  }

  void _removeTodo(int index) {
    setState(() {
      _todoList.removeAt(index);
    });
    _saveTodos();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('로컬 저장 할 일 앱')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            // 입력창
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: InputDecoration(
                      labelText: '할 일을 입력하세요',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                SizedBox(width: 10),
                ElevatedButton(
                  onPressed: _addTodo,
                  child: Text('추가'),
                ),
              ],
            ),
            SizedBox(height: 20),
            // 리스트
            Expanded(
              child: ListView.builder(
                itemCount: _todoList.length,
                itemBuilder: (context, index) {
                  final item = _todoList[index];
                  return Card(
                    child: ListTile(
                      leading: Checkbox(
                        value: item['done'],
                        onChanged: (_) => _toggleDone(index),
                      ),
                      title: Text(
                        item['title'],
                        style: TextStyle(
                          decoration: item['done']
                              ? TextDecoration.lineThrough
                              : TextDecoration.none,
                        ),
                      ),
                      trailing: IconButton(
                        icon: Icon(Icons.delete, color: Colors.red),
                        onPressed: () => _removeTodo(index),
                      ),
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

🔐 핵심 포인트 요약

기능설명
SharedPreferences.getInstance() 저장소 인스턴스 가져오기
setStringList() 문자열 리스트 저장
getStringList() 문자열 리스트 불러오기
jsonEncode / jsonDecode Map ↔ String 변환
 

🎁 보너스 팁

  • 다른 설정값 저장 시에도 활용 가능 (다크모드 여부 등)
  • 사용자의 로그인 정보, 언어 설정, 앱 초기화 여부 등에도 적합
  • JSON 구조가 복잡해진다면 hive나 sqflite 패키지를 고려해보세요

🧠 마무리 요약

개념설명
SharedPreferences Flutter에서 제공하는 로컬 저장소
setState + 저장 상태가 바뀔 때마다 저장
앱 종료 후 유지 앱 재시작해도 데이터 유지됨
 

이제 여러분의 To-do 앱은 앱을 꺼도 데이터가 유지되는 실사용 가능한 앱이 되었습니다!