[flutter] 플러터 Riverpod를 이용한 앱 성능 최적화 방법

소개

플러터는 UI를 개발하기 위한 도구로써 강력한 성능을 가지고 있습니다. 하지만 앱이 더 복잡해지면 성능 문제가 발생할 수 있습니다. 이 때 Riverpod를 사용하여 앱의 성능을 최적화할 수 있습니다.

Riverpod란?

Riverpod는 Google에서 개발한 의존성 주입(Dependency Injection) 프레임워크입니다. 이를 사용하면 앱의 상태 관리와 의존성 관리를 효율적으로 처리할 수 있습니다.

앱 성능 최적화 방법

앱의 성능을 최적화하기 위해서는 다음과 같은 몇 가지 방법을 고려할 수 있습니다.

1. 불필요한 위젯 리빌딩 방지

플러터에서는 앱의 상태 변화에 따라 위젯이 리빌딩되는 경우가 많습니다. 이 때 Riverpod를 사용하여 상태를 관리하면, 필요한 경우에만 위젯을 리빌딩하도록 설정할 수 있습니다. 이를 통해 불필요한 위젯 리빌딩을 방지하여 성능을 향상시킬 수 있습니다.

// 상태 관리를 위한 Provider 생성
final countProvider = Provider<int>((ref) => 0);

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

class MyHomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final count = watch(countProvider);
    
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Count: $count'), // Count가 변경되지 않으면 리빌딩되지 않음
            RaisedButton(
              child: Text('Increase'),
              onPressed: () => context.read(countProvider).state++,
            ),
          ],
        ),
      ),
    );
  }
}

2. 비동기 작업 최적화

비동기 작업은 앱의 성능에 영향을 미칠 수 있습니다. Riverpod를 사용하면 쉽게 비동기 작업을 관리할 수 있습니다. FutureProvider를 사용하여 앱의 필요한 데이터를 비동기적으로 로드할 수 있습니다.

final fetchDataProvider = FutureProvider<MyData>((ref) async {
  final response = await http.get('https://api.example.com/data');
  if (response.statusCode == 200) {
    final jsonData = jsonDecode(response.body);
    return MyData.fromJson(jsonData);
  } else {
    throw Exception('Failed to load data');
  }
});

class MyHomePage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final fetchDataAsyncValue = watch(fetchDataProvider);
    
    return Scaffold(
      body: Center(
        child: fetchDataAsyncValue.when(
          data: (data) => Text('Data loaded: ${data.name}'),
          loading: () => CircularProgressIndicator(),
          error: (error, stackTrace) => Text('Error: $error'),
        ),
      ),
    );
  }
}

3. 메모이제이션 적용

Riverpod는 값을 계산하거나 필요할 때까지 계산을 지연시키는 메모이제이션 기능을 제공합니다. 이를 활용하면 동일한 값을 다시 계산하는 비용을 줄일 수 있습니다. Provider 대신 Provider.family를 사용하여 메모이제이션을 적용할 수 있습니다.

final itemProvider = Provider.family<Item, int>((ref, id) {
  // id에 해당하는 아이템을 로드하는 비용이 큰 계산
  return Item(id: id, data: fetchData(id));
});

class MyListItem extends ConsumerWidget {
  final int itemId;

  MyListItem({this.itemId});

  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final item = watch(itemProvider(itemId));
    
    return ListTile(
      title: Text(item.title),
      subtitle: Text(item.subtitle),
    );
  }
}

결론

플러터 Riverpod를 사용하여 앱의 성능을 최적화하는 방법에 대해 알아보았습니다. 위에서 소개한 방법들을 사용하면 앱의 성능을 효과적으로 개선할 수 있고, 사용자들은 더 빠르고 원활한 사용 경험을 얻을 수 있습니다. Riverpod를 적극적으로 활용하여 플러터 앱의 성능을 향상시키는 데 도움이 되길 바랍니다.

참고 자료