Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image assets load is slow #70527

Closed
mikeRozen opened this issue Nov 14, 2020 · 19 comments
Closed

Image assets load is slow #70527

mikeRozen opened this issue Nov 14, 2020 · 19 comments
Labels
in triage Presently being triaged by the triage team

Comments

@mikeRozen
Copy link

mikeRozen commented Nov 14, 2020

Hi,

My local image assets loading is slow, it hapens on the first screen/page on IOS simulator (I didnt tried on other pages or on Android ). I tried all possible solution on stack (like caching etc with no help). I think that currently its unpossible to run in production mode in simulator

Steps to Reproduce

  1. Create an app add image on the first screen (its not mandatory to have high resolution image)

Expected results: The images should appear as the screen loads

Actual results: Images appear with short delay

Logs

logs_flutter_doctor.txt
logs_flutter_analyze.txt
logs_verboose.txt

[slow image lod](https://user-images.githubusercontent.com/11506268/99142480-f807b200-265d-11eb-83e7-3e37bd04f665.gif) As you can see the background image and the logo image both have a delay, I also tried to precache the image
static Image getImage(String imageName, double width, double height) {
    String fullImageName = 'images/' + imageName + '.png';
    return Image(
      image: AssetImage(fullImageName),
      width: width,
      height: height,
      gaplessPlayback: true,
    );
  }

I also tried to use caching

void initState() {
    super.initState();
    _logoImg = Styles.getImage('mainIcon', 39, 45);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    precacheImage(_logoImg.image, context);
  }

Thanks for your help.

@iapicca
Copy link
Contributor

iapicca commented Nov 14, 2020

@mikeRozen
can you provide a minimal code sample?
the issue might depend from many factors, like the implementation of the assets size

also you might want to run your app with the flag --release
in debug mode your app is slower

@mikeRozen
Copy link
Author

mikeRozen commented Nov 14, 2020

@iapicca
Dont want to pollute with a lot of code:

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      backgroundColor: Theme.of(context).primaryColor,
      body: Stack(
        children: [
          Styles.getImage('BackGround', Styles.screenWidth, Styles.screenHeight);   
      ],
      ),
    );
  }
static Image getImage(String imageName, double width, double height) {
    String fullImageName = 'images/' + imageName + '.png';

    return Image(
      image: AssetImage(fullImageName),
      width: Styles.swf(width),//I can set the size directly same result 
      height: Styles.shf(height),
      gaplessPlayback: true,
      fit: BoxFit.fill,
    );
  }

regarding the image size the background image is 24KB
and the logo is 691 byte

AFAIK I cant run in release mode on the IOS simultor (correct me if I am wrong)

@iapicca
Copy link
Contributor

iapicca commented Nov 14, 2020

@mikeRozen
the size of the images seem very reasonable
release mode might not be possible on ios simulator, but generally ios should support it
I don't see this restriction in the docs
Regardless, If you don't have the possibility of reproducing the issue in release mode
I recommend to provide a "runnable" code sample, so that the issue can be triaged properly

@mikeRozen
Copy link
Author

@iapicca
Sure, is it ok if I send you the code to iapicca@gmail.com?

@iapicca
Copy link
Contributor

iapicca commented Nov 15, 2020

not really,
the code sample (not your production code) should be available for the triage process,
you can post it here the link to a github repository, attaching it as a file
or if it's concise, as it should be, just copy paste it here

@TahaTesser
Copy link
Member

Hi @mikeRozen
Can you please provide a minimal complete reproducible code sample and comment it below?
Thank you

@TahaTesser TahaTesser added in triage Presently being triaged by the triage team waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds labels Nov 16, 2020
@pedromassangocode pedromassangocode removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Dec 9, 2020
@pedromassangocode
Copy link

Without additional information, we are unfortunately not sure how to resolve this issue.
We are therefore reluctantly going to close this bug for now.
Please don't hesitate to comment on the bug if you have any more information for us; we will reopen it right away!
Thanks for your contribution.

