Forum Xamarin.Forms

Multiple Async-Await calls in same method - skipping calls in Android

ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

In my XF solution, I am creating sample data using a series of async-await calls. In Windows Phone all data is created. But in Android some data items are not created. My code structure is as follows:

`private async void CreateSampleData()
{
MyObject mo = new MyObject(...Item 1 Details...);
await mo.SaveItemAsync();

mo = new MyObject(...Item 2 Details...);
await mo.SaveItemAsync();

mo = new MyObject(...Item 3 Details...);
await mo.SaveItemAsync();

... and so on ...
}`

Any ideas on why this is happening only in Android and not in WP (I have not tested in ios)? Any work around?

Answers

  • adamkempadamkemp USInsider, Developer Group Leader mod

    What does SaveItemAsync do? Maybe it's not returning a Task that waits on completion.

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    @adamkemp No, the method is defined as below.

    public Task SaveItemAsync()
    {
      ... ...  ...  ...
    }
    

    Actually I have taken this from @CharlesPetzold 1st preview edition book.

    After reviewing this code, I have removed the async and await in the CreateSampleCode() method as follows:

    private async void CreateSampleData()
    {
       MyObject mo = new MyObject(...Item 1 Details...);
       await mo.SaveItemAsync();
    
       mo = new MyObject(...Item 2 Details...);
       await mo.SaveItemAsync();
    
       mo = new MyObject(...Item 3 Details...);
       await mo.SaveItemAsync();
    
        ... and so on ...
     }
    

    But still my issue is not resolved.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    I'm not sure you understood my question. What are the contents of that method?

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    The code chain is as follows:

    // In the HomePage.cs
    private async void CreateSampleData()
    {
       MyObject mo = new MyObject(...Item 1 Details...);
       await mo.SaveItemAsync();
    
       mo = new MyObject(...Item 2 Details...);
       await mo.SaveItemAsync();
    
       mo = new MyObject(...Item 3 Details...);
       await mo.SaveItemAsync();
    
        ... and so on ...
     }
    
    // In the ItemViewModel
    public Task SaveItemAsync()
    {
        // Formulate body of the file
        string text = this.Name + "/n" + ... ;
    
        return FileHelper.WriteTextAsync (this.FileName, text);
    }
    
    
    // In FileHelper.cs
    static IFileHelper fileHelper = DependencyService.Get<IFileHelper> ();
    
    public static Task WriteTextAsync (string filename, string text)
    {
        return fileHelper.WriteTextAsync (filename, text)
    }
    
    // In the FileHelper.cs in the .Android project
    public async Task WriteTextAsync (string filename, string text)
    {
        string filepath = GetFilePath (filename);
        using (StreamWriter writer = File.CreateText(filepath)) {
            await writer.WriteAsync (text);
        }
    }
    

    All of the dependency code is taken from Petzold's book.

  • AndrewMobileAndrewMobile USMember ✭✭✭✭

    What do you mean by "In Windows Phone all data is created. But in Android some data items are not created" ?

    How do you what is created and it's not?
    Your codes only shows that you save some strings in a file.

    Maybe it's an issue how you display those items in the UI?

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    @AndreiNitescu I hope you understand that in Xamarin.Forms the UI is in the common project (in my case it is a PCL one). So the same UI (here it is a ListView which is sourced by same view model) is used to display in all 3 platforms.

    And I say when all data is not created, I mean:

    1. I am creating a total of 9 files with different set of data.
    2. Since all members of my view model can be converted to string, I convert them to string and save each item in a separate file. I am sure there are better ways to store data but for the present I am doing this.
    3. Out of the 9 files, on the Android (using both Kitkat and Lollipop) only 6 files are actually saved in which some files are skipped in creation. But on Windows Phone all 9 files are created and saved.

    My issue is not UI related. You are mistaken if you think that I have decided that not all data is created because I am not seeing all the data in UI. While debugging mode, you can put break points and see how many files are present before populating the view model.

  • AndrewMobileAndrewMobile USMember ✭✭✭✭

    OK, I got it, it's not an UI related issue.

    It's probably an issue in the IFileHelper implementation on Android
    https://github.com/xamarin/xamarin-forms-book-preview/blob/master/Chapter04/NoteTaker10/NoteTaker10/NoteTaker10.Android/FileHelper.cs

    It's interesting no exception is being thrown. I wonder why

  • AndrewMobileAndrewMobile USMember ✭✭✭✭

    If you call ReadTextAsync after calling WriteTextAsync on the same file, how does it work ?

  • adamkempadamkemp USInsider, Developer Group Leader mod

    Could you share a sample project showing what you are doing (a reproduction if necessary) that shows this behavior? I think we're just missing some important pieces of the puzzle, and it's very difficult to find the answer without a complete picture. There are too many assumptions being made.

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    That's a good idea @adamkemp . I will work on it this weekend. Probably that may clear what I am doing wrong...

  • AndrewMobileAndrewMobile USMember ✭✭✭✭

    @ShantimohanElchuri

    I hope you understand that in Xamarin.Forms the UI is in the common project (in my case it is a PCL one). So the same UI (here it is a ListView which is sourced by same view model) is used to display in all 3 platforms.

    Thanks for the intro on PCL and how Xamarin Forms works. I had no idea how it works. This the WinForms forum right?

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭
    edited May 2015

    @AndreiNitescu This is not WinForms forum. This is Xamarin.Forms forum. There is no WinForms here as Xamarin doesn't have any API for Windows as it implements .NET for iOS, Mac & Android and .NET is native to Windows. But Xamarin.Forms API can be compiled for Windows Phone and Windows (introduced recently).

  • AndrewMobileAndrewMobile USMember ✭✭✭✭

    @ShantimohanElchuri I was kidding.

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    I needed solutions...

  • BrianRepettiBrianRepetti USUniversity ✭✭✭

    How are you calling CreateSampleData? Are you doing it from a button click, or the constructor?

    Can you post that code? Just a hunch.

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    Here is my code:

    using System;
    using System.Collections.ObjectModel;
    using System.Collections.Generic;
    using System.Linq;
    using XPA_FileOps_XFP;
    using System.Threading.Tasks;
    using Xamarin.Forms;
    
    namespace MyProject
    {
        public class moFolder
        {
            public ObservableCollection<MyItem> MyItems { private set; get; }
    
            public moFolder ()
            {
                this.MyItems = new ObservableCollection<MyItem> ();
    
                GetFilesAsync ();
            }
    
            async void GetFilesAsync()
            {
                // Sort the filenames
                IEnumerable<string> filenames =
                    from filename in await FileHelper.GetFilesAsync ()
                    where filename.EndsWith (".mo")
                    orderby (filename)
                    select filename;
    
                            if (filenames.Count() == 0)
                            {
                                    // There is no data stored. Create sample data
                    if (Device.OS == TargetPlatform.WinPhone) {
                        Task task = Task.Run (() => {
                            CreateSampleData ();
                        });
                        task.Wait ();
                    } else {
                        CreateSampleData ();
                    }
    
                        filenames =
                            from filename in await FileHelper.GetFilesAsync()
                            where filename.EndsWith(".mo")
                            orderby (filename)
                            select filename;
                    }
    
                // Store them in the MyItems collection
                foreach (string filename in filenames) {
                MyItem mo = new MyItem (filename);
                await mo.LoadmoAsync ();
                this.MyItems.Add (mo);
    
                SetItemViews (mo);
                }
            }
    
            private void SetItemViews (MyItem mo)
            {
                moItem item = new moItem (mo);
                ... ... ...
            }
    
            private void CreateSampleData()
            {
                // This code given earlier
            }
    
        }  // end of: class moFolder
    
    }  // end of: namespace
    
  • BrianRepettiBrianRepetti USUniversity ✭✭✭

    You shouldnt call async methods in the constructor like that. They wont await properly.

    There are a few methods around this.

    For instance: https://msdn.microsoft.com/en-us/magazine/jj991977.aspx

  • ShantimohanElchuriShantimohanElchuri USMember ✭✭✭✭✭

    I will give a shot to them...

  • AshleyJacksonAshleyJackson GBMember ✭✭

    Did you get a solution to this? I am having a similar issue.

  • adamkempadamkemp USInsider, Developer Group Leader mod

    @AshleyJackson , I'll ask the same thing I asked before of Shantimohan: can you provide an example project that shows this issue?

    I would say 9 times out of 10 when people say that they're having problems with async/await it's because they're misunderstanding something and doing something wrong. That's why it helps to have a project to look at so I can see exactly what you're doing and where you might have gone astray. If you can't show what you're doing then it's really difficult to help you.

  • ylemsoulylemsoul RUMember ✭✭✭
    edited June 2015

    @ShantimohanElchuri, at least the problem with above code is async void CreateSampleData(). No one awaits it so you have each time non-deterministic results because method returns immediately to the caller after encountering first await while doing async work. So some of your missing writes could occur after reading the files.
    Probably the lines if (Device.OS == TargetPlatform.WinPhone) .. task.Wait() for WP are for attempt to delay reading until files are created. May be it worked on specific config. But it will not help.

    Change return type to Task, await before read operation and check @breps links.

Sign In or Register to comment.