I'm writing an WP8 app, and wanna save some data when app is deactivated or closed.

I've tried the new WinRT api, but not working while app is being deactivated :|

The code:

 public async Task CacheData()
        {

            StorageFolder localFolder = ApplicationData.Current.LocalFolder;

                string data = "Hello!";

                ///WinRT not Working !!!

                // Get a reference to the Local Folder 
                // Create the file in the local folder, or if it already exists, just replace it 

                StorageFile storageFileIsolated = await localFolder.CreateFileAsync("Data.data", CreationCollisionOption.ReplaceExisting);
                Stream writeStream = await storageFileIsolated.OpenStreamForWriteAsync();
                using (StreamWriter writer = new StreamWriter(writeStream))
                {
                    await writer.WriteAsync(data);
                }
            }
        }

but working fine with the old api

                string data = "Hello!";

                using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (IsolatedStorageFileStream rawStream = isf.CreateFile("Data.store"))
                    {
                        StreamWriter writer = new StreamWriter(rawStream);
                        writer.WriteLine(data); // save the message
                        writer.Close();
                    }
                }

I don't know what the problem is :| !!!

I tested it with this code

 private  void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
            ViewModel.CacheExchangeRates().Wait();
            System.Diagnostics.Debug.WriteLine("deactivated !!!!!");
        }

never printed deactivated !!!

有帮助吗?

解决方案

The problem is with await keyword. In short, await really doesn't block the executing thread, as it may sound. Quite the opposite, when execution comes to await keyword, it looks like return from the caller's point of view. The continuation (what comes after await keyword) is scheduled to run later, when the task associated with await is completed. For more details about that, I encourage you to read more about await and Task, starting, for example, here.

In your case, when Deactivated or Closing is called, you probably make a call similar to:

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    CacheData();
}

When execution comes to the first await keyword (that is, to the line StorageFile storageFileIsolated = await localFolder.CreateFileAsync("Data.data", CreationCollisionOption.ReplaceExisting);), your CacheData() method returns control to the caller. Everything else will run later, when that task is completed. But you're not waiting for that in your Application_Deactivated method. Instead, execution continues and control leaves the Application_Deactivated.

When control leaves the Application_Deactivated, your app is considered to be ready to shutdown. But in fact it's not ready, because await writer.WriteAsync(data); is probably not even started yet. That's why your app closes without writing anything.

Btw, if your app is not tombstoned during deactivation, as if you return to it quickly, the WriteAsync should be completed eventually. But of course it's not what you expect.

In order to fix this, you need to run your file write operation synchronously. By the way, this is precisely what old API does, and that's why it works. The easiest way to fix your problem would be to change your CacheData function to return Task instead of void (to public async Task CacheData()), and use Task.Wait() in your Application_Deactivated handler. Like this:

public async Task CacheData()
    {

        StorageFolder localFolder = ApplicationData.Current.LocalFolder;

            string data = "Hello!";

            ///WinRT not Working !!!

            // Get a reference to the Local Folder 
            // Create the file in the local folder, or if it already exists, just replace it 

            StorageFile storageFileIsolated = await localFolder.CreateFileAsync("Data.data", CreationCollisionOption.ReplaceExisting);
            Stream writeStream = await storageFileIsolated.OpenStreamForWriteAsync();
            using (StreamWriter writer = new StreamWriter(writeStream))
            {
                await writer.WriteAsync(data);
            }            
    }

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
    CacheData().Wait();
}

其他提示

I ran into the same issue, fixed it as

StorageFile storageFileIsolated = localFolder.CreateFileAsync("Data.data", CreationCollisionOption.ReplaceExisting).AsTask().Result;
Stream writeStream = storageFileIsolated.OpenStreamForWriteAsync().Result;
using (StreamWriter writer = new StreamWriter(writeStream))
{
    writer.WriteAsync(data).Wait();
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top