강의

멘토링

커뮤니티

인프런 커뮤니티 질문&답변

kindjin12님의 프로필 이미지
kindjin12

작성한 질문수

Flutter 앱 개발 기초

좋아요 사진 기기에 저장하기

SharedPreferences prefs 초기화 시기 문제

해결된 질문

작성

·

16

1

제 식대로 코드를 수정했습니다.

MultiProvider로 CatService(prefs)를 호출하는 시기와 prefs를 초기화하는 시기가 비슷하여, 문제가 생겼습니다. "CatService 내부에서 async로 초기화하게 만들고
생성자에서 바로 prefs를 쓰지 않도록 수정"하는 방식을 추천하는데 그게 맞을까요? 에러 메세지는 다음과 같습니다 [ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: PlatformException(channel-error, Unable to establish connection on channel: "dev.flutter.pigeon.shared_preferences_android.SharedPreferencesApi.getAll"., null, null)

 

 

 

 

주요 코드

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  SharedPreferences prefs = await SharedPreferences.getInstance();

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CatService(prefs)),
      ],
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
      theme: ThemeData(textTheme: GoogleFonts.getTextTheme('Sunflower')),
    );
  }
}

class CatService extends ChangeNotifier {
  SharedPreferences prefs;
  List<String> catImages = [];
  List<String> favoriteImages = [];

  CatService(this.prefs) {
    getRandomCatImages();
    favoriteImages = prefs.getStringList("favorites") ?? [];
  }

  void getRandomCatImages() async {
    Response result = await Dio().get(
      'https://api.thecatapi.com/v1/images/search?limit=10&mime_types=jpg',
    );
    for (var i = 0; i < result.data.length; i++) {
      catImages.add(result.data[i]["url"]);
    }
    notifyListeners();
  }

  void toggleFavoriteImages(String image) {
    if (favoriteImages.contains(image)) {
      favoriteImages.remove(image);
    } else {
      favoriteImages.add(image);
    }
    prefs.setStringList("favorites", favoriteImages);
    notifyListeners();
  }
}

 

<전체 코드>

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  SharedPreferences prefs = await SharedPreferences.getInstance();

  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (context) => CatService(prefs)),
      ],
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
      theme: ThemeData(textTheme: GoogleFonts.getTextTheme('Sunflower')),
    );
  }
}

class CatService extends ChangeNotifier {
  SharedPreferences prefs;
  List<String> catImages = [];
  List<String> favoriteImages = [];

  CatService(this.prefs) {
    getRandomCatImages();
    favoriteImages = prefs.getStringList("favorites") ?? [];
  }

  void getRandomCatImages() async {
    Response result = await Dio().get(
      'https://api.thecatapi.com/v1/images/search?limit=10&mime_types=jpg',
    );
    for (var i = 0; i < result.data.length; i++) {
      catImages.add(result.data[i]["url"]);
    }
    notifyListeners();
  }

  void toggleFavoriteImages(String image) {
    if (favoriteImages.contains(image)) {
      favoriteImages.remove(image);
    } else {
      favoriteImages.add(image);
    }
    prefs.setStringList("favorites", favoriteImages);
    notifyListeners();
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Consumer<CatService>(
      builder: (context, catService, child) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.yellow,
            title: Center(child: Text("랜덤 고양이")),
            actions: [
              IconButton(
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(builder: (context) => FavoritePage()),
                  );
                },
                icon: Icon(Icons.favorite, color: Colors.red),
              ),
            ],
          ),
          body: SafeArea(
            child: Container(
              color: Colors.brown.shade100,
              child: GridView.count(
                crossAxisCount: 2,
                mainAxisSpacing: 8,
                crossAxisSpacing: 8,
                padding: EdgeInsets.all(8),
                children: List.generate(catService.catImages.length, (index) {
                  String catImage = catService.catImages[index];
                  return Stack(
                    children: [
                      Positioned.fill(
                        child: GestureDetector(
                          onTap: () {
                            catService.toggleFavoriteImages(catImage);
                          },
                          child: Image.network(catImage, fit: BoxFit.cover),
                        ),
                      ),
                      Positioned(
                        right: 0,
                        bottom: 0,
                        child: Icon(
                          Icons.favorite,
                          size: 40,
                          color: catService.favoriteImages.contains(catImage)
                              ? Colors.pink.shade200
                              : Colors.transparent,
                        ),
                      ),
                    ],
                  );
                }),
              ),
            ),
          ),
        );
      },
    );
  }
}

