Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

nomad-programmer

[Programming/Flutter] isolate : 백그라운드에서의 JSON 파싱 본문

Programming/Flutter

[Programming/Flutter] isolate : 백그라운드에서의 JSON 파싱

scii 2020. 10. 23. 22:05

isolate는 다른 언어에서의 thread 개념이라도 생각면된다. Flutter는 main isolate에서 앱이 실행된다. 그런데 비싼 비용의 데이터를 불러올때면 툭툭 끊기는 애니메이션을 야기할 수 있다. 이렇게 툭툭 끊기는 애니메이션을 "jank"라고 부른다.
허나 isolate를 사용하면 jank가 없는 애니메이션을 볼 수 있을뿐더러 성능도 올라간다.

flutter-ko.dev/docs/cookbook/networking/background-parsing

 

백그라운드에서 JSON 파싱하기

기본적으로, Dart 앱은 모든 작업을 단일 스레드에서 수행합니다. 대부분의 경우 이러한 모델은코딩을 단순화시키며, 앱 성능이 떨어지거나 jank라고 불리는 뚝뚝 끊기는 애니메이션을 야기하지

flutter-ko.dev

import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('isolate 예제'),
      ),
      body: FutureBuilder<List<Photo>>(
        future: fetchPhotos(http.Client()),
        builder: (BuildContext context, AsyncSnapshot<List<Photo>> snapshot) {
          if (snapshot.hasError) {
            print(snapshot.error);
          }
          return snapshot.hasData
              ? PhotoList(photos: snapshot.data)
              : Center(child: CircularProgressIndicator());
        },
      ),
    );
  }
}

class PhotoList extends StatelessWidget {
  final List<Photo> photos;

  const PhotoList({Key key, this.photos}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: photos.length,
      itemBuilder: (BuildContext context, int index) {
        return Image.network(photos[index].thumbnailUrl);
      },
    );
  }
}

class Photo {
  final int albumId;
  final int id;
  final String title;
  final String url;
  final String thumbnailUrl;

  Photo({this.albumId, this.id, this.title, this.url, this.thumbnailUrl});

  factory Photo.fromJson(Map<String, dynamic> json) {
    return Photo(
      albumId: json['albumId'] as int,
      id: json['id'] as int,
      title: json['title'] as String,
      url: json['url'] as String,
      thumbnailUrl: json['thumbnailUrl'] as String,
    );
  }
}

Future<List<Photo>> fetchPhotos(http.Client client) async {
  final response =
      await client.get('https://jsonplaceholder.typicode.com/photos');

  // compute 함수를 사용하여 parsePhotos를 별도 isolate에서 수행한다.
  return compute(parsePhotos, response.body);
}

// 응답 결과를 List<Photo>로 변환하는 함수
List<Photo> parsePhotos(String reponseBody) {
  final List<Map<String, dynamic>> parsed =
      json.decode(reponseBody).cast<Map<String, dynamic>>();

  return parsed.map<Photo>((json) => Photo.fromJson(json)).toList();
}

compute 함수를 사용하여 파싱하고 변환하는 작업을 백그라운드 isolate으로 옮긴다.

compute() 함수는 오래 걸리는 함수를 백그라운드 isolate에서 돌리고 그 결과를 반환한다.

위의 예제에서는 parsePhotos() 함수를 백그라운드에서 수행한다.


FutureBuilder

Flutter의 경우 비동기 통신을 사용한다. 이것은 동기식 통신과 다르게 서버에서 데이터를 모두 받아오기전, 화면을 그려줄 수 있는 되는 장점이 있다.

위의 예제에서 FutureBuilder를 사용했다. FutureBuilder를 사용한 이유는 Future를 사용하는 이유처럼 데이터를 모두 다 받기전에 먼저 받은 데이터를 UI에 그리기위해서이다.

만약 FutureBuilder가 없다면 데이터가 모두 다 받아지기를 기다린 후, 데이터를 UI에 그릴것이다. 

Comments