[Flutter/Decoding Flutter] 핫 리로드(Hot reload)

작성 날짜:

최근 업데이트 날짜:

Decoding Flutter 유튜브 영상


핫 리로드란?

핫 리로드는 Flutter가 제공하는 정말 유용한 기능 중 하나이다. 사실 제일 마음에 드는 부분을 꼽으라면 핫 리로드를 선택할 정도로 유용하다고 생각한다.

핫 리로드란 어플이 실행되고 있는 상태에서 어플의 상태를 유지하면서 코드의 변경 사항을 적용시켜주는 기능이다.

핫 리로드 대한 Flutter의 공식 문서를 이 게시글에 한국어로 정리해봤다. 필자가 궁금해서 개인적으로 정리한 글이라 부족하지만, 핫 리로드에 대해 더 알고 싶은 다른 분들에게도 도움이 되었으면 좋겠다.

그렇다면 핫 리로드는 어떠한 방식으로 이루어지는 걸까?

핫 리로드는 Dart 가상 머신에 들어간 소스 코드를 업데이트하면서 시작한다. 그 후 위젯 트리에서 루트 위젯(최상단에 위치하는 위젯)부터 시작하여 모든 위젯의 build() 메소드를 재실행한다.

이제 핫 리로드를 직접 사용해보자.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MyApp());
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Hello, World!")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FlutterLogo(size: 100),
            FlutterLogo(size: 100),
          ],
        ),
      ),
    );
  }
}

위와 코드를 실행하면 아래 사진과 같은 화면이 보일 것이다.

그렇다면 어플을 실행하고 있는 상태에서 AppBartitle을 “Hello, Flutter!”로 설정하고, ColumnRow로 바꿔보자.

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Hello, Flutter!")),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FlutterLogo(size: 100),
            FlutterLogo(size: 100),
          ],
        ),
      ),
    );
  }
}

그리고 나서 핫 리로드를 해주면 아래 사진처럼 변경 사항들이 어플에 바로 적용되는 것을 확인할 수 있다.

"Hello, World!" -> "Hello, Flutter!" <br> Column -> Row

이번엔 MyAppMyOtherApp으로 변경해보자.

void main() => runApp(MyOtherApp());
class MyOtherApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: MyOtherPage());
  }
}

class MyOtherPage extends StatefulWidget {
  @override
  _MyOtherPageState createState() => _MyOtherPageState();
}

class _MyOtherPageState extends State<MyOtherPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Center(
        child: Text("Hello, Hot Reload.", style: TextStyle(color: Colors.white, fontSize: 30)),
      ),
    );
  }
}

이제 핫 리로드를 실행하면 MyApp 대신 MyOtherApp이 보일까?

화면에는 여전히 MyApp이 보인다.

그렇지 않다. 화면에는 그대로 MyApp이 보인다. 이는 MyApp이 루트 위젯이기 때문이다. 위에서 언급했듯이, 핫 리로드는 루트 위젯부터 시작해서 아래로 내려가며 각 위젯의 build() 메소드를 재실행한다. 따라서 핫 리로드를 한다고 해도 루트 위젯인 MyAppbuild() 메소드가 재실행되기 때문에 화면은 변하지 않는다.

MyOtherApp을 화면에 보이게 하기 위해선 루트 위젯보다 상위의 위치하는 main() 메소드나 runApp() 메소드를 재실행 하면 된다. 이를 위해서는 핫 리로드가 아니라 아예 어플을 재실행(restart) 해야한다.

어플을 재실행하면 아래 사진처럼 MyOtherApp이 화면에 보이는 것을 확인할 수 있다.

재실행하니 MyOtherApp이 보인다.

build() 메소드 외부에서 변경사항이 있을 때는 어떨까? 핫 리로드는 각 위젯의 build() 메소드만 재실행하기 때문에 당연히 build() 메소드 외부의 변경사항은 적용이 되지 않는다. Stateful 위젯에서 사용되는 initState() 메소드나 dispose() 메소드 안에 변경사항이 있다고 하더라도 핫 리로드로 이를 적용시킬 수 없다는 것을 의미한다. 이런 변경사항들 또한 어플을 재실행 해야한다.

마지막으로 static 필드를 새로 추가하거나 변경하는 상황을 생각해보자. 우선 다시 MyOtherAppMyApp으로 변경해주고 아래와 같이 AppBartitlestatic 변수로 선언한다.

class _MyHomePageState extends State<MyHomePage> {
  static const title = "Hello, Flutter!";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(title)),
      body: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FlutterLogo(size: 100),
            FlutterLogo(size: 100),
          ],
        ),
      ),
    );
  }
}

제목은 이전과 똑같기 때문에 화면도 변화가 없다. 이 상태에서 title을 “Hello, Dart!”로 변경해보자.

static const title = "Hello, Dart!";

이제 핫 리로드를 하면 타이틀이 변화할까?

타이틀은 여전히 "Hello, Flutter!"이다.

타이틀이 변경되지 않았다. 왜 그럴까? 위에서 언급햇듯이, 핫 리로드는 어플의 상태를 유지한 채로 변경사항을 적용한다. static 필드는 상태에 해당하기 때문에 핫 리로드를 해도 업데이트 되지 않는다. static 필드를 업데이트 하기 위해서는 이전 상황들과 마찬가지로 어플을 재실행 해야한다.

재실행하니 타이틀이 "Hello, Dart!"로 변경되어 보인다.

댓글남기기