Parsing large JSON files can lead to poor performance of apps and shuttering animations. If parsing and computing a large JSON file take more than 16 milliseconds, the users will experience Jank. Dart by default uses a single thread to perform these tasks, though being simple and fast for less expensive computation, it fails when the computation is large.

o avoid these janks, isolates can be used to perform all computations in a different thread in the background. In this article, we will explore the process of parsing JSON in the background. To do so follow the below steps:

  1. Import the http package.
  2. Make a network request using the http package
  3. Change the response into dart objects in list form
  4. Move this work to a different isolate

Add the below dependency to the pubsec.yml file

dependencies:
  http: ^0.13.4

 

We can use the http.get() method to fetch the sample data of 5000 images from JSONPlaceholder REST API as shown below:

Future<http.Response> fetchPhotos(http.Client client) async {
return client.get('https://jsonplaceholder.typicode.com/photos');
}


Parsing and Converting the Data:

We now have 5000 photos in JSON form received from the http.response and these need to be parsed and converted into a list of Dart objects. To do show First create a Photo class as shown below.

Here we will create a Photo class that contains the JSON data as shown below:

class Photo_list {
final int photo_id;
final String photo_title;
final String photo_thumbnailUrl;

Photo({this.photo_id, this.photo_title, this.photo_thumbnailUrl});

factory Photo_list.fromJson(Map<String, dynamic> json) {
    return Photo_list(
    photo_id: json['id'] as int,
    photo_title: json['title'] as String,
    photo_thumbnailUrl: json['thumbnailUrl'] as String,
    );
}
}
 

Now update the getPhoto() function to returns a Future<List<Photo>> through the below steps:

  1. Make a Photos_parser() function to convert the response body into a List<Photo>.
  2. Use the Photos_parser() function in the getPhotos() function.

List<Photo>Photos_parser(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();

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

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

return Photos_parser(response.body);
}
 

Moving work to a different Isolate:

The compute() function can be used to move the work to a separate isolate where it will be parsed and converted in the background. It runs expensive functions in a background isolate and returns the result. 

Future<List<Photo>> getPhotos(http.Client client) async {
final response =
    await client.get('https://jsonplaceholder.typicode.com/photos');
return compute(parsePhotos, response.body);
}
 

Complete Source Code:

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>> getPhotos(http.Client client) async {
final response =
await client.get('https://jsonplaceholder.typicode.com/photos');

// run Photos_parser in a separate isolate.
return compute(Photos_parser, response.body);
}

List<Photo> Photos_parser(String responseBody) {
final parsed = jsonDecode(responseBody).cast<Map<String, dynamic>>();

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

class Photo_list{
final int Photo_albumId;
final int Photo_id;
final String Photo_title;
final String Photo_url;
final String Photo_thumbnailUrl;

Photo_list({this.Photo_albumId, this.Photo_id, this.Photo_title, this.Photo_url, this.Photo_thumbnailUrl});

factory Photo_list.fromJson(Map<String, dynamic> json) {
    return Photo_list(
    Photo_albumId: json['albumId'] as int,
    Photo_id: json['id'] as int,
    Photo_title: json['title'] as String,
    Photo_url: json['url'] as String,
    Photo_thumbnailUrl: json['thumbnailUrl'] as String,
    );
}
}

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
    final appTitle = 'Isolate Demo';

    return MaterialApp(
    title: appTitle,
    home: MyHomePage(title: appTitle),
    );
}
}

class HomePage extends StatelessWidget {
final String title;

HomePage({Key key, this.title}) : super(key: key);

@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) print(snapshot.error);

        return snapshot.hasData
            ? PhotosList(photos: snapshot.data)
            : Center(child: CircularProgressIndicator());
        },
    ),
    );
}
}

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

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

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

Words from our clients

 

Tell Us About Your Project

We’ve done lot’s of work, Let’s Check some from here