Flutter Performance - Working With Low-Level Isolate APIs in Flutter

Flutter Performance - Working With Low-Level Isolate APIs in Flutter

Learn how to do performance programming in Flutter using Low-level Isolate APIs. Isolates helps to create threads that helps to do heavy operations on a separate threads. Isolates hugely improves the performance of Flutter apps.

Working With Low-Level Isolate APIs in Flutter

In my previous article I had explained about how to use Isolates at a high level. Using high-level APIs has some disadvantages though.

By using Low-level APIs over the High-level compute function you can get more control over the isolates. You can pause, resume and stop the Isolates at any point of time which is not possible with ‘_compute_’ function.

Let’s see how we can do those.

Here I am creating a custom class to sent data to Isolates. I am calling it ThreadParams.

class ThreadParams {
  ThreadParams(this.val, this.sendPort);
  int val;
  SendPort sendPort;
}

Here you can see one of the parameter is a SendPort. This is the port through with the isolate communicates

with the calling Isolate.

There is another class called ReceivePort through which the calling Isolate class gets the data back.

Start Isolate Thread

So this is how the start method will look like.

Isolate _isolate;
 bool _running = false;
 ReceivePort _receivePort;
 Capability _capability;

 void _start() async {
    if (_running) {
      return;
    }
    setState(() {
      _running = true;
    });
    _receivePort = ReceivePort();
    ThreadParams threadParams = ThreadParams(2000,     _receivePort.sendPort);
    _isolate = await Isolate.spawn(
      _isolateHandler,
      threadParams,
    );
    _receivePort.listen(_handleMessage, onDone: () {
      setState(() {
        _threadStatus = 'Stopped';
      });
    });
}

Isolate.spawn will create a new Isolate thread. The calling methods listens to the messages from the __isolate_ with __receivePort.listen_ which has a function that receives the message.

The __handleMessage_ can be a simple function like this.

void _handleMessage(dynamic data) {
    print(data.toString());
}

__isolateHandler_ method is the entry method of the _isolate and it should a either a static method or it should not a method inside a class.

So below is the __isolateHandler_ with the heavy operation methods that we are going to do inside the __isolate_ thread.

static void _isolateHandler(ThreadParams threadParams) async {
    heavyOperation(threadParams);
  }

  static void heavyOperation(ThreadParams threadParams) async {
    int count = 10000;
    while (true) {
      int sum = 0;
      for (int i = 0; i < count; i++) {
        sum += await computeSum(1000);
      }
      count += threadParams.val;
      threadParams.sendPort.send(sum.toString());
    }
  }

  static Future<int> computeSum(int num) {
    Random random = Random();
    return Future(() {
      int sum = 0;
      for (int i = 0; i < num; i++) {
        sum += random.nextInt(100);
      }
      return sum;
    });
  }

Pause, Resume and Stop Isolates

void _pause() {
  if (null != _isolate) {
    _paused ? _isolate.resume(_capability) : _capability = _isolate.pause();
    setState(() {
      _paused = !_paused;
      _threadStatus = _paused ? 'Paused' : 'Resumed';
    });
  }
}

void _stop() {
  if (null != _isolate) {
    setState(() {
      _running = false;
    });
    _receivePort.close();
    _isolate.kill(priority: Isolate.immediate);
    _isolate = null;
  }
}

Here the main thing to understand is that to pause the Isolate is that to resume an isolate, We need a Capability object which we can get while pausing the Isolate. The Isolate pause will return a Capability which can be used to resume that Isolate.

Send messages

threadParams.sendPort.send(sum.toString());

SendPort.send is used to send a message back to the Calling Isolate. By Calling Isolate i mean here the Main Isolate in which the Flutter app is running.

So thats the basics.

Complete Example

Here is the complete example.

import 'package:flutter/material.dart';
import 'dart:isolate';
import 'dart:math';
import 'dart:async';

class PerformancePage extends StatefulWidget {
  final String title = "Isolates Demo";

  @override
  _PerformancePageState createState() => _PerformancePageState();
}

