•  


Parse JSON in the background | Flutter

Parse JSON in the background

By default, Dart apps do all of their work on a single thread. In many cases, this model simplifies coding and is fast enough that it does not result in poor app performance or stuttering animations, often called "jank."

However, you might need to perform an expensive computation, such as parsing a very large JSON document. If this work takes more than 16 milliseconds, your users experience jank.

To avoid jank, you need to perform expensive computations like this in the background. On Android, this means scheduling work on a different thread. In Flutter, you can use a separate Isolate . This recipe uses the following steps:

  1. Add the http package.
  2. Make a network request using the http package.
  3. Convert the response into a list of photos.
  4. Move this work to a separate isolate.

1. Add the http package

#

First, add the http package to your project. The http package makes it easier to perform network requests, such as fetching data from a JSON endpoint.

To add the http package as a dependency, run flutter pub add :

$ flutter pub add http

2. Make a network request

#

This example covers how to fetch a large JSON document that contains a list of 5000 photo objects from the JSONPlaceholder REST API , using the http.get() method.

dart
Future
<http.
Response
> 
fetchPhotos
(http.
Client
 client) 
async
 {

  return
 client.
get
(
Uri
.
parse
(
'https://jsonplaceholder.typicode.com/photos'
));

}

3. Parse and convert the JSON into a list of photos

#

Next, following the guidance from the Fetch data from the internet recipe, convert the http.Response into a list of Dart objects. This makes the data easier to work with.

Create a Photo class

#

First, create a Photo class that contains data about a photo. Include a fromJson() factory method to make it easy to create a Photo starting with a JSON object.

dart
class
 Photo
 {

  final
 int
 albumId;

  final
 int
 id;

  final
 String
 title;

  final
 String
 url;

  final
 String
 thumbnailUrl;


  const
 Photo
({

    required
 this
.albumId,

    required
 this
.id,

    required
 this
.title,

    required
 this
.url,

    required
 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
,

    );

  }

}

Convert the response into a list of photos

#

Now, use the following instructions to update the fetchPhotos() function so that it returns a Future<List<Photo>> :

  1. Create a parsePhotos() function that converts the response body into a List<Photo> .
  2. Use the parsePhotos() function in the fetchPhotos() function.
dart
// A function that converts a response body into a List<Photo>.

List
<
Photo
> 
parsePhotos
(
String
 responseBody) {

  final
 parsed =

      (
jsonDecode
(responseBody) 
as
 List
).
cast
<
Map
<
String
, 
dynamic
>>();


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

}


Future
<
List
<
Photo
>> 
fetchPhotos
(http.
Client
 client) 
async
 {

  final
 response = 
await
 client

      .
get
(
Uri
.
parse
(
'https://jsonplaceholder.typicode.com/photos'
));


  // Synchronously run parsePhotos in the main isolate.

  return
 parsePhotos
(response.body);

}

4. Move this work to a separate isolate

#

If you run the fetchPhotos() function on a slower device, you might notice the app freezes for a brief moment as it parses and converts the JSON. This is jank, and you want to get rid of it.

You can remove the jank by moving the parsing and conversion to a background isolate using the compute() function provided by Flutter. The compute() function runs expensive functions in a background isolate and returns the result. In this case, run the parsePhotos() function in the background.

dart
Future
<
List
<
Photo
>> 
fetchPhotos
(http.
Client
 client) 
async
 {

  final
 response = 
await
 client

      .
get
(
Uri
.
parse
(
'https://jsonplaceholder.typicode.com/photos'
));


  // Use the compute function to run parsePhotos in a separate isolate.

  return
 compute
(parsePhotos, response.body);

}

Notes on working with isolates

#

Isolates communicate by passing messages back and forth. These messages can be primitive values, such as null , num , bool , double , or String , or simple objects such as the List<Photo> in this example.

You might experience errors if you try to pass more complex objects, such as a Future or http.Response between isolates.

As an alternate solution, check out the worker_manager or workmanager packages for background processing.

Complete example

#
dart
import
 'dart:async'
;

import
 'dart:convert'
;


import
 'package:flutter/foundation.dart'
;

import
 'package:flutter/material.dart'
;

import
 'package:http/http.dart'
 as
 http;


Future
<
List
<
Photo
>> 
fetchPhotos
(http.
Client
 client) 
async
 {

  final
 response = 
await
 client

      .
get
(
Uri
.
parse
(
'https://jsonplaceholder.typicode.com/photos'
));


  // Use the compute function to run parsePhotos in a separate isolate.

  return
 compute
(parsePhotos, response.body);

}


// A function that converts a response body into a List<Photo>.

List
<
Photo
> 
parsePhotos
(
String
 responseBody) {

  final
 parsed =

      (
jsonDecode
(responseBody) 
as
 List
).
cast
<
Map
<
String
, 
dynamic
>>();


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

}


class
 Photo
 {

  final
 int
 albumId;

  final
 int
 id;

  final
 String
 title;

  final
 String
 url;

  final
 String
 thumbnailUrl;


  const
 Photo
({

    required
 this
.albumId,

    required
 this
.id,

    required
 this
.title,

    required
 this
.url,

    required
 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
,

    );

  }

}


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


class
 MyApp
 extends
 StatelessWidget
 {

  const
 MyApp
({
super
.key});


  @override

  Widget
 build
(
BuildContext
 context) {

    const
 appTitle = 
'Isolate Demo'
;


    return
 const
 MaterialApp
(

      title: appTitle,

      home: 
MyHomePage
(title: appTitle),

    );

  }

}


class
 MyHomePage
 extends
 StatelessWidget
 {

  const
 MyHomePage
({
super
.key, 
required
 this
.title});


  final
 String
 title;


  @override

  Widget
 build
(
BuildContext
 context) {

    return
 Scaffold
(

      appBar: 
AppBar
(

        title: 
Text
(title),

      ),

      body: 
FutureBuilder
<
List
<
Photo
>>(

        future: 
fetchPhotos
(http.
Client
()),

        builder: (context, snapshot) {

          if
 (snapshot.hasError) {

            return
 const
 Center
(

              child: 
Text
(
'An error has occurred!'
),

            );

          } 
else
 if
 (snapshot.hasData) {

            return
 PhotosList
(photos: snapshot.data!);

          } 
else
 {

            return
 const
 Center
(

              child: 
CircularProgressIndicator
(),

            );

          }

        },

      ),

    );

  }

}


class
 PhotosList
 extends
 StatelessWidget
 {

  const
 PhotosList
({
super
.key, 
required
 this
.photos});


  final
 List
<
Photo
> photos;


  @override

  Widget
 build
(
BuildContext
 context) {

    return
 GridView
.
builder
(

      gridDelegate: 
const
 SliverGridDelegateWithFixedCrossAxisCount
(

        crossAxisCount: 
2
,

      ),

      itemCount: photos.length,

      itemBuilder: (context, index) {

        return
 Image
.
network
(photos[index].thumbnailUrl);

      },

    );

  }

}

Isolate demo

- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본