Flutter: How can I run a function on background thread in dart Flutter: How can I run a function on background thread in dart flutter flutter

Flutter: How can I run a function on background thread in dart


1. Use Future

You can use the async version of the readAsBytes.

So instead of:

final imageData = _image.readAsBytesSync();_base64 = base64.encode(imageData);

You could have:

final imageData = await _image.readAsBytes();_base64 = base64.encode(imageData);

2. Use Isolate

In your code, it may not necessarily be the readAsBytes line that is slow. It might be the base 64 encodings of the image. If that's the case, you could put the entire computation into a separate isolate. There is a convenient method compute that you can use.

// This needs to be a global functionencodeImage(File imageFile) {    return base64.encodeimageFile.readAsBytesSync());}
Future setPrefs() async { _base64 = await compute(encodeImage, _image); print(_base64); final prefs = await SharedPreferences.getInstance(); prefs.setString(IMAGE_KEY, _base64);}

In addition, it is worth mentioning that SharedPreferences (for Android, aka, NSUserDefaults on iOS) is designed to store small user settings. It is not designed for storing the images, which could be megabytes big. It is better to copy the image file into the app's document folder, and only store the filename in the SharedPreferences.


Since Flutter is single-threaded and runs an event loop (like Node.js), you don’t have to worry about thread management or spawning background threads. If you’re doing I/O-bound work, such as disk access or a network call, then you can safely use async/await and you’re done. If, on the other hand, you need to do computationally intensive work that keeps the CPU busy, you want to move it to an Isolate to avoid blocking the event loop.

For I/O-bound work, declare the function as an async function, and await on long-running tasks inside the function:

loadData() async {  String dataURL = "https://jsonplaceholder.typicode.com/posts";  http.Response response = await http.get(dataURL);  setState(() {    widgets = jsonDecode(response.body);  });}

This is how you typically do network or database calls, which are both I/O operations.

Isolates are separate execution threads that do not share any memory with the main execution memory heap. This means you can’t access variables from the main thread, or update your UI by calling setState(). Isolates are true to their name, and cannot share memory (in the form of static fields, for example).

Here, dataLoader() is the Isolate that runs in its own separate execution thread. In the isolate you can perform more CPU intensive processing (parsing a big JSON, for example), or perform computationally intensive math, such as encryption or signal processing.

You can run the full example below:

import 'dart:convert';import 'package:flutter/material.dart';import 'package:http/http.dart' as http;import 'dart:async';import 'dart:isolate';void main() {  runApp(SampleApp());}class SampleApp extends StatelessWidget {  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Sample App',      theme: ThemeData(        primarySwatch: Colors.blue,      ),      home: SampleAppPage(),    );  }}class SampleAppPage extends StatefulWidget {  SampleAppPage({Key key}) : super(key: key);  @override  _SampleAppPageState createState() => _SampleAppPageState();}class _SampleAppPageState extends State<SampleAppPage> {  List widgets = [];  @override  void initState() {    super.initState();    loadData();  }  showLoadingDialog() {    if (widgets.length == 0) {      return true;    }    return false;  }  getBody() {    if (showLoadingDialog()) {      return getProgressDialog();    } else {      return getListView();    }  }  getProgressDialog() {    return Center(child: CircularProgressIndicator());  }  @override  Widget build(BuildContext context) {    return Scaffold(        appBar: AppBar(          title: Text("Sample App"),        ),        body: getBody());  }  ListView getListView() => ListView.builder(      itemCount: widgets.length,      itemBuilder: (BuildContext context, int position) {        return getRow(position);      });  Widget getRow(int i) {    return Padding(      padding: EdgeInsets.all(10.0),      child: Text("Row ${widgets[i]["title"]}"),    );  }  loadData() async {    ReceivePort receivePort = ReceivePort();    await Isolate.spawn(dataLoader, receivePort.sendPort);    // The 'echo' isolate sends its SendPort as the first message    SendPort sendPort = await receivePort.first;    List msg = await sendReceive(      sendPort,      "https://jsonplaceholder.typicode.com/posts",    );    setState(() {      widgets = msg;    });  }// the entry point for the isolate  static dataLoader(SendPort sendPort) async {    // Open the ReceivePort for incoming messages.    ReceivePort port = ReceivePort();    // Notify any other isolates what port this isolate listens to.    sendPort.send(port.sendPort);    await for (var msg in port) {      String data = msg[0];      SendPort replyTo = msg[1];      String dataURL = data;      http.Response response = await http.get(dataURL);      // Lots of JSON to parse      replyTo.send(jsonDecode(response.body));    }  }  Future sendReceive(SendPort port, msg) {    ReceivePort response = ReceivePort();    port.send([msg, response.sendPort]);    return response.first;  }}