디스크에 키-값 데이터 저장하기

상대적으로 적은 양의 키-값 데이터를 저장하려고 한다면, shared_preferences 플러그인을 사용하세요.

일반적으로 iOS와 Android 두 플랫폼 모두에 데이터를 저장하기 위한 네이티브 플랫폼 통합 코드를 작성해야 합니다. 다행히도 shared_preferences 플러그인을 사용하면 키-값 데이터를 디스크에 저장할 수 있습니다. 간단한 데이터 저장 기능을 제공하는 shared preferences 플러그인은 iOS의 NSUserDefaults와 Android의 SharedPreferences를 감싸고 있습니다.

여기서는 아래와 같은 단계로 진행합니다:

  1. 의존성 추가하기.
  2. 데이터 저장하기.
  3. 데이터 읽기.
  4. 데이터 삭제하기.

1. 의존성 추가하기

시작하기 전에 pubspec.yaml 파일에 shared_preferences 플러그인을 추가하세요:

dependencies:
  flutter:
    sdk: flutter
  shared_preferences: "<newest version>"

2. 데이터 저장하기

SharedPreferences 클래스가 제공하는 setter 메서드를 사용하여 데이터를 저장합니다. Setter 메서드는 setInt, setBool, setString와 같이 다양한 원시 타입을 지원합니다.

Setter 메서드는 두 가지 작업을 수행합니다: 먼저, 메모리 상에서 키-값 쌍을 동기적으로 업데이트합니다. 다음으로, 데이터를 디스크에 저장합니다.

// shared preferences 얻기
final prefs = await SharedPreferences.getInstance();

// 값 저장하기
prefs.setInt('counter', counter);

3. 데이터 읽기

SharedPreferences 클래스가 제공하는 getter 메서드를 사용하여 데이터를 읽을 수 있습니다. 각 setter에 상응하는 getter가 존재합니다. 예를 들어 getInt, getBool, getString 와 같은 메서드를 사용할 수 있습니다.

final prefs = await SharedPreferences.getInstance();

// counter 키에 해당하는 데이터 읽기를 시도합니다. 만약 존재하지 않는 다면 0을 반환합니다.
final counter = prefs.getInt('counter') ?? 0;

4. 데이터 삭제하기

remove() 메서드를 사용하여 데이터를 삭제하세요.

final prefs = await SharedPreferences.getInstance();

prefs.remove('counter');

지원되는 자료형

키-값 저장소를 사용하는 것은 쉽고 간편하지만, 몇가지 제약 사항이 있습니다:

  • 오직 원시 타입만 사용 가능합니다: int, double, bool, string, stringList
  • 대용량 데이터 저장을 위해 설계되지 않았습니다.

Android의 Shared Preferences에 대해 더 자세히 알고 싶다면, Android 개발자 사이트의 Shared preferences 문서를 참고하세요.

테스팅 지원

shared_preferences를 사용하여 데이터를 저장하는 코드를 테스트하는 것은 좋은 생각입니다. 이를 위해 shared_preferences 라이브러리를 mocking 하는 MethodChannel 객체를 생성해야 합니다.

테스트 파일 setupAll() 메서드 안에서 아래 코드를 수행하면 초깃값과 함께 SharedPreferences를 생성하세요:

const MethodChannel('plugins.flutter.io/shared_preferences')
  .setMockMethodCallHandler((MethodCall methodCall) async {
    if (methodCall.method == 'getAll') {
      return <String, dynamic>{}; // 필요하다면 여기서 초깃값을 설정합니다.
    }
    return null;
  });

예제

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // 이 위젯은 어플리케이션의 최상위 위젯입니다.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Shared preferences demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Shared preferences demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

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

  //시작할 때 counter 값을 불러옵니다.
  _loadCounter() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter = (prefs.getInt('counter') ?? 0);
    });
  }

  //클릭하면 counter를 증가시킵니다.
  _incrementCounter() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _counter = (prefs.getInt('counter') ?? 0) + 1;
      prefs.setInt('counter', _counter);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // 이 마지막 콤마는 build 메서드에 자동 서식이 잘 적용될 수 있도록 도와줍니다.
    );
  }
}