如何优化大量图像的加载?



我从 REST 服务上传大量图像,并使用它们来创建各种 gif 图像,这要归功于定期任务。我想知道如何优化我的代码,增强它并使其更快。

public class WebcamListViewModel : BaseViewModel
{
public ICommand InitializeWebcamsCommand { set; get; }
public ICommand OpenVideoWebcamCommand { set; get; }
private List<Webcam> _ListOfWebcam { get; set; }
public List<Webcam> ListOfWebcam
{
get { return _ListOfWebcam; }
set
{
_ListOfWebcam = value;
OnPropertyChanged();
}
}
private IFolder folder;
private int _Counter { get; set; }
public int Counter
{
get { return _Counter; }
set
{
_Counter = value;
OnPropertyChanged();
}
}
private Task SetFrameOnViewTask;
private Task DownloadFramesTask;
CancellationTokenSource tokenSourceSetFrame = new CancellationTokenSource();
CancellationTokenSource tokenSourceDownloadFrames = new CancellationTokenSource();
CancellationToken cancellationTokenSetFrame;
CancellationToken cancellationTokenDownloadFrames;
public WebcamListViewModel(INavigationService navigationService, IApiAutostradeManagerFactory apiAutostradeManagerFactory) : base(navigationService,apiAutostradeManagerFactory)
{
OpenVideoWebcamCommand = new Command<Webcam>(async (webcam) => {
await navigationService.NavigateAsync(Locator.WebcamVideoPopUpPage);
Messenger.Default.Send(new InfoWebcamVideoMessage(webcam.c_mpr, webcam.c_uuid, webcam.t_str_vid));
});
InitializeWebcamsCommand = new Command(async () => await RunSafe(InitializeWebcams()));
InitializeWebcamsCommand.Execute(null);
cancellationTokenDownloadFrames = tokenSourceDownloadFrames.Token;
DownloadFramesTask = new Task(async () => {
cancellationTokenDownloadFrames.ThrowIfCancellationRequested();
while (true)
{
try
{
await DownloadAndSetWebcamImages();
await Task.Delay(2000);
if (cancellationTokenDownloadFrames.IsCancellationRequested)
{
// Clean up here, then...
cancellationTokenDownloadFrames.ThrowIfCancellationRequested();
}
}
catch (System.FormatException e)
{
Console.WriteLine(e.Message);
}
}
}, cancellationTokenDownloadFrames);
SetFrameOnViewTask = new Task(async () =>
{
cancellationTokenSetFrame.ThrowIfCancellationRequested();
while (true)
{
try
{
Counter++;
await Task.Delay(500);
if (cancellationTokenSetFrame.IsCancellationRequested)
{
Counter = 0;
// Clean up here, then...
cancellationTokenSetFrame.ThrowIfCancellationRequested();
}
}
catch (FormatException e)
{
Console.WriteLine(e.Message);
}
}
}, cancellationTokenSetFrame);
}
private async Task InitializeWebcams()
{
folder = await FileSystem.Current.LocalStorage.GetFolderAsync("WebcamImages");
ListOfWebcam = await RepositoryHelper.Instance.WebcamRepository.GetItemsAsync();
ListOfWebcam = ListOfWebcam.OrderByDescending(x => x.n_prg_km).ToList();
try
{
if (DownloadFramesTask.Status == TaskStatus.Running)
{
try
{
tokenSourceDownloadFrames.Cancel();
}
finally
{
tokenSourceDownloadFrames.Dispose();
}
}
DownloadFramesTask.Start();
if (SetFrameOnViewTask.Status == TaskStatus.Running)
{
try
{
tokenSourceSetFrame.Cancel();
}
finally
{
tokenSourceSetFrame.Dispose();
}
}
SetFrameOnViewTask.Start();
}
catch (System.InvalidOperationException)
{}
}
private async Task DownloadAndSetWebcamImages()
{
await ImageService.Instance.InvalidateCacheAsync(CacheType.All);
foreach (var web in ListOfWebcam)
{
web.image1 = await GetWebcamFrame(web.frame1);
web.image2 = await GetWebcamFrame(web.frame2);
web.image3 = await GetWebcamFrame(web.frame3);
web.image4 = await GetWebcamFrame(web.frame4);
}
}
private async Task<ImageSource> GetWebcamFrame(string urlFrame)
{
try
{
var frameResponse = await ApiManager.GetWebcamFrame(urlFrame);
var base64Image = await frameResponse.Content.ReadAsStringAsync();
byte[] imageData = Convert.FromBase64String(base64Image);
return (ImageSource.FromStream(() => { return new MemoryStream(imageData); }));
}
catch (FormatException e)
{
throw e;
}
}

在我的视图模型中,我有两个任务:DownloadFramesTask 和 SetFrameOnViewTask,每 500 毫秒递增一个计数器,用于在转弯处显示四个帧中的一个。

<ListView ItemsSource="{Binding ListOfWebcam}"
SeparatorVisibility="None"
CachingStrategy="RetainElement"
RowHeight="250"
VerticalOptions="FillAndExpand"
x:Name="ListWebcam">
<ListView.Header>
<StackLayout x:Name="HeaderStackLayout"
Padding="5,25,0,30"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand">
<Label  x:Name="LabelHeader"
Text="Webcam:"
FontSize="Large"
FontAttributes="Bold"
TextColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="Center"
HorizontalOptions="Start" Margin="10,0,0,0"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<controls:ExtendedViewCell SelectedItemBackgroundColor="#fafafa">
<Grid x:Name="GridWebcam">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Frame Grid.Column="1"
Grid.RowSpan="2"
CornerRadius="20"
BackgroundColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
HasShadow="True"
Margin="5,10">
<StackLayout>
<Label Text="{Binding t_str_vid,Converter={StaticResource WebcamNameConverter}}"
FontSize="Medium"
TextColor="White"
FontAttributes="Bold"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</Label>
<Label TextColor="White"
FontSize="Medium"
Text="{Binding direzione,Converter={StaticResource DirectionToStringConverter}}"/>
<StackLayout Orientation="Horizontal">
<ffimageloading:CachedImage DownsampleToViewSize="True"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
IsVisible="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame1Converter}}"
IsEnabled="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame1Converter}}"
Source="{Binding image1}"/>
<ffimageloading:CachedImage x:Name="SecondFrame"
DownsampleToViewSize="True"
Grid.Row="1"
Grid.Column="0"
IsVisible="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame2Converter}}"
IsEnabled="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame2Converter}}"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
Source="{Binding image2}"/>
<ffimageloading:CachedImage x:Name="ThirdFrame"
Grid.Row="1"
Grid.Column="0"
IsVisible="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame3Converter}}"
IsEnabled="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame3Converter}}"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
Source="{Binding image3}"/>
<ffimageloading:CachedImage x:Name="FourthFrame"
Grid.Row="1"
Grid.Column="0"
IsVisible="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame4Converter}}"
IsEnabled="{Binding Source={x:Reference WebcamList},Path=BindingContext.Counter,Converter={StaticResource VisibleFrame4Converter}}"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
Source="{Binding image4}"/>
<iconize:IconButton Text="fas-play-circle"
FontSize="50"
HorizontalOptions="EndAndExpand"
VerticalOptions="EndAndExpand"
TextColor="White"
Command="{Binding BindingContext.OpenVideoWebcamCommand, Source={x:Reference ListWebcam}}"
CommandParameter="{Binding}"
BackgroundColor="Transparent"/>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</controls:ExtendedViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

在我的数据模板中,我将每个图像的 isVisible 和 isEnabled 与计数器绑定,由于四个转换器,该图像被转换为布尔值。我将只展示其中之一:

public class VisibleFrame1Converter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, 
CultureInfo culture)
{
if ((int)value % 4 == 0)
return true;
else
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

这是我的模型:

public class Webcam : INotifyPropertyChanged
{
[PrimaryKey, AutoIncrement]
public int idWebcam { get; set; }
public string c_mpr { get; set; }
public int c_tel { get; set; }
public string c_uuid { get; set; }
public string direzione { get; set; }
public string frame1 { get; set; }
public string frame2 { get; set; }
public string frame3 { get; set; }
public string frame4 { get; set; }
public double n_crd_lat { get; set; }
public double n_crd_lon { get; set; }
public int n_ind_pri { get; set; }
public double n_prg_km { get; set; }
public int ramo { get; set; }
public int str { get; set; }
public string strada { get; set; }
public string t_str_vid { get; set; }
public string thumb { get; set; }
// modified code
ImageSource image1 ;
public ImageSource Image1
{
set
{
if (image1 != value)
{
image1 = value;
OnPropertyChanged("Image1");
}
}
get
{
return image1 ;
}
}
ImageSource image2 ;
public ImageSource Image2
{
set
{
if (image2 != value)
{
image2 = value;
OnPropertyChanged("Image2");
}
}
get
{
return image2 ;
}
}
ImageSource image3 ;
public ImageSource Image3
{
set
{
if (image3 != value)
{
image3 = value;
OnPropertyChanged("Image3");
}
}
get
{
return image3 ;
}
}
ImageSource image4 ;
public ImageSource Image4
{
set
{
if (image4 != value)
{
image4 = value;
OnPropertyChanged("Image4");
}
}
get
{
return image4 ;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

取而代之的是:

foreach (var web in ListOfWebcam)
{
web.image1 = await GetWebcamFrame(web.frame1);
web.image2 = await GetWebcamFrame(web.frame2);
web.image3 = await GetWebcamFrame(web.frame3);
web.image4 = await GetWebcamFrame(web.frame4);
}

您可以一次执行所有异步任务:

var tasks = new List<Task>();
tasks.Add(GetWebcamFrame(web.frame1));
// add more tasks here
await Task.WhenAll(tasks);

你也可以删除你对Task.Delay()的使用;目前还不清楚为什么这是必要的。

相关内容

  • 没有找到相关文章

最新更新