Home > Enterprise >  Flutter: Animations badly slow down disk write speed
Flutter: Animations badly slow down disk write speed

Time:10-15

Not sure if this is a bug or just how the things work, or me doing something wrong.

I'm making an app which can parse text files for some data and then store it in a sqlite database. At some point I decided to add basic spinner to indicate that there is parsing in progress, cause it usually takes few seconds on an average file.

So I added a ternary operator which renders CircularProgressIndicator() if isBusy variable is set to true. And my parsing time suddenly increased to about 10 times of what it was before. That's on Linux. On Android it also slows down process but only for additional ~70%. I checked few things and it looks like any animation causes this problem, e.g. AnimatedContainer.

Steps to reproduce:

  1. Run the code below, notice the completion time in dialog.
  2. Uncomment CircularProgressIndicator() or AnimatedContainer block and run the code again. Notice how much longer it takes now.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

const Color darkBlue = Color.fromARGB(255, 18, 32, 47);

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidget();
}

class _MyWidget extends State<MyWidget> {
  var _width = 50.0;
  var _height = 50.0;

  void startHeavyOperation() async {
    final directory = await getApplicationDocumentsDirectory();
    var myFile = File('${directory.path}/test.txt');

    const max = 10000;
    var x = 0;

    setState(() {
      _width = 300;
      _height = 300;
    });

    final startTime = DateTime.now();

    while (x < max) {
      await myFile.writeAsString('$x\n', mode: FileMode.append);
      x  = 1;
    }

    final endTime = DateTime.now();
    final durationInMilliseconds = endTime.difference(startTime).inMilliseconds;

    showDialog(
      context: context,
      builder: (ctx) => AlertDialog(
        title: Text('It took $durationInMilliseconds ms'),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () => startHeavyOperation(),
            child: const Text('startHeavyOperation'),
          ),
          // AnimatedContainer(
          //   duration: Duration(seconds: 10),
          //   child: Text('123'),
          //   color: Colors.red,
          //   width: _width,
          //   height: _height,
          // ),

          // CircularProgressIndicator(),
        ],
      ),
    );
  }
}

My question is: is there a way to use animations w/o slowing disk writes?

CodePudding user response:

Yeah - I suspect it is the animation indeed. Try putting the heavy operation in an isolate - I suspect that will speed things up (on the device). Here's an example.

CodePudding user response:

That while statement is very expensive even without the animation. Putting in a separate isolate will save you some time. Here is a quick modification to your code example. compute will give you a future.


void startHeavyOperation(String path) async {

  var myFile = File('$path/test.txt');

  const max = 10000;
  var x = 0;

  final startTime = DateTime.now();

  while (x < max) {
    await myFile.writeAsString('$x\n', mode: FileMode.append);
    x  = 1;
  }

  final endTime = DateTime.now();
  final durationInMilliseconds = endTime.difference(startTime).inMilliseconds;

  print('It took $durationInMilliseconds ms');
}

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidget();
}

class _MyWidget extends State<MyWidget> {
  var _width = 50.0;
  var _height = 50.0;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ElevatedButton(
            onPressed: () async {
              final directory = await getApplicationDocumentsDirectory();
              compute(startHeavyOperation, directory.path);
            },
            child: const Text('startHeavyOperation'),
          ),
          // AnimatedContainer(
          //   duration: Duration(seconds: 10),
          //   child: Text('123'),
          //   color: Colors.red,
          //   width: _width,
          //   height: _height,
          // ),
          //
          CircularProgressIndicator(),
        ],
      ),
    );
  }
}

  • Related