Truecolor
Truecolor

Reputation: 469

How to populate a ListView in Xamarin Android?

I have a Web Api that retrieves data from SQL database. I need to consume web api in xamrin for android. I am not sure how to call the GET and Post methods based on button click event. Right now with the code I have written, when I click the button to populate the list, I am getting an empty screen in the App. My API is working fine in Postman, but I don't know how to make it work on Xamarin Android App.

I have created a separate Library in my solution which has my Models and API Service class.

Web API Get List method

// GET: api/Books
[HttpGet]
[Route("api/books")]
public IHttpActionResult Get()
{
  IEnumerable<BookDTO> books;
  books = from b in db.Books
    select new BookDTO()
    {
       Id = b.Id,
       Title = b.Title,
       AuthorName = b.Author.Name
    };
       return Ok(books);
 } 

API Service class

public static async Task<BookDTO> GetBooks()
{
    var client = new HttpClient();

    var msg = await client.GetAsync(url);

    if (msg.IsSuccessStatusCode)
    {
        using (var stream = await msg.Content.ReadAsStreamAsync())
        {
            using (var streamReader = new StreamReader(stream))
            {
                var str = await streamReader.ReadToEndAsync();
                var obj = JsonConvert.DeserializeObject<BookDTO>(str);
                return obj;
            }
        }
    }
    return null;
}

MainActivity.cs

public class MainActivity : Activity
{
static readonly List<string> _bookTitles = new List<string>();
private ListView _list;

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    // Set our view from the "main" layout resource
    SetContentView(Resource.Layout.Main);

    // Get the button from the layout Resource and attach an event to it
    Button getBooks = FindViewById<Button>(Resource.Id.GetBooks);
    _list = FindViewById<ListView>(Resource.Id.listView1);


    getBooks.Click += async (sender, e) =>
    {
        var books = await BooksApiService.GetBooks();
        ShowTitles(books);
    };
}
    private void ShowTitles(BookDTO books)
    {
        _bookTitles.Clear();
        foreach (var book in books.Title)
        {
            _bookTitles.Add(book.ToString());
        }

    }

Upvotes: 0

Views: 882

Answers (2)

Felix Too
Felix Too

Reputation: 11941

Your Web API method's return type is IEnumerable<BookDTO>. This means that you are returning an IEnumerable List of books to the client app. Make these slight changes:

API Service class

public static async Task<IEnumerable<BookDTO>> GetBooks()
{
    var client = new HttpClient();

Change the return type of your Task to IEnumerable<BookDTO> as shown above.

if (msg.IsSuccessStatusCode)
    {
        using (var stream = await msg.Content.ReadAsStreamAsync())
        {
            using (var streamReader = new StreamReader(stream))
            {
                var str = await streamReader.ReadToEndAsync();
                var obj = JsonConvert.DeserializeObject<IEnumerable<BookDTO>>(str);
                return obj;
            }
        }
    }

Change the type to be deserialized to, from BookDTO to IEnumerable<BookDTO> as shown above.

MainActivity.cs

 private void ShowTitles(IEnumerable<BookDTO> books)
    {
       ...
        /*Change this block accordingly.*/
        foreach (var book in books)
        {                 
            _bookTitles.Add(book.Title.ToString());
        }    
      ...
    }

The ShowTitles() should take IEnumerable<BookDTO> as a parameter, since you might want to iterate through each book and retrieving the respective Title and adding that to the _bookTitles list.

getBooks.Click += async (sender, e) =>
    {
        /*This is will work, but it's not recommended. I'll update it later.*/
        var books = await BooksApiService.GetBooks();
        ShowTitles(books.Result);
    };

However, the section above will remain as is since you've used the var type which means the compiler will determine the explicit type of the variable, based on the usage.

Upvotes: 2

Elvis Xia - MSFT
Elvis Xia - MSFT

Reputation: 10841

My API is working fine in Postman, but I don't know how to make it work on Xamarin Android App.

The problem is, on server side, you return an IEnumerable<BookDTO> object. But on Client side, you deserialize it into a BookDTO object using var obj = JsonConvert.DeserializeObject<BookDTO>(str);.

Please try deserialize it into an IEnumerable<BookDTO> with var obj = JsonConvert.DeserializeObject<IEnumerable<BookDTO>>(str);

If the problem still persists, please debug to check what the str is by var str = await streamReader.ReadToEndAsync();

Upvotes: 1

Related Questions