mirror of
https://github.com/yaobiao131/downkyicore.git
synced 2025-08-10 00:52:31 +00:00
fix: 优化asyncImageLoader内存占用
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
<Project ToolsVersion="15.0">
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.2.7"/>
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.7"/>
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.7"/>
|
||||
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.2.7"/>
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.7"/>
|
||||
<PackageVersion Include="Avalonia.Themes.Simple" Version="11.2.7"/>
|
||||
<PackageVersion Include="Xaml.Behaviors" Version="11.2.7"/>
|
||||
<PackageVersion Include="Downloader" Version="3.3.4"/>
|
||||
<PackageVersion Include="Prism.Avalonia" Version="8.1.97.11073"/>
|
||||
<PackageVersion Include="Prism.DryIoc.Avalonia" Version="8.1.97.11073"/>
|
||||
<PackageVersion Include="FFMpegCore" Version="5.1.0"/>
|
||||
<PackageVersion Include="Google.Protobuf" Version="3.25.1"/>
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="9.0.4"/>
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3"/>
|
||||
<PackageVersion Include="QRCoder" Version="1.6.0"/>
|
||||
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.11"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.2.7" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.7" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.2.7" />
|
||||
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.2.7" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.7" />
|
||||
<PackageVersion Include="Avalonia.Themes.Simple" Version="11.2.7" />
|
||||
<PackageVersion Include="Xaml.Behaviors" Version="11.2.7" />
|
||||
<PackageVersion Include="Downloader" Version="3.3.4" />
|
||||
<PackageVersion Include="Prism.Avalonia" Version="8.1.97.11073" />
|
||||
<PackageVersion Include="Prism.DryIoc.Avalonia" Version="8.1.97.11073" />
|
||||
<PackageVersion Include="FFMpegCore" Version="5.1.0" />
|
||||
<PackageVersion Include="Google.Protobuf" Version="3.25.1" />
|
||||
<PackageVersion Include="Microsoft.Data.Sqlite.Core" Version="9.0.4" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageVersion Include="QRCoder" Version="1.6.0" />
|
||||
<PackageVersion Include="SQLitePCLRaw.bundle_e_sqlcipher" Version="2.1.11" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -4,6 +4,7 @@ using Avalonia;
|
||||
using Avalonia.Logging;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
using DownKyi.Core.Storage;
|
||||
using DownKyi.CustomControl.AsyncImageLoader.Loaders;
|
||||
|
||||
@@ -33,7 +34,20 @@ public static class ImageBrushLoader
|
||||
{
|
||||
if (newValue is not null)
|
||||
{
|
||||
bitmap = await AsyncImageLoader.ProvideImageAsync(newValue);
|
||||
// 注意缩放比例
|
||||
var width = GetWidth(imageBrush);
|
||||
var height = GetHeight(imageBrush);
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
var scale = await Dispatcher.UIThread.InvokeAsync(() => App.Current.MainWindow.DesktopScaling);
|
||||
var actualWidth = Convert.ToInt32(width * scale);
|
||||
var actualHeight = Convert.ToInt32(height * scale);
|
||||
bitmap = (await AsyncImageLoader.ProvideImageAsync(newValue))?.CreateScaledBitmap(new PixelSize(actualWidth, actualHeight));
|
||||
}
|
||||
else
|
||||
{
|
||||
bitmap = await AsyncImageLoader.ProvideImageAsync(newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -70,4 +84,28 @@ public static class ImageBrushLoader
|
||||
{
|
||||
element.SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly AttachedProperty<int> WidthProperty = AvaloniaProperty.RegisterAttached<ImageBrush, int>("Width", typeof(ImageLoader));
|
||||
|
||||
public static int GetWidth(ImageBrush element)
|
||||
{
|
||||
return element.GetValue(WidthProperty);
|
||||
}
|
||||
|
||||
public static void SetWidth(ImageBrush element, int value)
|
||||
{
|
||||
element.SetValue(WidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly AttachedProperty<int> HeightProperty = AvaloniaProperty.RegisterAttached<ImageBrush, int>("Height", typeof(ImageLoader));
|
||||
|
||||
public static int GetHeight(ImageBrush element)
|
||||
{
|
||||
return element.GetValue(HeightProperty);
|
||||
}
|
||||
|
||||
public static void SetHeight(ImageBrush element, int value)
|
||||
{
|
||||
element.SetValue(HeightProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Logging;
|
||||
using Avalonia.Media.Imaging;
|
||||
using Avalonia.Threading;
|
||||
using DownKyi.Core.Storage;
|
||||
using DownKyi.CustomControl.AsyncImageLoader.Loaders;
|
||||
|
||||
@@ -62,6 +62,13 @@ public static class ImageLoader
|
||||
// A small delay allows to cancel early if the image goes out of screen too fast (eg. scrolling)
|
||||
// The Bitmap constructor is expensive and cannot be cancelled
|
||||
await Task.Delay(10, cts.Token);
|
||||
if (sender.DesiredSize.Width != 0 && sender.DesiredSize.Height != 0)
|
||||
{
|
||||
var scale = Dispatcher.UIThread.Invoke(() => App.Current.MainWindow.DesktopScaling);
|
||||
var actualWidth = Convert.ToInt32(sender.DesiredSize.Width * scale);
|
||||
var actualHeight = Convert.ToInt32(sender.DesiredSize.Height * scale);
|
||||
return (await AsyncImageLoader.ProvideImageAsync(url))?.CreateScaledBitmap(new PixelSize(actualWidth, actualHeight));
|
||||
}
|
||||
|
||||
return await AsyncImageLoader.ProvideImageAsync(url);
|
||||
}
|
||||
@@ -75,10 +82,10 @@ public static class ImageLoader
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}, cts.Token);
|
||||
|
||||
if (bitmap != null && !cts.Token.IsCancellationRequested)
|
||||
sender.Source = bitmap!;
|
||||
sender.Source = bitmap;
|
||||
|
||||
// "It is not guaranteed to be thread safe by ICollection, but ConcurrentDictionary's implementation is. Additionally, we recently exposed this API for .NET 5 as a public ConcurrentDictionary.TryRemove"
|
||||
((ICollection<KeyValuePair<Image, CancellationTokenSource>>)PendingOperations).Remove(new KeyValuePair<Image, CancellationTokenSource>(sender, cts));
|
||||
@@ -104,4 +111,28 @@ public static class ImageLoader
|
||||
{
|
||||
element.SetValue(IsLoadingProperty, value);
|
||||
}
|
||||
|
||||
public static readonly AttachedProperty<int> WidthProperty = AvaloniaProperty.RegisterAttached<Image, int>("Width", typeof(ImageLoader));
|
||||
|
||||
public static int GetWidth(Image element)
|
||||
{
|
||||
return element.GetValue(WidthProperty);
|
||||
}
|
||||
|
||||
public static void SetWidth(Image element, int value)
|
||||
{
|
||||
element.SetValue(WidthProperty, value);
|
||||
}
|
||||
|
||||
public static readonly AttachedProperty<int> HeightProperty = AvaloniaProperty.RegisterAttached<Image, int>("Height", typeof(ImageLoader));
|
||||
|
||||
public static int GetHeight(Image element)
|
||||
{
|
||||
return element.GetValue(HeightProperty);
|
||||
}
|
||||
|
||||
public static void SetHeight(Image element, int value)
|
||||
{
|
||||
element.SetValue(HeightProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@ namespace DownKyi.PrismExtension.Dialog;
|
||||
|
||||
public class Dialog : Prism.Services.Dialogs.Dialog
|
||||
{
|
||||
public static readonly AvaloniaProperty ThemeProperty =
|
||||
AvaloniaProperty.RegisterAttached<AvaloniaObject, ControlTheme>("Theme", typeof(Dialog));
|
||||
public static readonly AvaloniaProperty ThemeProperty = AvaloniaProperty.RegisterAttached<AvaloniaObject, ControlTheme>("Theme", typeof(Dialog));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value for the <see cref="ThemeProperty"/> attached property.
|
||||
|
||||
@@ -54,7 +54,7 @@ public class AlertService
|
||||
return ShowMessage(image, title, message, 1);
|
||||
}
|
||||
|
||||
public async Task<ButtonResult> ShowMessage(VectorImage image, string type, string message, int buttonNumber)
|
||||
public async Task<ButtonResult> ShowMessage(VectorImage image, string title, string message, int buttonNumber)
|
||||
{
|
||||
var result = ButtonResult.None;
|
||||
if (_dialogService == null)
|
||||
@@ -65,7 +65,7 @@ public class AlertService
|
||||
var param = new DialogParameters
|
||||
{
|
||||
{ "image", image },
|
||||
{ "title", type },
|
||||
{ "title", title },
|
||||
{ "message", message },
|
||||
{ "button_number", buttonNumber }
|
||||
};
|
||||
|
||||
@@ -317,13 +317,15 @@ public class BuiltinDownloadService : DownloadService, IDownloadService
|
||||
{
|
||||
ChunkCount = SettingsManager.GetInstance().GetSplit(),
|
||||
RequestConfiguration = requestConfiguration,
|
||||
ParallelDownload = true
|
||||
ParallelDownload = true,
|
||||
ParallelCount = 2,
|
||||
MaximumMemoryBufferBytes = 1024 * 1024 * 50
|
||||
};
|
||||
foreach (var url in urls)
|
||||
{
|
||||
var downloader = new Downloader.DownloadService(downloadOpt);
|
||||
var isComplete = false;
|
||||
downloader.DownloadFileCompleted += (_, args) =>
|
||||
downloader.DownloadFileCompleted += (_, _) =>
|
||||
{
|
||||
if (File.Exists(Path.Combine(path, localFileName)))
|
||||
{
|
||||
|
||||
@@ -61,6 +61,8 @@
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="190"
|
||||
asyncImageLoader:ImageBrushLoader.Height="119"
|
||||
Stretch="Fill" />
|
||||
</Border.Background>
|
||||
<Border
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
CornerRadius="5">
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}" />
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="110"
|
||||
asyncImageLoader:ImageBrushLoader.Height="140" />
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
</Interaction.Behaviors>
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}" />
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="185"
|
||||
asyncImageLoader:ImageBrushLoader.Height="115" />
|
||||
</Border.Background>
|
||||
<Border
|
||||
Name="NameInfoPanel"
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="160"
|
||||
asyncImageLoader:ImageBrushLoader.Height="100"
|
||||
Stretch="UniformToFill" />
|
||||
</Border.Background>
|
||||
</Border>
|
||||
@@ -145,7 +147,9 @@
|
||||
CornerRadius="12">
|
||||
<Border.Background>
|
||||
<ImageBrush
|
||||
asyncImageLoader:ImageBrushLoader.Source="{Binding UpHeader}" />
|
||||
asyncImageLoader:ImageBrushLoader.Source="{Binding UpHeader}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="24"
|
||||
asyncImageLoader:ImageBrushLoader.Height="24" />
|
||||
</Border.Background>
|
||||
</Border>
|
||||
<TextBlock
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
CornerRadius="5">
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}" />
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="160"
|
||||
asyncImageLoader:ImageBrushLoader.Height="100" />
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
@@ -83,7 +85,9 @@
|
||||
VerticalAlignment="Center"
|
||||
CornerRadius="12">
|
||||
<Border.Background>
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding UpHeader}" />
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding UpHeader}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="24"
|
||||
asyncImageLoader:ImageBrushLoader.Height="24" />
|
||||
</Border.Background>
|
||||
</Border>
|
||||
<TextBlock
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
CornerRadius="5">
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding CoverUrl}" />
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding CoverUrl}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="190"
|
||||
asyncImageLoader:ImageBrushLoader.Height="119" />
|
||||
</Border.Background>
|
||||
<Grid Width="190" Height="119">
|
||||
<Image
|
||||
|
||||
@@ -37,7 +37,9 @@
|
||||
CornerRadius="5">
|
||||
<Border.Background>
|
||||
<!-- 长宽比:1.6 -->
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}" />
|
||||
<ImageBrush asyncImageLoader:ImageBrushLoader.Source="{Binding Cover}"
|
||||
asyncImageLoader:ImageBrushLoader.Width="190"
|
||||
asyncImageLoader:ImageBrushLoader.Height="119" />
|
||||
</Border.Background>
|
||||
<Grid Width="190" Height="119">
|
||||
<Image
|
||||
|
||||
Reference in New Issue
Block a user