Image slow to load.. for imagebackground

3,266 views
Skip to first unread message

Pascal Fournier

unread,
Jun 10, 2019, 2:27:22 PM6/10/19
to Flutter Development (flutter-dev)
Hello to all ! 

I have an issue that i don't know how to solve it. I have a SplashScreen and then after, it redirects to the second page. The seconde page has Container with an image in background.
But the problem is, when the second page appears, we see a white background for less than a second than after, my background image appears...

It's not a good user experience... how can i solve it !

Thanks a lot ! 

Pascal

Kristiyan Mitev

unread,
Jun 10, 2019, 4:33:19 PM6/10/19
to Flutter Development (flutter-dev)
This happens because (most probably) you're requesting the image when you are building the second page. You can pre-load it and keep a reference to it in some var 'cachedImage' or something like that.

Will Williams

unread,
Jun 10, 2019, 4:36:51 PM6/10/19
to Kristiyan Mitev, Flutter Development (flutter-dev)
You can either pre-load the image in the first screen. Or you can use a stream builder on the second screen to show a circular loading image until the image renders.  I do both in my app.

On Jun 10, 2019, at 2:33 PM, Kristiyan Mitev <kom...@gmail.com> wrote:

This happens because (most probably) you're requesting the image when you are building the second page. You can pre-load it and keep a reference to it in some var 'cachedImage' or something like that.

--
You received this message because you are subscribed to the Google Groups "Flutter Development (flutter-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/flutter-dev/fa780a1e-c846-479b-8f08-ca4d9ae05c84%40googlegroups.com.

Pascal Fournier

unread,
Jun 10, 2019, 4:42:58 PM6/10/19
to Flutter Development (flutter-dev)
Hello Will and Krystiyan! 

Thanks a lot for your response.

Actually i'm doing this

this : 
Image image1;


void initState() {
image1 = Image.asset("assets/img/image.jpg");
super.initState();
}


and

@override
void didChangeDependencies() {

precacheImage(image1.image, context);
super.didChangeDependencies();
}


Note that app.apk is in debug, should i need to be in release for to precachedImage works ?

How can i preload to the first page and send it to the second page ?

Thanks a lot !

I appreciate !

Pascal








Le lundi 10 juin 2019 16:36:51 UTC-4, Will Williams a écrit :
You can either pre-load the image in the first screen. Or you can use a stream builder on the second screen to show a circular loading image until the image renders.  I do both in my app.
On Jun 10, 2019, at 2:33 PM, Kristiyan Mitev <kom...@gmail.com> wrote:

This happens because (most probably) you're requesting the image when you are building the second page. You can pre-load it and keep a reference to it in some var 'cachedImage' or something like that.

--
You received this message because you are subscribed to the Google Groups "Flutter Development (flutter-dev)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to flutt...@googlegroups.com.

Kristiyan Mitev

unread,
Jun 10, 2019, 5:13:59 PM6/10/19
to Flutter Development (flutter-dev)
On way to achieve this is to preload it in the widget that is calling your second page.

After that, when pushing your route, all Navigator.push* methods accept some kind of arguments to pass onto the newly pushed route, see: https://flutter.dev/docs/cookbook/navigation/navigate-with-arguments
You can use these parameters to pass around your data, in the specific case your image. Also, this page might be helpful: https://api.flutter.dev/flutter/material/MaterialPageRoute-class.html the constructor accepts a 'RouteSettings settings' named param, which you can learn more about here: https://api.flutter.dev/flutter/widgets/RouteSettings-class.html - it's arguments parameter is what you're after most probably.

Andy Greenshaw

unread,
Jun 10, 2019, 5:15:00 PM6/10/19
to Flutter Development (flutter-dev), Pascal Fournier
Check the size of your image(s) (width / height and resolution). Are they larger / higher than they need to be to look good on a mobile device? If yes, reduce their size and resolution, which will decrease the load time (both of the app, as well as the images, and produce a smaller apk).

The way you are currently pre-caching the image will have no effect. You should pre-cache on the previous screen (or on a splash screen). What package are you using to do the pre-caching? It shouldn’t care what screen you are on. When you need to display the image, the package should see if it is already in its cache and use that version, otherwise it will load the image and cache it.

To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/flutter-dev/a1e4f4cc-8c9c-43e7-a111-70a3dc4c365c%40googlegroups.com.

Andy Greenshaw

unread,
Jun 10, 2019, 5:27:51 PM6/10/19
to Flutter Development (flutter-dev), Pascal Fournier
precacheImage(ImageProvider<dynamic> provider, BuildContext context, {Size size, (dynamic, StackTrace) → void onError}) → Future<void>

package:flutter

Prefetches an image into the image cache.

Returns a [Future] that will complete when the first image yielded by the [ImageProvider] is available or failed to load.

If the image is later used by an [Image] or [BoxDecoration] or [FadeInImage], it will probably be loaded faster. The consumer of the image does not need to use the same [ImageProvider] instance. The [ImageCache] will find the image as long as both images share the same key.


So you should just move your code to the previous screen as stated in the docs "The [ImageCache] will find the image as long as both images share the same key.“. So if it has the same name where you cache it and load it (on the next screen), it should use the cached image.

