micahhoover
micahhoover

Reputation: 2160

await seems to quietly return

I have a method that calls await on an async method.

private async void LoadPic(string imageFileName)
{
    StorageFolder sf = Windows.ApplicationModel.Package.Current.InstalledLocation;
    StorageFolder subFolder = await sf.GetFolderAsync("Assets");
    StorageFile sfile = await subFolder.GetFileAsync(imageFileName);

When I set a break point on the very next line, the break point is never hit. It just drops out of the method and returns.

public PixelData GrabPixelData(string imageFileName)
{
    if (!ImageDictionary.ContainsKey(imageFileName))
    {
        // doesn't exist yet, so load it
        LoadPic(imageFileName);
    }

    PixelData pd = new PixelData();
    bool found = false;
    while( found == false ) {
        found = ImageDictionary.TryGetValue(imageFileName, out pd);
    }
    return pd;
   // throw new NullReferenceException();
}

After I call LoadPic() I added a loop that keeps checking to see if it added the image in this file to a Dictionary. It never seems to get added and just hangs.

This method worked fine on a child class that I abstracted it out of.


Edit:

Modified a couple things. Everything seems to work now, but when I assign the results to the child class I get a null exception error (even though the debugger doesn't indicate anything is null!).

I wonder if it has to do with the fact that it is wrapped in a Task.

Child class:

private async void LoadPic()
{
     // I realize the async void is to be avoided, but ... I'm not sure because there isn't anything I want it to return. Should it just return a dummy task?
     sat1.pixelData = await rootPage.GrabPixelData("sat1.png");

LoadPic:

        private async Task<PixelData> LoadPic(string imageFileName)
        {
            StorageFolder sf = Windows.ApplicationModel.Package.Current.InstalledLocation;
            StorageFolder subFolder = await sf.GetFolderAsync("Assets");
            StorageFile sfile = await subFolder.GetFileAsync(imageFileName);
...
            return pd;

GrabPixelData:

public async Task<PixelData> GrabPixelData(string imageFileName)
{
    if (!ImageDictionary.ContainsKey(imageFileName))
    {
        // doesn't exist yet, so load it
        PixelData pd = await LoadPic(imageFileName);
        ImageDictionary.Add(imageFileName, pd);
    }

    var test = ImageDictionary[imageFileName];

    return ImageDictionary[imageFileName];
}

Upvotes: 0

Views: 163

Answers (1)

Stephen Cleary
Stephen Cleary

Reputation: 456322

You should avoid async void. Also, polling shared state to detect completion of an asynchronous operation is a no-no. That kind of CPU usage can get your app rejected from the Windows Store.

I recommend you change LoadPic to return Task<PixelData>. Then change your ImageDictionary from Dictionary<string, PixelData> to Dictionary<string, Task<PixelData>>. Your GrabPixelData method can then look like this:

public Task<PixelData> GrabPixelData(string imageFileName)
{
  if (!ImageDictionary.ContainsKey(imageFileName))
  {
    // doesn't exist yet, so load it
    ImageDictionary.Add(imageFileName, LoadPic(imageFileName));
  }

  return ImageDictionary[imageFileName];
}

Upvotes: 4

Related Questions