class _PerformancePageState extends State<PerformancePage> {
  //
  Isolate _isolate;
  bool _running = false;
  bool _paused = false;
  String _message = '';
  String _threadStatus = '';
  ReceivePort _receivePort;
  Capability _capability;

  void _start() async {
    if (_running) {
      return;
    }
    setState(() {
      _running = true;
      _message = 'Starting...';
      _threadStatus = 'Running...';
    });
    _receivePort = ReceivePort();
    ThreadParams threadParams = ThreadParams(2000, _receivePort.sendPort);
    _isolate = await Isolate.spawn(
      _isolateHandler,
      threadParams,
    );
    _receivePort.listen(_handleMessage, onDone: () {
      setState(() {
        _threadStatus = 'Stopped';
      });
    });
  }

  void _pause() {
    if (null != _isolate) {
      _paused ? _isolate.resume(_capability) : _capability = _isolate.pause();
      setState(() {
        _paused = !_paused;
        _threadStatus = _paused ? 'Paused' : 'Resumed';
      });
    }
  }

  void _stop() {
    if (null != _isolate) {
      setState(() {
        _running = false;
      });
      _receivePort.close();
      _isolate.kill(priority: Isolate.immediate);
      _isolate = null;
    }
  }

  void _handleMessage(dynamic data) {
    setState(() {
      _message = data;
    });
  }

  static void _isolateHandler(ThreadParams threadParams) async {
    heavyOperation(threadParams);
  }

  static void heavyOperation(ThreadParams threadParams) async {
    int count = 10000;
    while (true) {
      int sum = 0;
      for (int i = 0; i < count; i++) {
        sum += await computeSum(1000);
      }
      count += threadParams.val;
      threadParams.sendPort.send(sum.toString());
    }
  }

  static Future<int> computeSum(int num) {
    Random random = Random();
    return Future(() {
      int sum = 0;
      for (int i = 0; i < num; i++) {
        sum += random.nextInt(100);
      }
      return sum;
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Container(
        padding: EdgeInsets.all(20.0),
        alignment: Alignment.center,
        child: new Column(
          children: <Widget>[
            !_running
                ? OutlineButton(
                    child: Text('Start Isolate'),
                    onPressed: () {
                      _start();
                    },
                  )
                : SizedBox(),
            _running
                ? OutlineButton(
                    child: Text(_paused ? 'Resume Isolate' : 'Pause Isolate'),
                    onPressed: () {
                      _pause();
                    },
                  )
                : SizedBox(),
            _running
                ? OutlineButton(
                    child: Text('Stop Isolate'),
                    onPressed: () {
                      _stop();
                    },
                  )
                : SizedBox(),
            SizedBox(
              height: 20.0,
            ),
            Text(
              _threadStatus,
              style: TextStyle(
                fontSize: 20.0,
              ),
            ),
            SizedBox(
              height: 20.0,
            ),
            Text(
              _message,
              style: TextStyle(
                fontSize: 20.0,
                color: Colors.green,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class ThreadParams {
  ThreadParams(this.val, this.sendPort);
  int val;
  SendPort sendPort;
}

That’s it.

Please clap if you find this article useful.

flutter mobile-apps programming developer

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

How long does it take to develop/build an app?

This article covers A-Z about the mobile and web app development process and answers your question on how long does it take to develop/build an app.

Top Mobile App Developers & Leading App Development Companies in UK

Profusely examined top Mobile App Development companies in UK with ratings & reviews to help find the best Mobile App Development solution providers.

Top 25 Flutter Mobile App Templates in 2020

Flutter has been booming worldwide from the past few years. While there are many popular mobile app development technologies out there, Flutter has managed to leave its mark in the mobile application development world. In this article, we’ve curated the best Flutter app templates available on the market as of July 2020.

Mobile App Development North Carolina

Mobile App Development North Carolina In the era of globalization, technology has forced the businesses and industries to jump into the space of competition. Technology has both tangible and intangible benefits that help businesses from different ind...

Top 7 Mobile App Development Companies in Delhi NCR

Looking for a Mobile app development company in Delhi NCR? Here it a list of top mobile app development companies in Delhi for Android & iOS app Development.