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

时间:2019-08-19 14:49:23

标签: c# image xamarin.forms task ffimageloading

由于要执行定期任务,因此我从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;
    }
}

在viewModel中,我有两个任务: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>

在我的dataTemplate中,我将每个图像的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));
}
}

1 个答案:

答案 0 :(得分:0)

代替此:

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()的使用;尚不清楚为什么有必要。