Could everyone who still has this problem please file a new issue with the exact description of what happens, logs, and the output of flutter doctor -v.
All system setups can be slightly different, so it's always better to open new issues and reference related issues.

@mikeRozen
Copy link
Author

mikeRozen commented Dec 9, 2020

My apologies for the late response @pedromassangocode , @TahaTesser , @iapicca
So just upgraded to last flutter version 1.22.4. Created a new project, set a background color for Scaffold, and added image, it's very easy to see that the background color is seen for a split of a second, and then the image gets loaded (iPhone Simulator 11 pro max) Sample code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
        // This makes the visual density adapt to the platform that you run
        // the app on. For desktop platforms, the controls will be smaller and
        // closer together (more dense) than on mobile platforms.
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    MediaQueryData md = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
    return Scaffold(
      backgroundColor: Colors.red,
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Stack(
        children: [
          getImage('BackGround', md.size.width, md.size.height),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Image getImage(String imageName, double width, double height, {BoxFit fit = BoxFit.cover}) {
  String fullImageName = 'images/' + imageName + '.png';

  return Image(
    image: AssetImage(fullImageName),
    width: width,
    height: height,
    gaplessPlayback: true,
    fit: fit,
  );
}

@mikeRozen
Copy link
Author

Please note after that the image get cached so opening a new screen with same background image will not have this delay. Its happens on the first time the image get loaded (which is the first screen and the first impression of the app)

@TahaTesser
Copy link
Member

Hi @mikeRozen
I just tried to reproduce the using your code sample, I see no delay at all |
video.zip

flutter doctor -v
[✓] Flutter (Channel stable, 1.22.4, on Microsoft Windows [Version 10.0.19042.630], locale en-US)
    • Flutter version 1.22.4 at C:\Code\flutter_stable
    • Framework revision 1aafb3a8b9 (4 weeks ago), 2020-11-13 09:59:28 -0800
    • Engine revision 2c956a31c0
    • Dart version 2.10.4


[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at C:\Code\sdk
    • Platform android-30, build-tools 30.0.3
    • ANDROID_HOME = C:\Code\sdk
    • Java binary at: C:\Code\android-studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    • All Android licenses accepted.

[!] Android Studio (version 4.1.0)
    • Android Studio at C:\Code\android-studio
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)

[✓] VS Code (version 1.51.1)
    • VS Code at C:\Users\Taha\AppData\Local\Programs\Microsoft VS Code
    • Flutter extension version 3.17.0

[✓] Connected device (1 available)
    • sdk gphone x86 (mobile) • emulator-5554 • android-x86 • Android 11 (API 30) (emulator)

! Doctor found issues in 1 category.

@iapicca
Copy link
Contributor

iapicca commented Dec 10, 2020

@mikeRozen
ImageProvider has to load images somehow, regardless if it's AssetImage or NetworkImage;
it might appear instantaneous in some cases, but it uses an ImageStream,
so it is expected that a lag might occur depending from hardware, asset, network, implementation and so on.

I believe you already know that, as the title of the issue is Image assets load is slow ,
so assuming that we all agree that a lag is possible and intended
and it's up to the developer to deal with loading, placeholders and so on
(maybe with the help of some reliable 3rd party package)

I'm not sure what slow means in this case,
here some steps for minimal benchmark:

set up
flutter channel master
flutter upgrade -f
flutter create img_bench
cd img_bench
mkdir assets
cd assets
wget https://flutter.dev/assets/homepage/carousel/slide_1-bg-4e2fcef9a7343692a5f7784d68241a786c57c79d55f0fe37e6b82a653d146b93.jpg
mv slide_1-bg-4e2fcef9a7343692a5f7784d68241a786c57c79d55f0fe37e6b82a653d146b93.jpg canyon.jpg
cd ..
echo -e '\n  assets:\n   - canyon.jpg' >> pubspec.yaml
code sample

replace main.dart with the following

import 'package:flutter/material.dart';

void main() => runApp(
      const MaterialApp(
        home: Material(
          child: Center(
            child: MyImage(
              imageProvider: AssetImage( 'canyon.jpg'),
            ),
          ),
        ),
      ),
    );

/// code below edited from `https://api.flutter.dev/flutter/painting/ImageProvider-class.html#painting.ImageProvider.1`
/// comment removed, new comments above the edited lines

class MyImage extends StatefulWidget {
  const MyImage({
    Key key,
    @required this.imageProvider,
  })  : assert(imageProvider != null),
        super(key: key);

  final ImageProvider imageProvider;

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

class _MyImageState extends State<MyImage> {
  ImageStream _imageStream;
  ImageInfo _imageInfo;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _getImage();
  }

  @override
  void didUpdateWidget(MyImage oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.imageProvider != oldWidget.imageProvider) _getImage();
  }

  void _getImage() {
    /// added line for pseudo bencchmark
    print('get image: ${DateTime.now()}');
    final ImageStream oldImageStream = _imageStream;
    _imageStream =
        widget.imageProvider.resolve(createLocalImageConfiguration(context));
    if (_imageStream.key != oldImageStream?.key) {
      final ImageStreamListener listener = ImageStreamListener(_updateImage);
      oldImageStream?.removeListener(listener);
      _imageStream.addListener(listener);
    }
  }

  void _updateImage(ImageInfo imageInfo, bool synchronousCall) {
    setState(() {
      /// added line for pseudo bencchmark
      print('update image: ${DateTime.now()}');
      _imageInfo = imageInfo;
    });
  }

  @override
  void dispose() {
    _imageStream.removeListener(ImageStreamListener(_updateImage));
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return RawImage(
      image: _imageInfo?.image,
      scale: _imageInfo?.scale ?? 1.0,
    );
  }
}
logs
flutter run --release -v
[   +4 ms] ✓ Built build/app/outputs/flutter-apk/app-release.apk (5.7MB).
[   +5 ms] executing: /home/francesco/Android/Sdk/build-tools/30.0.2/aapt dump xmltree /home/francesco/projects/imageprovider_bench/build/app/outputs/flutter-apk/app.apk AndroidManifest.xml
[   +8 ms] Exit code 0 from: /home/francesco/Android/Sdk/build-tools/30.0.2/aapt dump xmltree /home/francesco/projects/imageprovider_bench/build/app/outputs/flutter-apk/app.apk AndroidManifest.xml
[        ] N: android=http://schemas.android.com/apk/res/android
             E: manifest (line=2)
               A: android:versionCode(0x0101021b)=(type 0x10)0x1
               A: android:versionName(0x0101021c)="1.0.0" (Raw: "1.0.0")
               A: android:compileSdkVersion(0x01010572)=(type 0x10)0x1e
               A: android:compileSdkVersionCodename(0x01010573)="11" (Raw: "11")
               A: package="com.example.imageprovider_bench" (Raw: "com.example.imageprovider_bench")
               A: platformBuildVersionCode=(type 0x10)0x1e
               A: platformBuildVersionName=(type 0x10)0xb
               E: uses-sdk (line=7)
                 A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
                 A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1e
               E: application (line=11)
                 A: android:label(0x01010001)="imageprovider_bench" (Raw: "imageprovider_bench")
                 A: android:icon(0x01010002)=@0x7f080000
                 A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory" (Raw: "androidx.core.app.CoreComponentFactory")
                 E: activity (line=15)
                   A: android:theme(0x01010000)=@0x7f0a0000
                   A: android:name(0x01010003)="com.example.imageprovider_bench.MainActivity" (Raw: "com.example.imageprovider_bench.MainActivity")
                   A: android:launchMode(0x0101001d)=(type 0x10)0x1
                   A: android:configChanges(0x0101001f)=(type 0x11)0x40003fb4
                   A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
                   A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
                   E: meta-data (line=29)
                     A: android:name(0x01010003)="io.flutter.embedding.android.NormalTheme" (Raw: "io.flutter.embedding.android.NormalTheme")
                     A: android:resource(0x01010025)=@0x7f0a0001
                   E: meta-data (line=39)
                     A: android:name(0x01010003)="io.flutter.embedding.android.SplashScreenDrawable" (Raw: "io.flutter.embedding.android.SplashScreenDrawable")
                     A: android:resource(0x01010025)=@0x7f040000
                   E: intent-filter (line=43)
                     E: action (line=44)
                       A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
                     E: category (line=46)
                       A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
                 E: meta-data (line=53)
                   A: android:name(0x01010003)="flutterEmbedding" (Raw: "flutterEmbedding")
                   A: android:value(0x01010024)=(type 0x10)0x2
[   +2 ms] Stopping app 'app.apk' on Pixel 3a.
[   +1 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell am force-stop com.example.imageprovider_bench
[ +128 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell pm list packages com.example.imageprovider_bench
[ +106 ms] package:com.example.imageprovider_bench
[   +5 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell cat /data/local/tmp/sky.com.example.imageprovider_bench.sha1
[  +87 ms] 5cf835028649157d90a0fae0dc9be0ba11ab6c84
[   +1 ms] Installing APK.
[   +4 ms] Installing build/app/outputs/flutter-apk/app.apk...
[   +1 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C install -t -r /home/francesco/projects/imageprovider_bench/build/app/outputs/flutter-apk/app.apk
[+1578 ms] Performing Streamed Install
                    Success
[   +3 ms] Installing build/app/outputs/flutter-apk/app.apk... (completed in 1,579ms)
[   +3 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell echo -n 2532e7e0a388f0e5f153ce520991e2da92c00625 > /data/local/tmp/sky.com.example.imageprovider_bench.sha1
[  +42 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell am start -a android.intent.action.RUN -f 0x20000000 --ez enable-background-compilation true --ez
enable-dart-profiling true com.example.imageprovider_bench/com.example.imageprovider_bench.MainActivity
[  +72 ms] Starting: Intent { act=android.intent.action.RUN flg=0x20000000 cmp=com.example.imageprovider_bench/.MainActivity (has extras) }
[   +2 ms] Application running.
[   +3 ms] Flutter run key commands.
[   +3 ms] h Repeat this help message.
[   +1 ms] c Clear the screen
[        ] q Quit (terminate the application on the device).
[ +493 ms] I/flutter (17301): get image: 2020-12-10 16:39:42.015517
[  +55 ms] I/flutter (17301): update image: 2020-12-10 16:39:42.071453

results about 55 milliseconds

flutter clean
flutter run -v
[   +4 ms] Installing build/app/outputs/flutter-apk/app.apk...
[   +1 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C install -t -r /home/francesco/projects/imageprovider_bench/build/app/outputs/flutter-apk/app.apk
[+4778 ms] Performing Streamed Install
                    Success
[        ] Installing build/app/outputs/flutter-apk/app.apk... (completed in 4.8s)
[   +1 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell echo -n a8aa09b27150753efb8b25b03c0438a863d63531 > /data/local/tmp/sky.com.example.imageprovider_bench.sha1
[  +37 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell -x logcat -v time -t 1
[  +46 ms] --------- beginning of main
           12-10 16:42:20.058 I/Finsky  (15319): [665] hck.a(3): Cancelled 0 ongoing asset module downloads for package com.example.imageprovider_bench due to a concurrent app update.
[  +31 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C shell am start -a android.intent.action.RUN -f 0x20000000 --ez enable-background-compilation true --ez
enable-dart-profiling true --ez enable-checked-mode true --ez verify-entry-points true com.example.imageprovider_bench/com.example.imageprovider_bench.MainActivity
[  +82 ms] Starting: Intent { act=android.intent.action.RUN flg=0x20000000 cmp=com.example.imageprovider_bench/.MainActivity (has extras) }
[   +1 ms] Waiting for observatory port to be available...
[+1179 ms] Observatory URL on device: http://127.0.0.1:38473/X1GJQpK7ibw=/
[   +4 ms] executing: /home/francesco/Android/Sdk/platform-tools/adb -s 965AY0WP5C forward tcp:0 tcp:38473
[  +18 ms] 38853
[        ] Forwarded host port 38853 to device port 38473 for Observatory
[   +7 ms] Caching compiled dill
[ +137 ms] Connecting to service protocol: http://127.0.0.1:38853/X1GJQpK7ibw=/
[   +2 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:38853/X1GJQpK7ibw=/.
[ +710 ms] DDS is listening at http://127.0.0.1:41781/1j02Gn7D4zg=/.
[  +64 ms] Successfully connected to service protocol: http://127.0.0.1:38853/X1GJQpK7ibw=/
[  +23 ms] DevFS: Creating new filesystem on the device (null)
[  +37 ms] DevFS: Created new filesystem on the device (file:///data/user/0/com.example.imageprovider_bench/code_cache/imageprovider_benchNDAONF/imageprovider_bench/)
[  +10 ms] Updating assets
[ +118 ms] Syncing files to device Pixel 3a...
[   +1 ms] <- reset
[        ] Compiling dart to kernel with 0 updated files
[   +1 ms] <- recompile package:imageprovider_bench/main.dart 72588266-b6a0-4415-a0b5-40f2977df76e
[        ] <- 72588266-b6a0-4415-a0b5-40f2977df76e
[ +105 ms] Updating files.
[        ] DevFS: Sync finished
[        ] Syncing files to device Pixel 3a... (completed in 110ms)
[        ] Synced 0.0MB.
[        ] <- accept
[  +18 ms] Connected to _flutterView/0x77fe15de60.
[   +1 ms] Flutter run key commands.
[   +1 ms] r Hot reload. 🔥🔥🔥
[        ] R Hot restart.
[        ] h Repeat this help message.
[        ] d Detach (terminate "flutter run" but leave application running).
[        ] c Clear the screen
[        ] q Quit (terminate the application on the device).
[        ] An Observatory debugger and profiler on Pixel 3a is available at: http://127.0.0.1:41781/1j02Gn7D4zg=/
[        ] Running with unsound null safety
[        ] For more information see https://dart.dev/null-safety/unsound-null-safety
[ +201 ms] I/flutter (17808): get image: 2020-12-10 16:42:22.843361
[ +427 ms] I/flutter (17808): update image: 2020-12-10 16:42:23.278589

results about 435 milliseconds

doctor
[✓] Flutter (Channel master, 1.25.0-5.0.pre.141, on Linux, locale en_US.UTF-8)
    • Flutter version 1.25.0-5.0.pre.141 at /home/francesco/snap/flutter/common/flutter
    • Framework revision 36bed2b4c3 (14 hours ago), 2020-12-09 20:13:04 -0500
    • Engine revision 8518a5bbe6
    • Dart version 2.12.0 (build 2.12.0-135.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at /home/francesco/Android/Sdk
    • Platform android-30, build-tools 30.0.2
    • Java binary at: /snap/android-studio/current/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Chrome - develop for the web
    • Chrome at google-chrome

[✓] Linux toolchain - develop for Linux desktop
    • clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
    • cmake version 3.10.2
    • ninja version 1.8.2
    • pkg-config version 0.29.1

[✓] Android Studio
    • Android Studio at /snap/android-studio/current/android-studio
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • android-studio-dir = /snap/android-studio/current/android-studio
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] Connected device (3 available)
    • Pixel 3a (mobile) • 965AY0WP5C • android-arm64  • Android 11 (API 30)
    • Linux (desktop)   • linux      • linux-x64      • Linux
    • Chrome (web)      • chrome     • web-javascript • Google Chrome 87.0.4280.88

• No issues found!

what result are you getting from this pseudo benchmark?

@mikeRozen
Copy link
Author

mikeRozen commented Dec 10, 2020

First of all, thanks a lot for your help.
The channel master definitely loads the image faster than the stable one, but its still very easy to reproduce especially on Iphone (on android its faster but the delay is still visible)
@iapicca I slightly changed your code to emphasize that the background color is the first that get loaded and only then we can see the image.(I didn't create a new proj, I copy-pasted your code in the sample proj I shared last time)

Sample code

import 'package:flutter/material.dart';

void main() => runApp(
      const MaterialApp(
        home: Material(
          child: Center(
            child: MyImage(
              imageProvider: AssetImage('images/canyon.jpg'),
            ),
          ),
        ),
      ),
    );

/// code below edited from `https://api.flutter.dev/flutter/painting/ImageProvider-class.html#painting.ImageProvider.1`
/// comment removed, new comments above the edited lines

class MyImage extends StatefulWidget {
  const MyImage({
    Key key,
    @required this.imageProvider,
  })  : assert(imageProvider != null),
        super(key: key);

  final ImageProvider imageProvider;

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

class _MyImageState extends State<MyImage> {
  ImageStream _imageStream;
  ImageInfo _imageInfo;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _getImage();
  }

  @override
  void didUpdateWidget(MyImage oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.imageProvider != oldWidget.imageProvider) _getImage();
  }

  void _getImage() {
    /// added line for pseudo bencchmark
    print('get image: ${DateTime.now()}');
    final ImageStream oldImageStream = _imageStream;
    _imageStream = widget.imageProvider.resolve(createLocalImageConfiguration(context));
    if (_imageStream.key != oldImageStream?.key) {
      final ImageStreamListener listener = ImageStreamListener(_updateImage);
      oldImageStream?.removeListener(listener);
      _imageStream.addListener(listener);
    }
  }

  void _updateImage(ImageInfo imageInfo, bool synchronousCall) {
    setState(() {
      /// added line for pseudo bencchmark
      print('update image: ${DateTime.now()}');
      _imageInfo = imageInfo;
    });
  }

  @override
  void dispose() {
    _imageStream.removeListener(ImageStreamListener(_updateImage));
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    MediaQueryData md = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
    return Scaffold(
      backgroundColor: Colors.red,
      body: Stack(
        children: [
          Container(
            height: md.size.height,
            width: md.size.width,
            child: RawImage(
              image: _imageInfo?.image,
              scale: _imageInfo?.scale ?? 1.0,
              fit: BoxFit.fill,
            ),
          )
        ],
      ),
    );
  }
}
flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel master, 1.25.0-9.0.pre.19, on Mac OS X 10.15.1 19B88 darwin-x64, locale en-IL)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[!] Xcode - develop for iOS and macOS (Xcode 11.2.1)
    ! CocoaPods 1.8.1 out of date (1.9.0 is recommended).
        CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
        Without CocoaPods, plugins will not work on iOS or macOS.
        For more info, see https://flutter.dev/platform-plugins
      To upgrade see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.1)
[✓] Connected device (3 available)

! Doctor found issues in 1 category.

I didn't try it in release mode, from your logs I see that it's almost 9x faster so I tend to believe we won't feel it in production (hope so as my image 8x smaller than yours ).

Regarding the slow I don't have a precise definition. I think in the perspective of user experience, all the visible ui widgets should be loaded at "the same time" ( in terms of that the user should not feel the difference)
Please have a look at the attached video in the next comment.

Thanks again.

flutter_run_v.txt

@mikeRozen
Copy link
Author

@TahaTesser attaching video with @iapicca code
Screen Recording low.mov.zip

@iapicca
Copy link
Contributor

iapicca commented Dec 10, 2020

@mikeRozen

I didn't try it in release mode, from your logs I see that it's almost 9x faster so I tend to believe we won't feel it in production

the reason why I posted a comparison between release and debug
was to emphasize the difference of performance between the 2,
but bench marking in debug is in my opinion pointless, please run in profile or release
and makes even less sense on an emulator

[...] all the visible ui widgets should be loaded at "the same time" ( in terms of that the user should not feel the difference)

as mentioned above, this is not how the framework is designed;
it's developers choice to decide to delay the page until all the images are loaded,
but I don't see this implementation in your code

lastly, something might be wrong in the logs, I don't see the print for print('get image: ${DateTime.now()}');

/Users/user_name/AndroidStudioProjects/flutter_app_image_load/build/ios/iphonesimulator/Runner.app
[ +939 ms] executing: /usr/bin/plutil -convert json -o - /Users/user_name/AndroidStudioProjects/flutter_app_image_load/build/ios/iphonesimulator/Runner.app/Info.plist
[   +7 ms] Exit code 0 from: /usr/bin/plutil -convert json -o -
/Users/user_name/AndroidStudioProjects/flutter_app_image_load/build/ios/iphonesimulator/Runner.app/Info.plist
[        ]
{"CFBundleName":"flutter_app_image_load","DTXcode":"1120","DTSDKName":"iphonesimulator13.2","UILaunchStoryboardName":"LaunchScreen","CFBundleIcons~ipad":{"CFBundlePrimaryIco
n":{"CFBundleIconFiles":["AppIcon20x20","AppIcon29x29","AppIcon40x40","AppIcon60x60","AppIcon76x76","AppIcon83.5x83.5"],"CFBundleIconName":"AppIcon"}},"DTSDKBuild":"17B102",
"CFBundleDevelopmentRegion":"en","CFBundleVersion":"1","BuildMachineOSBuild":"19B88","DTPlatformName":"iphonesimulator","CFBundlePackageType":"APPL","UIMainStoryboardFile":"
Main","CFBundleSupportedPlatforms":["iPhoneSimulator"],"CFBundleShortVersionString":"1.0.0","CFBundleInfoDictionaryVersion":"6.0","CFBundleExecutable":"Runner","DTCompiler":
"com.apple.compilers.llvm.clang.1_0","UISupportedInterfaceOrientations~ipad":["UIInterfaceOrientationPortrait","UIInterfaceOrientationPortraitUpsideDown","UIInterfaceOrienta
tionLandscapeLeft","UIInterfaceOrientationLandscapeRight"],"MinimumOSVersion":"9.0","CFBundleIdentifier":"com.flutterAppImageLoad","UIDeviceFamily":[1,2],"DTPlatformVersion"
:"13.2","CFBundleSignature":"????","CFBundleIcons":{"CFBundlePrimaryIcon":{"CFBundleIconFiles":["AppIcon20x20","AppIcon29x29","AppIcon40x40","AppIcon60x60"],"CFBundleIconNam
e":"AppIcon"}},"DTXcodeBuild":"11B500","LSRequiresIPhoneOS":true,"UISupportedInterfaceOrientations":["UIInterfaceOrientationPortrait","UIInterfaceOrientationLandscapeLeft","
UIInterfaceOrientationLandscapeRight"],"UIViewControllerBasedStatusBarAppearance":false,"NSBonjourServices":["_dartobservatory._tcp"],"DTPlatformBuild":"17B102","NSLocalNetw
orkUsageDescription":"Allow Flutter tools on your computer to connect and debug your application. This prompt will not appear on release builds."}
[   +3 ms] executing: xcrun simctl launch C42DDFF8-071E-48C7-9D43-169E58C63215 com.flutterAppImageLoad --enable-dart-profiling --enable-checked-mode --verify-entry-points
--observatory-port=0
[ +342 ms] com.flutterAppImageLoad: 30429
[        ] Waiting for observatory port to be available...
[+2076 ms] Observatory URL on device: http://127.0.0.1:49416/scAyZt5rzgs=/
[  +15 ms] Caching compiled dill
[ +218 ms] Connecting to service protocol: http://127.0.0.1:49416/scAyZt5rzgs=/
[   +4 ms] Launching a Dart Developer Service (DDS) instance at http://127.0.0.1:0, connecting to VM service at http://127.0.0.1:49416/scAyZt5rzgs=/.
[ +236 ms] DDS is listening at http://127.0.0.1:49425/M4KbxYrcQ_s=/.
[  +96 ms] Successfully connected to service protocol: http://127.0.0.1:49416/scAyZt5rzgs=/
[  +13 ms] DevFS: Creating new filesystem on the device (null)
[  +14 ms] DevFS: Created new filesystem on the device
(file:///Users/user_name/Library/Developer/CoreSimulator/Devices/C42DDFF8-071E-48C7-9D43-169E58C63215/data/Containers/Data/Application/A90696DE-46E0-4B55-8B27-82264A2
DFE2F/tmp/flutter_app_image_loadoJLFdY/flutter_app_image_load/)
[   +3 ms] Updating assets
[ +108 ms] Manifest contained wildcard assets. Inserting missing file into build graph to force rerun. for more information see #56466.
[   +6 ms] Syncing files to device iPhone 11 Pro Max...
[   +2 ms] <- reset
[        ] Compiling dart to kernel with 0 updated files
[   +4 ms] <- recompile package:flutter_app_image_load/main.dart c582ae0c-d265-43c8-967c-4e4fb8ed2cb1
[        ] <- c582ae0c-d265-43c8-967c-4e4fb8ed2cb1
[   +1 ms] flutter: get image: 2020-12-10 22:23:55.545693
[ +120 ms] Updating files.
[        ] DevFS: Sync finished
[        ] Syncing files to device iPhone 11 Pro Max... (completed in 129ms)
[        ] Synced 0.0MB.
[   +1 ms] <- accept
[   +6 ms] Connected to _flutterView/0x7fb385029a20.
[   +1 ms] Flutter run key commands.
[   +1 ms] r Hot reload. 🔥🔥🔥
[        ] R Hot restart.
[        ] h Repeat this help message.
[        ] d Detach (terminate "flutter run" but leave application running).
[        ] c Clear the screen
[        ] q Quit (terminate the application on the device).
[        ] An Observatory debugger and profiler on iPhone 11 Pro Max is available at: http://127.0.0.1:49425/M4KbxYrcQ_s=/
[        ] Running with unsound null safety
[        ] For more information see https://dart.dev/null-safety/unsound-null-safety
[ +235 ms] flutter: update image: 2020-12-10 22:23:55.966705

@mikeRozen
Copy link
Author

@iapicca
Strange I do see this log, could u please search for something like:

[ +1 ms] flutter: get image: 2020-12-10 22:23:55.545693
(in the snippets u posted its 18 line from the bottom)
(Its essentially the code u posted with Stack and background color).
So how would u suggest to make the image load synchronously? (or to delay the page load until the image ready)
Sorry if I dont make it clear enough or don't use the correct terminology in terms of Framework use, I am still relatively new to flutter

@iapicca
Copy link
Contributor

iapicca commented Dec 11, 2020

@mikeRozen
I believe this is a question for stackoverflow (example) not a bug with flutter

@meiraxx
Copy link

meiraxx commented Jun 1, 2021

This issue is affecting me too. All other widgets load before the image does on the first screen, ruining the smoothness the user should experience when opening the app

@TahaTesser
Copy link
Member

Could everyone who still has this problem please file a new issue with the exact description of what happens, logs, and the output of flutter doctor -v.
All system setups can be slightly different, so it's always better to open new issues and reference related issues.

@github-actions
Copy link

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 31, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
in triage Presently being triaged by the triage team
Projects
None yet
Development

No branches or pull requests

5 participants