Kristiyan Mitev

unread,
Jun 11, 2019, 5:27:08 AM6/11/19
to Flutter Development (flutter-dev)
Hey Pascal, if you're still wondering what method to employ, use Andy's solution - it's better. If you don't mind, let us know if it works well, because I don't have time to test precacheImage now.

Pascal Fournier

unread,
Jun 11, 2019, 8:05:27 AM6/11/19
to Flutter Development (flutter-dev)
Hello Andy and Kristiyan,

Thanks a lot for your help ! I really appreciate ! 

To answer the question of Andy, the size of my image(the file) is 1920x1280 and is 307kb. is this size too big?

Also, i did what you suggest to me.

In my splash screen i did that :

I declare a variable : 

Image imgbg_next_screen;


after, i edit the initState like this :

@override
void initState() {
// TODO: implement initState
imgbg_next_screen = Image.asset("assets/img/background.jpg");
super.initState();
}


After i edit the didChangeDependencies to use precacheImage:
@override
void didChangeDependencies() {
precacheImage(imgbg_next_screen.image, context);

super.didChangeDependencies();
}

Then, when i call my second page, i pass the variable imgbg_next_screen.

do I use the right way to do with the InitState and the didChangeDependencies ? Because in the doc, it talks about the both images share the same key ? what is a key ? the image name ?

For now, it seems to work perfectly, i did not see the white background !!

Thanks a lot i really appreciate.

One more question, what if the background image is  on the first page... like the background image of my splash screen ? how to use precacheImage if the background image is on the first page?

Thanks a lot ! I wish you a wonderful day ! 

Pascal

Andy Greenshaw

unread,
Jun 11, 2019, 8:21:30 AM6/11/19
to Flutter Development (flutter-dev), Pascal Fournier
I would say the image size is large if your app is just for mobile, but if it’s also for tablets then it’s fine.

The way you’ve implemented it looks about right (though if the image is needed in many places, maybe using the ‘Provider' class and storing the image there, would be better than passing it as a parameter).

If the image is on your first screen (splash screen in this case), then the best thing you can do is have a small image that loads quickly (or maybe just a coloured background with a small logo…). Another option is to add the splash screen directly into Android and iOS, but that’s outside of the scope of Flutter and requires updating the Android and iOS projects (you can read about here https://medium.com/flutter-community/flutter-2019-real-splash-screens-tutorial-16078660c7a1).
To unsubscribe from this group and stop receiving emails from it, send an email to flutter-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/flutter-dev/f23efe92-791f-4d7d-8c66-ccc585c3c112%40googlegroups.com.

Pascal Fournier

unread,
Jun 11, 2019, 8:38:47 AM6/11/19
to Flutter Development (flutter-dev)
Hello Andy ! 

Thanks a lot ! I will read about the provider ! I use this image on one or two pages maybe.

I appreciate your help ! 

Have a great day ! 
Pascal

Kristiyan Mitev

unread,
Jun 11, 2019, 8:44:11 AM6/11/19
to Flutter Development (flutter-dev)
It should also work without passing the imgbg_next_screen to the next screen, just load it as you would from your assets, it's already cached. The key would be an implementation of https://api.flutter.dev/flutter/painting/ImageProvider-class.html I imagine. e.g. identical instances of https://api.flutter.dev/flutter/painting/AssetImage-class.html would be treated as the same key, and thus a cached image would be loaded (if present). Be mindful, that the cache might be invalidated in any point in time, so you might want to keep a reference to the image during the entire life-cycle of your app.

As for your second question, I'm not entirely sure that's possible, without displaying some kind of a loading indicator. One thing you can try is use SchedulerBinding.instance.addPostFrameCallback in your initState for the home of your app (more here: https://api.flutter.dev/flutter/scheduler/SchedulerBinding/addPostFrameCallback.html ) and preload the image there.

Something like:

@override
void initState() {
 
super.initState();
 
SchedulerBinding.instance.addPostFrameCallback((_) {
   
// Quote from docs:
   
   
// Schedule a callback for the end of this frame.
   
//Does not request a new frame.
   
// This callback is run during a frame, just after the persistent frame callbacks (which is when the main rendering pipeline has been flushed). If a frame is in progress and post-frame callbacks haven't been executed yet, then the registered callback is still executed during the frame. Otherwise, the registered callback is executed during the next frame.
   
// The callbacks are executed in the order in which they have been added.
   
// Post-frame callbacks cannot be unregistered. They are called exactly once.
   
   
// this means:
   
// context is accessible here, also this will be called only once
   
// didChangeDependencies might be called multiple times.
   
// so it's a good idea to precache images here
   
// but it's doubtful that it'll work, because you need to precache
   
// images before the first frame is shown
 
});
}

Pascal Fournier

unread,
Jun 11, 2019, 9:29:27 AM6/11/19
to Flutter Development (flutter-dev)
Hello Kristiyan ! 

Thanks a lot for your explanation. It's good if i do not need to pass the image in parameter ! I will try it ! 

I will  read about and try SchedulerBinding.instance.addPostFrameCallback.

Thanks a lot, i really appreciate :)

Have a great day ! 

Pascal
Reply all
Reply to author
Forward
0 new messages