2015-08-25 17 views
6

Tôi đang phát triển ứng dụng Windows Phone 8.1. Tôi có một màn hình với một danh sách các tiêu đề tin tức với hình thu nhỏ.Không đồng bộ/đang chờ bế tắc trong khi tải xuống hình ảnh

Trước tiên tôi đang làm theo yêu cầu http không đồng bộ để có được bộ sưu tập tin trong JSON (đáp ứng NotifyTaskCompletion pattern)

NewsCategories = new NotifyTaskCompletion<ObservableCollection<NewsCategory>>(_newsService.GetNewsCategoriesAsync()); 

NewsCategory:

public class NewsCategory : ObservableObject 
{ 
    ... 
    public string Title { get; set; } 
    public ObservableCollection<News> Items { get; set; } 
} 

Tin tức:

public class News : ObservableObject 
{ 
    ... 
    public string Title { get; set; } 
    public string ImagePath { get; set; } 
} 

Cho đến nay nó hoạt động hoàn hảo, nhưng ngay sau khi tôi nhận được tài sản ImagePath, tôi muốn tải xuống và hiển thị hình ảnh đã cho. Tôi đã tìm thấy một giải pháp để làm điều đó một cách không đồng bộ ở đây: WP 8.1 Binding image from a http request - để khi xaml nhận được đường dẫn hình ảnh, nó gọi một lớp chuyển đổi (BinaryToImageSourceConverter), cũng sử dụng mẫu NotifyTaskCompletion.

Vấn đề xảy ra trong phương pháp sau đây:

private async Task<BitmapImage> GetImage(string path) 
{ 
    HttpClient webCLient = new HttpClient(); 
    var responseStream = await webCLient.GetStreamAsync(path); 
    var memoryStream = new MemoryStream(); 
    await responseStream.CopyToAsync(memoryStream); 
    memoryStream.Position = 0; 
    var bitmap = new BitmapImage(); 
    await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream()); 
    return bitmap; 
} 

Khi await đầu tiên được gọi, trình gỡ lỗi không bao giờ đạt dòng tiếp theo và các phương pháp không bao giờ trở lại. Biến số string path có nội dung phù hợp.

Cho đến nay tôi đã cố gắng sử dụng ConfigureAwait(false), nhưng nó không hoạt động trong trường hợp của tôi.

Tôi cũng đã phát hiện ra trong topic: Deadlock while using async await, rằng:

Khi bạn đang sử dụng ConfigureAwait(false), bạn cho chương trình của bạn, bạn không nhớ về bối cảnh. Nó có thể giải quyết một số vấn đề bế tắc, nhưng không phải là giải pháp đúng. Các giải pháp đúng là rất có thể không bao giờ chờ đợi cho các nhiệm vụ một cách ngăn chặn, và được không đồng bộ tất cả các cách.

Tôi không biết nơi tôi có thể có nội dung đó theo cách chặn. Điều gì có thể là lý do cho bế tắc đó?

Và nếu đó là tất cả về phương pháp tiếp cận sai, bạn có biết bất kỳ mẫu nào thích hợp hơn để tải hình thu nhỏ xuống một tập hợp các mục không?

Cảm ơn sự giúp đỡ của bạn.


update: như thế nào GetImage gọi: Nó giống như trong chủ đề: WP 8.1 Binding image from a http request

public class WebPathToImage : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, string language) 
    { 
     if (value == null) return null; 
     return new NotifyTaskCompletion<BitmapImage>(GetImage((String)value)); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, string language) 
    { throw new NotImplementedException(); } 

    private async Task<BitmapImage> GetImage(string path) 
    { 
     using (var webCLient = new HttpClient()) 
     { 
      webCLient.DefaultRequestHeaders.Add("User-Agent", "bot"); 
      var responseStream = await webCLient.GetStreamAsync(path).ConfigureAwait(false); 
      var memoryStream = new MemoryStream(); 
      await responseStream.CopyToAsync(memoryStream); 
      memoryStream.Position = 0; 
      var bitmap = new BitmapImage(); 
      await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream()); 
      return bitmap; 
     } 
    } 
} 

và trong XAML:

<Image 
DataContext="{Binding ImagePath, Converter={StaticResource WebPathToImage}}" 
Source="{Binding Result}" 
Stretch="UniformToFill" 
Height="79" Width="79"/> 
+3

Cách gọi 'GetImage'? Hoặc bạn chặn nó bằng cách sử dụng '.Result' hoặc' .Wait'? –

+0

Tôi đã chỉnh sửa bài đăng của mình để hiển thị mã. –

+1

Tôi không trực tiếp thấy bất cứ điều gì có thể sai. Nếu bạn có thể tạo ra một bản sao nhỏ, nhỏ gọn, điều này sẽ giúp ích cho bạn. –

Trả lời

0

Trước tiên, nếu bạn sử dụng Windows Phone 8.1 thì bạn nên sử dụng HttpClient từ không gian tên Windows.Web.Http chứ không phải từ System.Net.Http. Một số lý do được giải thích trên this link.

câu trả lời của tôi sử dụng mới Windows.Web.Http.HttpClient vì vậy phương pháp GetImage của bạn có thể trông như thế này:

 private async Task<BitmapImage> GetImage(string path) 
     { 
      using (var webCLient = new Windows.Web.Http.HttpClient()) 
      { 
       webCLient.DefaultRequestHeaders.Add("User-Agent", "bot"); 
       var responseStream = await webCLient.GetBufferAsync(new Uri(path)); 
       var memoryStream = new MemoryStream(responseStream.ToArray()); 
       memoryStream.Position = 0; 
       var bitmap = new BitmapImage(); 
       await bitmap.SetSourceAsync(memoryStream.AsRandomAccessStream()); 
       return bitmap; 
      } 
     } 

Tôi đã thử nghiệm phương pháp này trên một URL mẫu và nó hiển thị đúng trong một điều khiển Image.

Thứ hai, tại sao bạn không chỉ để cho các Image kiểm soát xử lý tải BitmapImage mà không cần bộ chuyển đổi, do đó XAML của bạn trông như thế này:

<Image 
    Source="{Binding ImagePath}" 
    Stretch="UniformToFill" 
    Height="79" 
    Width="79" /> 

Bằng cách này bạn ImagePath có thể là một đường dẫn đến một nguồn tài nguyên từ internet và tài nguyên địa phương.

0

Cố gắng có lẽ để gọi cho bạn getImage vào Task.Factory .Run để buộc nhiệm vụ được thực hiện trong một chuỗi khác.

Chú ý đến bạn Tạo bitmap bạn có thể gặp vấn đề với nó vì bitmap không được tạo trong chuỗi giao diện người dùng.

Các vấn đề liên quan