티스토리 뷰

 


 

Flutter Interview Questions and Answers

In this article, you’ll work through a series of Flutter and Dart job interview questions and answers.

www.kodeco.com


1. hot reload와 hot restart의 차이

Hot Reload

- UI를 거의 즉시에 업데이트

- 앱을 실행한 상태에서도 코드 변경을 즉시 반영 (앱 상태 유지됨)

 

Hot Restart

- 앱 상태를 초기 조건으로 재설정 한 후 UI 업데이트 -> Hot Reload보다 시간이 더 소요됨

- 앱을 재시작, 앱의 모든 상태를 초기화, 앱을 다시 빌드하고 새로운 인스턴스로 실행

- 앱의 전반적인 구조가 변경됐거나 패키지 추가 또는 제거와 같이 앱 자체의 설정이 변경된 경우 사용

 


 

2. StatelessWidget과 StatefulWidget의 차이

StatelessWidget

- 변경되지 않는 불변의 클래스

- 한 번 생성되면 내부 상태가 변경되지 않고, 한 번에 한 번만 화면에 그려짐

 

StatefulWidget

- State 객체와 결합되어 setState()를 호출할 때마다 새로운 값으로 위젯을 다시 빌드

- UI가 동적으로 변경될 수 있는 상황에서 사용

 


 

3. WidgetsApp and MaterialApp의 차이

WidgetsApp

- 기본 앱 기능을 제공하는 낮은 수준의 클래스

- 모든 플러터 앱의 핵심 위젯으로 네비게이션 및 로컬라이제이션과 같은 기능 포함

- 기본적으로 Material Design 언어를 사용하지 않음 (MaterialApp에서 제공하는 다양한 위젯과 기능은 포함되어 있지 않음)

- Material 구성 요소를 필요로 하지 않는 플러터 앱을 개발할 때 or 완전히 사용자 지정 디자인 언어를 구현할 때 적절

 

MaterialApp

- WidgetsApp 상위에 구축되어 있는 클래스

- Material Design 언어를 채택하며, Material Design 특정 위젯과 기능을 제공

- Material Design 가이드라인을 준수하는 앱에 사용됨. 풍부한 Material 위젯과 테마를 제공하기 때문에 대부분의 Flutter 앱에서 MaterialApp을 사용 중

- WidgetsApp이 제공하는 모든 기능을 포함하며, 테마(ThemeData), Material Design 위젯(Scaffold, AppBar, FloatingActionButton 등), 라우팅, 고급 네비게이션 기능 등 제공

 

주요 차이점

- MaterialApp이 Material Design을 지원하도록 설계된 반면, Widgets는 디자인 언어에 중립적

- MaterialApp는 Material Design에 맞춘 다양한 기능을 포함하여 UI를 만드는데 필요한 (사전 제작된) 위젯을 포함. 그에 비해 WidgetsApp은 더 기본적인 기능을 제공하며, 네비게이션, 로컬라이젠이션 및 구성과 같은 기본적인 기능만 제공

 

반드시 MaterialApp을 사용할 필요는 없음. iOS 사용자에게 친숙한 느낌을 주기 위해서는 CupertinoApp을 사용할 수도 있고, 직접 디커스텀 위젯 세트를 구축할 수도 있음

 

 

 

What is the difference between flutter WidgetsApp and MaterialApp?

In Flutter, both WidgetsApp and MaterialApp are classes used to set up and configure an app, serving as the root of your app’s widget tree…

medium.com

 

 


 

4. Scaffold도 nested 될 있나? 

가능. Scaffold도 단지 위젯일 뿐이기 때문에 위젯 자리 어디든 위치할 수 있음. nested한 후  layer drawers, snack bars, bottom sheets도 쓸 수 있음

 

 

코드 ⬇️

더보기
void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'ProxyProvider Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('scaffold-1'),
        backgroundColor: Colors.blue[100],
      ),
      body: Scaffold(
        appBar: AppBar(
          title: Text('scaffold-2'),
          backgroundColor: Colors.green[200],
        ),
        body: Container(
          height: 300,
          width: 300,
          child: Scaffold(
            backgroundColor: Colors.pink[200],
            appBar: AppBar(
              backgroundColor: Colors.pink[600],
              title: Text('scaffold-3'),
            ),
            drawer: Drawer(
              // Add a ListView to the drawer. This ensures the user can scroll
              // through the options in the drawer if there isn't enough vertical
              // space to fit everything.
              child: ListView(
                // Important: Remove any padding from the ListView.
                padding: EdgeInsets.zero,
                children: [
                  const DrawerHeader(
                    decoration: BoxDecoration(
                      color: Colors.blue,
                    ),
                    child: Text('Drawer Header'),
                  ),
                  ListTile(
                    title: const Text('Item 1'),
                    onTap: () {
                      // Update the state of the app.
                      // ...
                    },
                  ),
                  ListTile(
                    title: const Text('Item 2'),
                    onTap: () {
                      // Update the state of the app.
                      // ...
                    },
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

 

 

5. 패키지, 플러그인, third-party dependencies는 언제 쓰는 게 적절한가?

패키지나 플러그인들은 개발 시간과 노력을 아껴줌. 복잡한 문제를 해결할 필요가 없음. 이미 다른 누군가 해놨기 때문에. 특히 높은 rate가 높을수록

 

그러나 한편으로는 서드 파티 패키지들에게 너무 의존하게 될 위험이 있음. 패키지는 망가질 수도 있고 버그가 있을 수도 있고 때로는 더 이상 유지되지 않을 수도 있음. 나중에 새로운 패키지로 전환할 필요가 생겨서 코드를 크게 수정해야 할 수도 있음

 

그래서 핵심 비즈니즈 로직에서 패키지를 분리하는 것이 중요. 이를 위해 Dart 언어의 추상 클래스를 생성하여 패키지를 인터페이스로 사용할 수 있음. 이런 아키텍처를 설정하면, 패키지를 전환할 때 인터페이스를 구현하는 구체적인 래퍼 클래스만 다시 작성하면 됨

 

 

플러터에서의 추상 클래스

- 상속을 통해 서브클래에게 강제를 구현하는 메커니즘.

- class 앞에 abstract 키워드를 써서 표현

- 하나 이상의 추상 메서드(구현부가 없음)를 포함할 수 있고, 해당 추상 클래스를 직접적으로 인스턴스화할 수 없음. 

- 실제 구현은 추상 클래스를 상속받은 구체적인 클래스에서 하게 됨

 

예를들어 아래처럼 SmartPhone이라는 추상 클래스를 만들고

abstract class SmartPhone {
  void init();
  int getVersion(String name);
  String getOS(String name);
}

 

 

이 추상 클래스를 상속받은 iPhone라는 클래스를 만들었을 때 반드시 세개의 메서드(init, getVersion, getOS)를 오버라이드해서 구현해야 함 (안할 시 에러 발생)

class iPhone implements SmartPhone {
  @override
  void init() {
    
  }

  @override
  int getVersion(String name) {
    return 15;
  }

  @override
  String getOS(String name) {
    return 'iOS';
    
  }
}

 

 

만약에 사용하던 패키지나 라이브러리가 변경되거나 심지어 사라질 경우에도 구체적인 구현부만 수정해주면 다른 곳에 영향이 적게 새로운 패키지나 라이브러리로 변경할 수 있음

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크