diff --git a/source/FFImageLoading.Common/Work/ImageLoaderTask.cs b/source/FFImageLoading.Common/Work/ImageLoaderTask.cs index 7ca6d4845..9ae521df5 100644 --- a/source/FFImageLoading.Common/Work/ImageLoaderTask.cs +++ b/source/FFImageLoading.Common/Work/ImageLoaderTask.cs @@ -174,10 +174,11 @@ public virtual bool UsesSameNativeControl(IImageLoaderTask anotherTask) public void Cancel() { - ImageService.RemovePendingTask(this); - if (!_isDisposed) { + Target?.SetImageLoadingTask(null); + ImageService.RemovePendingTask(this); + try { CancellationTokenSource?.Cancel(); @@ -185,10 +186,10 @@ public void Cancel() catch (ObjectDisposedException) { } - } - if (Configuration.VerboseLoadingCancelledLogging) - Logger.Debug(string.Format("Image loading cancelled: {0}", Key)); + if (Configuration.VerboseLoadingCancelledLogging) + Logger.Debug(string.Format("Image loading cancelled: {0}", Key)); + } } public void CancelIfNeeded() @@ -203,10 +204,7 @@ public void CancelIfNeeded() protected virtual void BeforeLoading(TImageContainer image, bool fromMemoryCache) { } - protected virtual void AfterLoading(TImageContainer image, bool fromMemoryCache) - { - Target?.SetImageLoadingTask(null); - } + protected virtual void AfterLoading(TImageContainer image, bool fromMemoryCache) { } public async virtual Task TryLoadFromMemoryCacheAsync() { @@ -423,7 +421,7 @@ await MainThreadDispatcher.PostAsync(() => MemoryCache.Clear(); } - if (ex is OperationCanceledException) + if (ex is OperationCanceledException || ex is ObjectDisposedException) { if (Configuration.VerboseLoadingCancelledLogging) { diff --git a/source/FFImageLoading.Common/Work/WorkScheduler.cs b/source/FFImageLoading.Common/Work/WorkScheduler.cs index 3c737cb23..43e350abd 100644 --- a/source/FFImageLoading.Common/Work/WorkScheduler.cs +++ b/source/FFImageLoading.Common/Work/WorkScheduler.cs @@ -169,7 +169,7 @@ public virtual async void LoadImage(IImageLoaderTask task) if (task == null) return; - if (task.IsCancelled || task.IsCompleted) + if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) { task?.Dispose(); return; @@ -195,32 +195,6 @@ public virtual async void LoadImage(IImageLoaderTask task) { try { - EvictStaleTasks(); - - if (task.IsCancelled || task.IsCompleted) - { - task?.Dispose(); - return; - } - - if (!task.Parameters.Preload) - { - lock (_pendingTasksLock) - { - foreach (var pendingTask in PendingTasks.ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration - { - if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) - pendingTask.ImageLoadingTask.CancelIfNeeded(); - } - } - } - - if (task.IsCancelled || ExitTasksEarly) - { - task?.Dispose(); - return; - } - QueueImageLoadingTask(task); } catch (Exception ex) @@ -235,9 +209,26 @@ protected void QueueImageLoadingTask(IImageLoaderTask task) int position = Interlocked.Increment(ref _currentPosition); var currentPendingTask = new PendingTask() { Position = position, ImageLoadingTask = task, FrameworkWrappingTask = CreateFrameworkTask(task) }; + if (task.IsCancelled || task.IsCompleted || ExitTasksEarly) + { + task?.Dispose(); + return; + } + PendingTask similarRunningTask = null; lock (_pendingTasksLock) { + if (!task.Parameters.Preload) + { + foreach (var pendingTask in PendingTasks.ToList()) // FMT: here we need a copy since cancelling will trigger them to be removed, hence collection is modified during enumeration + { + if (pendingTask.ImageLoadingTask != null && pendingTask.ImageLoadingTask.UsesSameNativeControl(task)) + pendingTask.ImageLoadingTask.CancelIfNeeded(); + } + + EvictStaleTasks(); + } + similarRunningTask = PendingTasks.FirstOrDefault(t => t.ImageLoadingTask.Key == task.Key); if (similarRunningTask == null) { diff --git a/source/FFImageLoading.Droid/Targets/ImageViewTarget.cs b/source/FFImageLoading.Droid/Targets/ImageViewTarget.cs index 0c90323b3..b14c39480 100644 --- a/source/FFImageLoading.Droid/Targets/ImageViewTarget.cs +++ b/source/FFImageLoading.Droid/Targets/ImageViewTarget.cs @@ -26,7 +26,6 @@ public override bool IsValid public override bool IsTaskValid(IImageLoaderTask task) { var controlTask = Control?.ImageLoaderTask; - return IsValid && (controlTask == null || controlTask == task); } @@ -38,7 +37,8 @@ public override void SetAsEmpty(IImageLoaderTask task) var control = Control; if (control == null) return; - + + control.ImageLoaderTask = null; control.SetImageResource(global::Android.Resource.Color.Transparent); } @@ -72,7 +72,7 @@ public override bool UsesSameNativeControl(IImageLoaderTask task) if (control == null || otherControl == null) return false; - return control.Handle == otherControl.Handle; + return control.Handle == otherControl.Handle; } public override ImageViewAsync Control diff --git a/source/FFImageLoading.Droid/TaskParameterExtensions.cs b/source/FFImageLoading.Droid/TaskParameterExtensions.cs index ae69970df..086062a1d 100644 --- a/source/FFImageLoading.Droid/TaskParameterExtensions.cs +++ b/source/FFImageLoading.Droid/TaskParameterExtensions.cs @@ -21,6 +21,8 @@ public static class TaskParameterExtensions /// Image view that should receive the image. public static IScheduledWork Into(this TaskParameter parameters, ImageViewAsync imageView) { + imageView.CancelLoading(); + var target = new ImageViewTarget(imageView); if (parameters.Source != ImageSource.Stream && string.IsNullOrWhiteSpace(parameters.Path)) diff --git a/source/FFImageLoading.Droid/Views/ImageViewAsync.cs b/source/FFImageLoading.Droid/Views/ImageViewAsync.cs index 923a4ddd5..48accdb31 100644 --- a/source/FFImageLoading.Droid/Views/ImageViewAsync.cs +++ b/source/FFImageLoading.Droid/Views/ImageViewAsync.cs @@ -69,11 +69,6 @@ protected override void OnDetachedFromWindow() base.OnDetachedFromWindow(); }*/ - public void CancelLoading() - { - ImageService.Instance.CancelWorkFor(ImageLoaderTask); - } - protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (Drawable == null) diff --git a/source/FFImageLoading.Droid/Views/ManagedImageView.cs b/source/FFImageLoading.Droid/Views/ManagedImageView.cs index 500245cb6..e9488a24c 100644 --- a/source/FFImageLoading.Droid/Views/ManagedImageView.cs +++ b/source/FFImageLoading.Droid/Views/ManagedImageView.cs @@ -60,54 +60,43 @@ protected override void OnDetachedFromWindow() public IImageLoaderTask ImageLoaderTask { get; set; } + public void CancelLoading() + { + if (ImageLoaderTask != null) + { + ImageService.Instance.CancelWorkFor(ImageLoaderTask); + ImageLoaderTask = null; + } + + } + public override void SetImageDrawable(Drawable drawable) { - try - { - var previous = Drawable; + var previous = Drawable; - _drawableRef = new WeakReference(drawable); - base.SetImageDrawable(drawable); + _drawableRef = new WeakReference(drawable); + base.SetImageDrawable(drawable); - UpdateDrawableDisplayedState(drawable, true); - UpdateDrawableDisplayedState(previous, false); - } - finally - { - ImageLoaderTask = null; - } + UpdateDrawableDisplayedState(drawable, true); + UpdateDrawableDisplayedState(previous, false); } public override void SetImageResource(int resId) { - try - { - var previous = Drawable; - // Ultimately calls SetImageDrawable, where the state will be updated. - _drawableRef = null; - base.SetImageResource(resId); - UpdateDrawableDisplayedState(previous, false); - } - finally - { - ImageLoaderTask = null; - } + var previous = Drawable; + // Ultimately calls SetImageDrawable, where the state will be updated. + _drawableRef = null; + base.SetImageResource(resId); + UpdateDrawableDisplayedState(previous, false); } public override void SetImageURI(global::Android.Net.Uri uri) { - try - { - var previous = Drawable; - // Ultimately calls SetImageDrawable, where the state will be updated. - _drawableRef = null; - base.SetImageURI(uri); - UpdateDrawableDisplayedState(previous, false); - } - finally - { - ImageLoaderTask = null; - } + var previous = Drawable; + // Ultimately calls SetImageDrawable, where the state will be updated. + _drawableRef = null; + base.SetImageURI(uri); + UpdateDrawableDisplayedState(previous, false); } private void UpdateDrawableDisplayedState(Drawable drawable, bool isDisplayed)