【问题标题】:Making a method Async使方法异步
【发布时间】:2014-08-03 00:41:49
【问题描述】:

我有一个方法可以列出媒体库中的所有歌曲。该方法有 2 个方面,它要么从 MediaLibrary 返回 SongsCollection,要么返回自定义对象列表。

public static Task<object> GetSongList(bool lib = true, bool albumArt = true)
{
     MediaLibrary mediaLib = new MediaLibrary();
     var songs = mediaLib.Songs;

     if (lib)
     {
          return songs;
     }
     else
     {
          var list = new List<MusicTitle>();
          foreach (var song in songs)
          {
               list.Add(new MusicTitle()
               {
                   Artist = song.Artist.Name,
                   Title = song.Name,
                   Duration = (new DateTime(song.Duration.Ticks)).ToString("mm:ss"),
                   Album = song.Album.Name, 
                   Art = albumArt ? GetAlbumArt(song, 100) : null
               });
          }

          return list;
      }
  }

MusicTitle 是具有一些属性的自定义类。由于这返回 2 种类型的结果,我将返回类型设置为对象并适当地转换结果。这让 UI 有点支撑,所以我需要它是 async。因此,正如方法所示,我在方法签名中添加了Task&lt;object&gt;,当我这样做时,return songs;return lists; 给出了以下编译错误。

Cannot implicitly convert type 'Microsoft.Xna.Framework.Media.SongCollection' to 'System.Threading.Tasks.Task<object>'

Cannot implicitly convert type 'System.Collections.Generic.List<KVKWindowsPhoneHelper.Core.MediaLibrary.MusicTitle>' to 'System.Threading.Tasks.Task<object>'

我该怎么办?我尝试将返回类型转换为object,但没有奏效。我怎样才能使这个方法async

编辑

以下代码在 Page 的 OnNavigatedTo() 方法中 这会抛出 UnauthorizedAccessException

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    // Set Song List
    List<AlphaKeyGroup<MusicTitle>> songList = await Task.Run(() => AlphaKeyGroup<MusicTitle>.CreateGroups(ListHelper.GetSongList(false, false) as List<MusicTitle>, Thread.CurrentThread.CurrentUICulture, (MusicTitle s) => { return s.Title; }, true));
    listSongs.ItemsSource = songList;
    // Set Artist List
    List<AlphaKeyGroup<MusicArtist>> artistList = await Task.Run(() => AlphaKeyGroup<MusicArtist>.CreateGroups(ListHelper.GetArtistList(false) as List<MusicArtist>, Thread.CurrentThread.CurrentUICulture, (MusicArtist ar) => { return ar.Artist; }, true));
    listArtist.ItemsSource = artistList;
    // Set Album List
    List<AlphaKeyGroup<MusicAlbum>> albumList = await Task.Run(() => AlphaKeyGroup<MusicAlbum>.CreateGroups(ListHelper.GetAlbumList(false, true) as List<MusicAlbum>, Thread.CurrentThread.CurrentUICulture, (MusicAlbum al) => { return al.Album; }, true));
    listAlbums.ItemsSource = albumList;
    // Set Genre List
    List<AlphaKeyGroup<MusicGenre>> genreList = await Task.Run(() => AlphaKeyGroup<MusicGenre>.CreateGroups(ListHelper.GetGenreList(false) as List<MusicGenre>, Thread.CurrentThread.CurrentUICulture, (MusicGenre g) => { return g.Genre; }, true));
    listGenres.ItemsSource = genreList;
    // Set PlayList
    List<AlphaKeyGroup<MusicPlaylist>> playList = await Task.Run(() => AlphaKeyGroup<MusicPlaylist>.CreateGroups(ListHelper.GetPlayList(false) as List<MusicPlaylist>, Thread.CurrentThread.CurrentUICulture, (MusicPlaylist pl) => { return pl.Playlist; }, true));
    listPlaylist.ItemsSource = playList;

}

编辑 2

在我的手机中有 233 首歌曲,异常是在我编写的 ListHelper 类中的一个方法中引发的,其中包括获取歌曲、专辑、播放列表、流派和艺术家的所有方法。引发异常的方法是我获取专辑的专辑封面的方法。这就是方法。

public static BitmapImage GetAlbumArt(Song song, int size = 100 )
{
    BitmapImage img = new BitmapImage(); // EXCEPTION IS THROWN HERE
    img.DecodePixelHeight = size;
    img.DecodePixelWidth = size;

    if (song.Album.HasArt)
    {               
         img.SetSource(song.Album.GetAlbumArt());
    }
    else
    {
         img.UriSource = new Uri("/Images/cover.png", UriKind.Relative);
    }
    return img;
  }

【问题讨论】:

  • 在哪里执行异步操作?
  • 在方法中没有异步操作,我的目标是创建一个异步方法,这样列表的创建就不会阻碍 UI。我不确定我在这里做了正确的事情。
  • 在Task.Run()中运行你的方法体,它将在线程池中排队

标签: c# windows-phone-8 asynchronous windows-phone async-await


【解决方案1】:

您的方法没有做任何异步工作,因此没有理由让它返回Task。相反,如果你想让你的 UI 保持响应,请将其包装在 Task.Run 中,这将在 ThreadPool 线程上排队:

public static object GetSongList(bool lib = true, bool albumArt = true)
{
     MediaLibrary mediaLib = new MediaLibrary();
     var songs = mediaLib.Songs;

     if (lib)
     {
          return songs;
     }
     else
     {
          var list = new List<MusicTitle>();
          foreach (var song in songs)
          {
               list.Add(new MusicTitle()
               {
                   Artist = song.Artist.Name,
                   Title = song.Name,
                   Duration = (new DateTime(song.Duration.Ticks)).ToString("mm:ss"),
                   Album = song.Album.Name, 
                   Art = albumArt ? GetAlbumArt(song, 100) : null
               });
          }

          return list;
      }
}

并在 Task.Run 中使用它:

var obj = await Task.Run(() => GetSongList());

作为一个不相关的附注,我建议你看看你是否可以创建一个公共基类/接口作为返回类型而不是 object,以确保类型安全。

【讨论】:

  • 谢谢,这行得通。 UI 不再举行。但是,当它运行时,会抛出一个 uNauthorizedAccessException 以及包含无效跨线程访问消息的附加信息。我该怎么办?
  • 嗯,您是否在访问此方法中的任何 UI 元素?
  • 你不能在线程池线程中设置ItemSource。使用Deployment.Current.Dispatcher.Invoke并在其中设置itemsource
  • 使用Dispatcher.BeginInvoke 并不能解决我的问题。在填充列表之前,它仍然保留 UI。
  • 非常感谢。我会仔细看看的。 :) 如果我需要帮助,我会发表评论。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 1970-01-01
  • 2020-12-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多