1

I've been building a simple Xamarin app using MvvmCross framework together with Azure Mobile App service to store and retrieve data from the cloud. UI projects are platform specific.

The main view of my app shows a list of posts and this list is supposed to be retrieved from the Azure cloud. What happens is that after the splash screen, the app just shows a black screen. The call to retrieve the data seems to be fired correctly but the response is never received.

This is my posts view model:

public class PostsViewModel : MvxViewModel
    {
        readonly IPostService _postService;
        readonly IMvxNavigationService _navigationService;
        readonly MvxSubscriptionToken token;

        public PostsViewModel(IPostService postService, IMvxMessenger messenger, IMvxNavigationService navigationService)
        {
            _postService = postService;
            _navigationService = navigationService;

            token = messenger.SubscribeOnMainThread<PostsChangedMessage>
                (async mex => await LoadPosts());

            Posts = new ObservableCollection<PostViewModel>();
            AddNewPostCommand = new MvxAsyncCommand(AddNewPost);
            ShowPostDetailsCommand = new MvxAsyncCommand<PostViewModel>(ShowPostDetails);
        }

        #region Properties
        public ObservableCollection<PostViewModel> Posts { get; set; }

        private bool isLoading = true;
        public bool IsLoading
        {
            get => isLoading;
            set => SetProperty(ref isLoading, value);
        }
        #endregion

        #region Commands
        public IMvxAsyncCommand AddNewPostCommand { get; }
        private async Task AddNewPost()
        {
            await _navigationService.Navigate(typeof(PostViewModel), new Post());
        }

        public IMvxAsyncCommand<PostViewModel> ShowPostDetailsCommand { get; }
        private async Task ShowPostDetails(PostViewModel postViewModel)
        {
            await _navigationService.Navigate(typeof(PostDetailsViewModel), postViewModel);
        }
        #endregion

        #region Functions
        public override async Task Initialize()
        {
            await LoadPosts();
        }

        private async Task LoadPosts()
        {
            // Remove all counters before reloading
            Posts.Clear();

            var posts = await _postService.GetAllPosts();
            foreach(var post in posts)
            {
                var viewModel = new PostViewModel(_postService, _navigationService);
                viewModel.Prepare(post);
                Posts.Add(viewModel);
            }

            IsLoading = false;
        }
        #endregion
    }

This is my post service:

    public class PostService : IPostService
    {
        readonly IPostRepository _repository;
        readonly IMvxMessenger _messenger;

    public PostService(IPostRepository repository, IMvxMessenger messenger)
    {
        _repository = repository;
        _messenger = messenger;
    }

    public async Task<Post> AddNewPost(Post post)
    {
        // Just for testing purposes
        post.Date = DateTimeOffset.Now;
        // Temporary hard-coded author; this will be get from the user object 
        post.Author = "John Smith";

        await _repository.Save(post).ConfigureAwait(false);
        _messenger.Publish(new PostsChangedMessage(this));

        return post;
    }

    public async Task DeletePost(Post post)
    {
        await _repository.Delete(post).ConfigureAwait(false);
        _messenger.Publish(new PostsChangedMessage(this));
    }

    public Task<List<Post>> GetAllPosts()
    {
        return _repository.GetAll();
    }

This is my repository:

public class PostRepository : IPostRepository
{
    MobileServiceClient MobileService
        = new MobileServiceClient(@"https://vntestapp.azurewebsites.net", new LoggingHandler(true));

    IMobileServiceTable<Post> postTable;

public PostRepository()
{
    postTable = MobileService.GetTable<Post>();
}

public Task Delete(Post post)
{
    return postTable.DeleteAsync(post);
}

public async Task<List<Post>> GetAll()
{
    return await postTable.ToListAsync();
}

public async Task<Post> Save(Post post)
{
    await postTable.InsertAsync(post);
    return post;
}

}

3
  • What happens where you comment out the blocking request, everything works fine? Is running platform iOS or Android? If it is android try calling the api inside Task.Run() and see if it returns. Commented Aug 26, 2018 at 16:27
  • Running platform is Android. Calling the api inside Task.Run() works correctly. How is that so? I don't understand the problem. Am I causing a thread deadlock?
    – Salvatore
    Commented Aug 26, 2018 at 17:47
  • I updated this as an answer, I would update the answer with the proper explanation, for now, I think you have good :) Commented Aug 26, 2018 at 19:05

1 Answer 1

0

Use Task.Run() construct for the API call if the running platform is android.

From my practical experience of working with Mvvmcross, in android sometimes, awaited call inside async method blocks that thread and it never returns,

In that case, if you call it inside Task.Run() it just works fine. While iOS doesn't have that problem.

I would look for the deeper explanation to provide the reason for it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.