class FavoritePage extends StatelessWidget {
  const FavoritePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<CatService>(
      builder: (context, catService, child) {
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.yellow,
            title: Center(child: Text("좋아")),
          ),
          body: SafeArea(
            child: GridView.count(
              crossAxisCount: 2,
              mainAxisSpacing: 8,
              crossAxisSpacing: 8,
              padding: EdgeInsets.all(8),
              children: List.generate(catService.favoriteImages.length, (
                index,
              ) {
                String catImage = catService.favoriteImages[index];
                return Stack(
                  children: [
                    Positioned.fill(
                      child: GestureDetector(
                        onTap: () {
                          catService.toggleFavoriteImages(catImage);
                        },
                        child: Image.network(catImage, fit: BoxFit.cover),
                      ),
                    ),
                    Positioned(
                      right: 0,
                      bottom: 0,
                      child: Icon(
                        Icons.favorite,
                        size: 40,
                        color: catService.favoriteImages.contains(catImage)
                            ? Colors.pink.shade200
                            : Colors.transparent,
                      ),
                    ),
                  ],
                );
              }),
            ),
          ),
        );
      },
    );
  }
}

답변 2

1

DevStory님의 프로필 이미지
DevStory
지식공유자

안녕하세요.

첨부해 주신 에러 메세지는 async와 관련이 없고, SharedPreferences 패키지를 설치하신 뒤 Hot Reload 방식으로 실행할 때 나오는 에러로 보입니다.

VSCode에서 현재 실행중인 연결을 종료했다가 다시 시작하시면 해결 될 것으로 보입니다. 만약 그렇게 해도 문제가 해결되지 않으신다면 문제 재현 방법을 공유 부탁드립니다.

감사합니다 🙂

0

안녕하세요, 인프런 AI 인턴입니다. kindjin12님.

질문해 주신 내용은 SharedPreferences 초기화와 관련된 문제로 보입니다. SharedPreferences가 비동기적으로 초기화되기 때문에, 클래스 생성자에서 바로 사용하려고 할 때 문제가 발생할 수 있습니다.

현재 코드에서는 SharedPreferences를 동기적으로 얻어와 CatService에 전달하므로, prefs가 초기화되기 전에 생성자를 호출하여 문제가 발생할 수 있습니다. 이를 해결하기 위해서는 SharedPreferences를 설정하는 시점을 비동기로 처리하는 것이 좋습니다. 이는 Futureasync를 통해 다룰 수 있습니다.

CatService에서 SharedPreferences를 비동기로 초기화하는 방법은 다음과 같이 수정할 수 있습니다:

  1. prefs를 생성자에서 직접 설정하지 않고 비동기 메서드로 초기화합니다.
  2. 초기화가 완료될 때까지 기다린 후 나머지 로직을 수행합니다.

아래 예제를 통해 SharedPreferences의 비동기 초기화를 확인하실 수 있습니다:

class CatService extends ChangeNotifier {
  SharedPreferences? prefs;
  List<String> catImages = [];
  List<String> favoriteImages = [];

  CatService() {
    initializePreferences();
    getRandomCatImages();
  }

  Future<void> initializePreferences() async {
    prefs = await SharedPreferences.getInstance();
    favoriteImages = prefs?.getStringList("favorites") ?? [];
    notifyListeners();
  }

  void getRandomCatImages() async {
    Response result = await Dio().get(
      'https://api.thecatapi.com/v1/images/search?limit=10&mime_types=jpg',
    );
    for (var i = 0; i < result.data.length; i++) {
      catImages.add(result.data[i]["url"]);
    }
    notifyListeners();
  }

  void toggleFavoriteImages(String image) {
    if (favoriteImages.contains(image)) {
      favoriteImages.remove(image);
    } else {
      favoriteImages.add(image);
    }
    prefs?.setStringList("favorites", favoriteImages);
    notifyListeners();
  }
}

이렇게 초기화가 비동기로 처리되어 prefs가 준비된 후에 사용될 수 있습니다. 이로 인해 코드 실행 시점에 발생할 수 있는 문제를 방지할 수 있습니다.

참고 링크를 첨부합니다:
- Flutter에서 SharedPreferences 사용하기 - 유사한 질문과 답변

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

kindjin12님의 프로필 이미지
kindjin12

작성한 질문수

질문하기