xamarin / XamarinCommunityToolkit

The Xamarin Community Toolkit is a collection of Animations, Behaviors, Converters, and Effects for mobile development with Xamarin.Forms. It simplifies and demonstrates common developer tasks building iOS, Android, and UWP apps with Xamarin.Forms.
MIT License
1.58k stars 471 forks source link

[Bug] AvatarView - Valid source images dont load for the first time they are created #805

Closed mtsrdr closed 3 years ago

mtsrdr commented 3 years ago

Description

AvatarView images are not loaded the first time they are created and may never load if Caching is disabled.

Steps to Reproduce

  1. Run the Attached Project with the Switch "Enable caching" set to true in the first launch of the app on the device:

  2. Click the "Load avatar images" button and see that avatar images won't load the first time.

  3. Click again and you'll see that the new images will appear normally (because they're the same url and caching is enabled).

  4. Click the "Clear avatar images" button and set the "Enable caching" Switch to false.

  5. Click the "Load avatar images" button again and see that the images will not appear.

Expected Behavior

AvatarView Image should always be visible if source is valid

Actual Behavior

AvatarView source image is not showing

Basic Information

Reproduction imagery

-

-

Reproduction Link

AvatarViewIssue.zip

mtsrdr commented 3 years ago

After investigating the AvatarView source code, I found out what is causing the issue.

It's trying to update the source of the image twice during its startup, which generates an error.

Android log:

Image Loading: Error getting stream for https://avatars.githubusercontent.com/u/1405704?v=4: System.OperationCanceledException: The operation was canceled.
  at System.Threading.CancellationToken.ThrowOperationCanceledException () [0x00000] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corert/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs:338 
  at System.Threading.CancellationToken.ThrowIfCancellationRequested () [0x00008] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corert/src/System.Private.CoreLib/shared/System/Threading/CancellationToken.cs:333 
  at Xamarin.Android.Net.AndroidClientHandler.ProcessRequest (System.Net.Http.HttpRequestMessage request, Java.Net.URL javaUrl, Java.Net.HttpURLConnection httpConnection, System.Threading.CancellationToken cancellationToken, Xamarin.Android.Net.AndroidClientHandler+RequestRedirectionState redirectState) [0x00000] in /Users/builder/azdo/_work/278/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs:331 
  at Xamarin.Android.Net.AndroidClientHandler.SendAsync (System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) [0x00255] in /Users/builder/azdo/_work/278/s/xamarin-android/src/Mono.Android/Xamarin.Android.Net/AndroidClientHandler.cs:287 
  at System.Net.Http.HttpClient.FinishSendAsyncBuffered (System.Threading.Tasks.Task`1[TResult] sendTask, System.Net.Http.HttpRequestMessage request, System.Threading.CancellationTokenSource cts, System.Boolean disposeCts) [0x0017e] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/external/corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:506 
  at Xamarin.Forms.StreamWrapper.GetStreamAsync (System.Uri uri, System.Threading.CancellationToken cancellationToken, System.Net.Http.HttpClient client) [0x00038] in D:\a\1\s\Xamarin.Forms.Core\StreamWrapper.cs:99 
  at Xamarin.Forms.Forms+AndroidPlatformServices.GetStreamAsync (System.Uri uri, System.Threading.CancellationToken cancellationToken) [0x0003f] in D:\a\1\s\Xamarin.Forms.Platform.Android\Forms.cs:854 
  at Xamarin.Forms.UriImageSource.GetStreamAsync (System.Uri uri, System.Threading.CancellationToken cancellationToken) [0x000cf] in D:\a\1\s\Xamarin.Forms.Core\UriImageSource.cs:136 
ImageLoaderSourceHandler: Could not retrieve image or image data was invalid: Uri: https://avatars.githubusercontent.com/u/1405704?v=4

There are two places where this happens:

  1. In the propagation of the 'propertyChanged' event from SourceProperty.
  2. In the propagation of the event 'Image.BindingContextChanged'.

We can fix this issue by passing false as the value of the 'shouldUpdateSource' parameter or even by removing the following line:

Image.BindingContextChanged += (s, e) => OnValuePropertyChanged(true);

I can only think of one reason why this line is there:

On the 'AvatarViewPage' page we have:

                  <xct:AvatarView ColorTheme="{x:Static xct:ColorTheme.Jungle}" FontSize="Medium" Size="{Binding Value, Source={x:Reference Slider}}" Text="{Binding Initials}" >
                      <xct:AvatarView.Source:>
                          <UriImageSource Uri="{Binding Source}" />
                      </xct:AvatarView.Source>
                  </xct:AvatarView>

When we set the source the 'propertyChanged' event is called before the Uri is set in UriImageSource, then it does not work in this case.

The control is unusable in this state. Can someone take a look at this?