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

Changing image source on Android causes flicker between images #6625

Closed
dharber opened this issue Apr 28, 2022 · 8 comments · Fixed by #7348
Closed

Changing image source on Android causes flicker between images #6625

dharber opened this issue Apr 28, 2022 · 8 comments · Fixed by #7348
Assignees
Labels
area-controls-image Image control fixed-in-6.0.400 Look for this fix in 6.0.400! p/2 Work that is important, but not critical for the release platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Milestone

Comments

@dharber
Copy link

dharber commented Apr 28, 2022

Description

I have an Image control and I periodically set the source to a new Uri image. This worked perfectly (on Android...don't get me started on Windows) in Preview 14. It was completely broken by RC1 and then partially sort of fixed by #6394 and then more fixed in #6543. However, the image still flickers, i.e., goes black for a short time, maybe a quarter second or so, when the image source is set to a new Uri.

I just noticed in a test app that when the images are cached, i.e., have already been loaded and displayed once, there is no flicker. Unfortunately, my app is fetching a series of hundreds and sometimes thousands of images so the images will literally never be cached.

Again, in Preview 14 there was no flickering at all.

Steps to Reproduce

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ImageTest2.MainPage">
			 
    <ScrollView>
        <VerticalStackLayout 
            Spacing="25" 
            Padding="30,0" 
            VerticalOptions="Center">

            <Image
                x:Name="Image"
                Source="dotnet_bot.png"
                SemanticProperties.Description="Cute dot net bot waving hi to you!"
                HeightRequest="200"
                HorizontalOptions="Center" />
                
            <Label 
                Text="Hello, World!"
                SemanticProperties.HeadingLevel="Level1"
                FontSize="32"
                HorizontalOptions="Center" />
            
            <Label 
                Text="Welcome to .NET Multi-platform App UI"
                SemanticProperties.HeadingLevel="Level2"
                SemanticProperties.Description="Welcome to dot net Multi platform App U I"
                FontSize="18"
                HorizontalOptions="Center" />

        </VerticalStackLayout>
    </ScrollView>
 
</ContentPage>

MainPage.xaml.cs:

namespace ImageTest2;

public partial class MainPage : ContentPage
{
	int count = 0;

	public MainPage()
	{
		InitializeComponent();

		imageTimer = new(Timer_Tick, null, 1000, 1000);
	}

	private void Timer_Tick(object _)
    {
		Application.Current.Dispatcher.Dispatch(() => Image.Source = new Uri(images[imageNo]));
		imageNo = (imageNo + 1) % images.Length;
    }

	readonly string[] images = new string[]
	{
        "https://64.media.tumblr.com/14cb5aa197e5d9ca6479d955f68344f0/cb28a32e384437f2-07/s540x810/005508be5849eff8fda5b0ebda23f9fcbede164e.jpg",
        "https://64.media.tumblr.com/d66b1709639c23315d26c0a4e977c399/1fb3e31c5e63625d-81/s540x810/2e9a893ec8c1f65a4b9fb8f1264b4fb76914ced8.jpg",
        "https://64.media.tumblr.com/e7db300b8248c0a7f4c66884032c9414/8f89498ebe784d1c-4e/s540x810/90835c041547bf2936ee249c5c5e1b4eddd589a3.jpg",
        "https://64.media.tumblr.com/fd901060692d2c9ca6f05ddc58e28e5d/2db73c9c5730d87c-e2/s500x750/092c9dc3cff5150acf24bf22a9e61b9719d9ccd6.jpg",
        "https://64.media.tumblr.com/c011aa547a45ac6fe47c46beeb290596/eafc76ded66f16f9-dc/s500x750/5ed923ed086296a2bd41cab3106079eb7addc2d0.jpg",
    };
	int imageNo = 0;
	readonly Timer imageTimer;
}

Version with bug

Release Candidate 3

Last version that worked well

Preview 14

Affected platforms

Android

Affected platform versions

Seeing it on Android 11

Did you find any workaround?

No workaround was found. I tried performing ImageSource.LoadImage and setting the image source in the callback (which is what I was doing in Preview 14) but that didn't appear to help.

Relevant log output

n/a
@dharber dharber added s/needs-verification Indicates that this issue needs initial verification before further triage will happen t/bug Something isn't working labels Apr 28, 2022
@Eilon Eilon added the area-image Image loading, sources, caching label Apr 28, 2022
@v-longmin v-longmin added s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage and removed s/needs-verification Indicates that this issue needs initial verification before further triage will happen labels Apr 29, 2022
@v-longmin
Copy link

Verified repro on Android 12.0 with VS 17.3.0 Preview 1.0 [32427.455.main]. Repro with above project.

@Redth Redth added this to the 6.0.300 milestone May 3, 2022
@Redth Redth added the p/1 Work that is critical for the release, but we could probably ship without label May 3, 2022
@Redth Redth modified the milestones: 6.0.300, 6.0.300-servicing May 3, 2022
@Redth Redth added p/2 Work that is important, but not critical for the release and removed p/1 Work that is critical for the release, but we could probably ship without labels May 3, 2022
@mattleibow
Copy link
Member

This could also be fixed with #6898

@dharber
Copy link
Author

dharber commented May 7, 2022

I just tried it with the most recent maui.aar and the flicker is somewhat better. But there is still a distinct gap between the old image and the new image, i.e. a noticeable flicker. In Preview 14 there is none.

I will note, however, that the sample code above is not completely representative of my actual code. I'm going to say the sample code should probably still not flicker at all but my actual code calls LoadImage on the ImageSource and actually sets the Source property on the Image control during the callback. My interpretation of the LoadImage method was that the callback was called when the image was actually fetched and decoded so that display would be immediate. As I mentioned, this works exactly as I expect in Preview 14 but still flickers with the maui.aar from #6898.

Also, this observation is predicated on the premise that I grabbed the correct maui.aar. I'm pretty sure I copied it to the right place since images started appearing after I copied the new one but I'm not sure how to determine if what I grabbed actually has #6898 in it.

Edit: I just checked the history of maui.aar and it appears to include #6898 so the flicker does still seem to be there.

@mattleibow
Copy link
Member

The reason for the gap is because we actually clear out the old image when assigning a new one. Not sure if that is desired behaviour for general apps or not.

There are a few scenarios:

  1. a list with images being scrolled fast (contacts list)
  2. a static image that changes an image (ad ticker, carousel)
  3. some page being reloaded (refresh image)

There may be more, but what should the correct way be?

Should we have an API that allows the developer to decide? Is there an example of this type of API out in the wild and regardless of frameworks or language, what do other frameworks do?

I am wondering if this should/could be done with 2 image views and having the one mage loaded even trigger a swap between the two? So by default clear, but the smooth way is to actually load the image into an invisible image view? Is that better? Is that worse?

@dharber
Copy link
Author

dharber commented May 19, 2022

Is there any insight on what changed from Preview 14 to RC1 and why it changed behavior?

@mattleibow
Copy link
Member

I am not sure why... Seems we always cleared the old image since the very first image support: https://github.com/dotnet/maui/pull/759/files#diff-13df83e905abc59530f995480e58f3532792e1c248818fa2f29b3eeaa358d0c3R46

However both @PureWeen reworked the images as well as @Redth moved more code into Java land.

I did test your code in the issue and I still see flickering - but only at the start and then once all the images are cached, it goes away. When I remove the code to clear the image before loading the new one, I do actually see a noticeable difference and no flickering at all. Same with Windows.

So, why do we clear the image? I have no idea and it seemed correct at the time because why would you want some old image in there? Well, to not make the UX terrible.

I'll do a PR on not-clearing and we can see.

@mattleibow
Copy link
Member

Thanks for the persistence.

@dharber
Copy link
Author

dharber commented May 19, 2022

Unfortunately, the nature of the app I'm working on pretty much guarantees the images will never be cached. I just used the tumblr images to demonstrate the flickering. In reality, the app fetches images from a very large pool so it's very likely they'd have been dumped from the cache long before they ever came up again.

Redth pushed a commit that referenced this issue May 24, 2022
* Don't clear old images. Fixes #6625

* omg

* Unify the image tests

* using

* test

* SetImageDrawable
@ghost ghost locked as resolved and limited conversation to collaborators Jul 1, 2022
@samhouts samhouts added the fixed-in-6.0.400 Look for this fix in 6.0.400! label Feb 17, 2023
@Eilon Eilon added area-controls-image Image control and removed area-image Image loading, sources, caching labels May 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-controls-image Image control fixed-in-6.0.400 Look for this fix in 6.0.400! p/2 Work that is important, but not critical for the release platform/android 🤖 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants