Eren Pinaz

Software Developer

Consuming a RESTful Web Service in Android App - Part 2



In this part of the tutorial, we will create an Android application and consume the API that we've built in the previous part. This tutorial consists of two parts:

 

You can find the source code for this part on Github/NotesAPP

 

Step 1: Creating an Android Project

Open your Android Studio, and then select File -> New -> New Project. You can name the application "NotesAPP". As the project location, we will use the app folder that we've created in the previous part. Click Next.


In the next window, we will choose minimum and maximum SDK versions. We don't need to change anything here. Click Next.


Next, we will create our first Activity. Leave the activity name as "MainActivity" and the layout name as "activity_main". Click Finish.


Step 2: Adding a Model (POJO)

We will create a model that represents a simple note and use it to deserialize and display JSON response data. You can find detailed information about Plain Old Java Object (POJO) here.

In Project Browser, right-click on app -> java -> com.[your project package], and then select New -> Package. Name the package "models" and Click OK.


Right-click on the models folder you've created, and then select New -> Java Class. Name the class "Note". Replace the generated code with:

package com.example.erenp.notesapp.models;

import org.json.JSONException;
import org.json.JSONObject;

public class Note {

    private String Id;
    private String Title;
    private String Content;

    public Note(JSONObject object) {
        try {
            this.Id = object.getString("id");
            this.Title = object.getString("title");
            this.Content = object.getString("content");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public Note(String Title, String Content) {
        this.Title = Title;
        this.Content = Content;
    }

    public String getId() {
        return this.Id;
    }

    public String getTitle() {
        return this.Title;
    }

    public void setTitle(String title) {
        this.Title = title;
    }

    public String getContent() {
        return this.Content;
    }

    public void setContent(String content) {
        this.Content = content;
    }
}

 

Step 3: Adding a Custom Adapter

In order to display notes, we need a custom ArrayAdapter. First, we will create a simple layout that represents a note item.

In Project Browser, right-click on app -> res -> layout, and then select New -> Layout resource file. Name the file "item_note.xml" and click OK.

Open item_note.xml you've created. Switch to Text mode, and replace the generated code with:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <TextView
        android:id="@+id/label_note_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/label_note_id" />

    <TextView
        android:id="@+id/value_note_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/value_note_title"
        android:layout_alignTop="@+id/label_note_id" />

    <TextView
        android:id="@+id/label_note_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/label_note_id"
        android:layout_marginTop="12dp"
        android:text="@string/label_note_title" />

    <TextView
        android:id="@+id/value_note_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@+id/label_note_title"
        android:layout_marginLeft="12dp"
        android:layout_toRightOf="@+id/label_note_title" />
</RelativeLayout>

 

Now we need to take care of those string resource errors. Open strings.xml file, and add following:

<resources>
    <string name="app_name">Notes</string>

    <string name="label_note_id">Note Id</string>
    <string name="label_note_title">Note Title</string>
</resources>

 

Let's create our custom ArrayAdapter now.

In Project Browser, right-click on app -> java -> com.[your project package], and then select New -> Package. Name the package "adapters" and Click OK.

Right-click on adapters folder you've created, and the select New -> Java Class. Name the class "NoteAdapter" and click OK. Replace the generated code with:

package com.example.erenp.notesapp.adapters;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

import com.example.erenp.notesapp.R;
import com.example.erenp.notesapp.models.Note;

import java.util.ArrayList;

public class NoteAdapter extends ArrayAdapter<Note> {
    private static class ViewHolder {
        TextView id;
        TextView title;
    }

    public NoteAdapter(Context context, ArrayList<Note> notes) {
        super(context, R.layout.item_note, notes);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Note note = getItem(position);
        ViewHolder viewHolder;

        if (convertView == null) {
            viewHolder = new ViewHolder();

            LayoutInflater inflater = LayoutInflater.from(getContext());
            convertView = inflater.inflate(R.layout.item_note, parent, false);

            viewHolder.id = (TextView) convertView.findViewById(R.id.value_note_id);
            viewHolder.title = (TextView) convertView.findViewById(R.id.value_note_title);

            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        viewHolder.id.setText(note.getId());
        viewHolder.title.setText(note.getTitle());

        return convertView;
    }
}

 

Step 4: Create an Async HTTP Client

In order to call our API, we will use LoopJ's (James Smith) Android Asynchronous Http Client. This is an asynchronous, call-back based HTTP client built on top of Apache’s HttpClient libraries. With this library, we can make requests outside of the main UI thread. To install this library, we need to add maven dependency using Gradle buildscript in format:

dependencies {
  compile 'com.loopj.android:android-async-http:1.4.9'
}

 

We need to Synchronize Gradle buildscript (build.gradle) to suppress import errors.

In Project Browser, right-click on app -> java -> com.[your project package], and then select New -> Package. Name the package "clients" and Click OK.

Right-click on clients folder you've created, and then select New -> Java Class. Name the class "NoteRestClient". Replace the generated code with:

package com.example.erenp.notesapp.clients;

import android.content.Context;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;

import cz.msebera.android.httpclient.Header;

public class NoteRestClient {
    private static final String BASE_URL = "http://192.168.1.82:5000/";

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(Context context, String url, Header[] headers, RequestParams params,
                           AsyncHttpResponseHandler responseHandler) {
        client.get(context, getAbsoluteUrl(url), headers, params, responseHandler);
    }

    private static String getAbsoluteUrl(String relativeUrl) {
        return BASE_URL + relativeUrl;
    }
}

Be sure to update BASE_URL with your LAN IP.

 

Step 5: Create and Populate the Note List

In this step, we will create a ListView, and then populate it with the data from the API. Let's start by creating a ListView.

Open activity_main.xml file, and then add a new ListView. Set the android:id value to "list_notes".

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.erenp.notesapp.MainActivity">

    <ListView
        android:id="@+id/list_notes"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</RelativeLayout>

 

Now we will make a GET request to our API and populate the list with the returned data. Open MainActivity.java, and then replace the generated code with:

package com.example.erenp.notesapp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;

import com.example.erenp.notesapp.adapters.NoteAdapter;
import com.example.erenp.notesapp.clients.NoteRestClient;
import com.example.erenp.notesapp.models.Note;
import com.loopj.android.http.JsonHttpResponseHandler;

import org.json.JSONArray;
import org.json.JSONException;

import java.util.ArrayList;
import java.util.List;

import cz.msebera.android.httpclient.Header;
import cz.msebera.android.httpclient.message.BasicHeader;

public class MainActivity extends AppCompatActivity {

    private ListView noteList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getNotes();
    }

    private void getNotes() {
        List<Header> headers = new ArrayList<Header>();
        headers.add(new BasicHeader("Accept", "application/json"));

        NoteRestClient.get(MainActivity.this, "api/notes", headers.toArray(new Header[headers.size()]),
                null, new JsonHttpResponseHandler() {
                    @Override
                    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
                        ArrayList<Note> noteArray = new ArrayList<Note>();
                        NoteAdapter noteAdapter = new NoteAdapter(MainActivity.this, noteArray);

                        for (int i = 0; i < response.length(); i++) {
                            try {
                                noteAdapter.add(new Note(response.getJSONObject(i)));
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }

                        noteList = (ListView) findViewById(R.id.list_notes);
                        noteList.setAdapter(noteAdapter);
                    }
                });
    }
}

 

We are telling the server that we are expecting the data in "application/json" format.

 

Final Step: Testing the Application

Before we begin testing, we need to add a special permission to our application. Open AndroidManifest.xml file, and then add:

<uses-permission android:name="android.permission.INTERNET"/>

 

Now we are ready to test our application. I will use Genymotion emulator as the testing platform. You can choose any other AVD or an actual Android device.

Go back to Visual Studio and run your server (CTRL + F5). In Android Studio, press SHIFT + F10 to run your application. Select your emulator or device from the list. 

This is the final result.


Consuming a RESTful Web Service in Android App - Part 1



In this tutorial, we will build a RESTful API using ASP.NET Core 1.0, and then use LoopJ's (James Smith) Android Asynchronous Http Client to make API calls from an Android application. This tutorial consists of two parts:

 

You can find the source code for this part on Github/NotesAPI

 

Step 1: Creating Directories

We are creating a simple note application. Before start creating our project, we will create a directory and name it "Notes". In this directory, we will create two additional folders. One named "api", another named "app".

 

Step 2: Creating an ASP.NET Web API Project

Open VS2015 and select New Project -> Visual C# -> Web. Select ASP.NET Web Application from the list. As the project location, we will use the api folder that we've created before. You can name the project "NotesAPI". Select the latest framework version available and tick Create directory for solution. Click OK.

 

Now we will select the template named Web API located under ASP.NET 5 Templates. Click OK.



Step 3: Adding a Model

Models are objects that representing the data. Our models will be serialized to JSON or XML, and then written to the HTTP response message. Clients that are capable of reading JSON or XML formats can deserialize and use this data. Clients can specify the format by sending Accept header with HTTP requests. In this tutorial, we are going to use "application/json".

Let's create our model that represents a simple note.

In Solution Explorer, right-click on your project name NotesAPI, and then select Add -> New Folder. Name the folder "Models".

 

right-click on Models folder, and then select Add -> Class.


Name the class "Note" and replace the generated code with:

using System;
using System.ComponentModel.DataAnnotations;

namespace NotesAPI.Models
{
    public class Note
    {
        public Guid Id { get; set; }

        [Required]
        public string Title { get; set; }

        [Required]
        public string Content { get; set; }
    }
}

 

Step 4: Creating the Repository

In Solution Explorer, right-click on your project name NotesAPI, and then select Add -> New Folder. Name the folder "Repositories". We will create two files in this folder. The interface INoteRepository and the implementation for this interface NoteRepository.

right-click on Repositories folder, and then select Add -> New Item.

In the next window, select Interface and name it "INoteRepository". Click Add.


Replace the generated code of INoteRepository with:

using System;
using System.Collections.Generic;
using NotesAPI.Models;

namespace NotesAPI.Repositories
{
    public interface INoteRepository
    {
        IEnumerable<Note> GetAll();
        Note GetNoteById(Guid id);
        void Add(Note item);
        void Update(Note item);
        Note Remove(Guid id);
    }
}

 

Now we will create an implementation for this Interface. For simplicity, notes will be stored in a ConcurrentDictionary. In a real app, we would be using an ORM, a database or some other external data source.

right-click on Repositories folder, and then select Add -> Class. Name the class "NoteRepository" and click Add.


Replace the generated code of NoteRepository with:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using NotesAPI.Models;

namespace NotesAPI.Repositories
{
    public class NoteRepository : INoteRepository
    {
        private static readonly ConcurrentDictionary<string, Note> Notes = new ConcurrentDictionary<string, Note>();

        public NoteRepository()
        {
            Add(new Note { Title = "My First Note", Content = "A worthy content" });
            Add(new Note { Title = "Second Note", Content = "A worthy content" });
            Add(new Note { Title = "Third Note", Content = "A worthy content" });
            Add(new Note { Title = "Fourth Note", Content = "A worthy content" });
            Add(new Note { Title = "Fifth Note", Content = "A worthy content" });
            Add(new Note { Title = "Sixth Note", Content = "A worthy content" });
            Add(new Note { Title = "Seventh Note", Content = "A worthy content" });
        }

        public IEnumerable<Note> GetAll()
        {
            return Notes.Values;
        }

        public Note GetNoteById(Guid id)
        {
            Note item;
            Notes.TryGetValue(id.ToString(), out item);
            return item;
        }

        public void Add(Note item)
        {
            item.Id = Guid.NewGuid();
            Notes[item.Id.ToString()] = item;
        }

        public void Update(Note item)
        {
            Notes[item.Id.ToString()] = item;
        }

        public Note Remove(Guid id)
        {
            Note item;
            Notes.TryGetValue(id.ToString(), out item);
            Notes.TryRemove(id.ToString(), out item);
            return item;
        }
    }
}

In order to use our Repository, we need to register it in Startup.cs file. Open the Startup.cs file and replace the ConfigureServices method with:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc()
        .AddJsonOptions(x => x.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver())
        .AddXmlDataContractSerializerFormatters()
        .AddXmlSerializerFormatters();

    // Register our repositories.
    services.AddSingleton<INoteRepository, NoteRepository>();
}

 

Becase we've added extra formatters, we need to add this dependency to project.json file:

"Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-rc1-final"

 

Step 5: Adding a Controller

Our controller will handle the HTTP requests and be responsible for listing, creating, updating and deleting notes. In Solution Explorer, right-click on Controllers folder and then select Add -> New Item.

In the next window, select Web API Controller Class and name it "NotesController". Click Add.


Replace the generated code for NotesController with:

using System;
using System.Collections.Generic;
using Microsoft.AspNet.Mvc;
using NotesAPI.Models;
using NotesAPI.Repositories;

namespace NotesAPI.Controllers
{
    [Route("api/[controller]")]
    public class NotesController : Controller
    {
        [FromServices]
        public INoteRepository NoteRepository { get; set; }

        [HttpGet]
        public IEnumerable<Note> GetAll()
        {
            return NoteRepository.GetAll();
        }

        [HttpGet("{id}", Name = "GetNote")]
        public IActionResult GetById(Guid id)
        {
            var item = NoteRepository.GetNoteById(id);
            if (item == null)
            {
                return HttpNotFound();
            }
            return new ObjectResult(item);
        }

        [HttpPost]
        public IActionResult Create([FromBody]Note item)
        {
            if (item == null)
            {
                return HttpBadRequest();
            }

            NoteRepository.Add(item);
            return CreatedAtRoute("GetNote", new { controller = "Note", id = item.Id.ToString() }, item);
        }

        [HttpPut("{id}")]
        public IActionResult Update(Guid id, [FromBody]Note item)
        {
            if (item == null || item.Id != id)
            {
                return HttpBadRequest();
            }

            var note = NoteRepository.GetNoteById(id);
            if (note == null)
            {
                return HttpNotFound();
            }

            NoteRepository.Update(item);
            return new NoContentResult();
        }

        [HttpDelete("{id}")]
        public void Delete(Guid id)
        {
            NoteRepository.Remove(id);
        }
    }
}

 

Final Step: Configuring the Server

In this final step, we will configure the Kestrel web server. In order to call our API from another device or emulator located in the same network, we need to add our LAN IP (cmd -> ipconfig) to server urls.

Open up projects.json file and find "commands" -> "web" node. Update the value:

"Microsoft.AspNet.Server.Kestrel"

to:

"Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000;http://192.168.1.82:5000"

Be sure to update second url with your LAN IP.

Save the file and select web from the toolbar.


Press CTRL + F5 to run the server.


Now we are ready to test our API. Open up your favorite browser and navigate to http://localhost:5000/api/notes. You should see something like this.

[{"id":"349b21f3-2674-46ed-940e-3d9671f7d9ea","title":"Fourth Note","content":"A worthy content"},
{"id":"9464186f-8376-48f8-8f11-a8318d474a57","title":"Third Note","content":"A worthy content"},
{"id":"e80363f7-6d28-4168-abef-f24e7a049f59","title":"Sixth Note","content":"A worthy content"},
{"id":"d619c754-7301-4ec7-8bc1-7a73ef2408f0","title":"Second Note","content":"A worthy content"},
{"id":"c8898e59-d3f6-4585-9378-dcebbae558df","title":"Seventh Note","content":"A worthy content"},
{"id":"f375c9e3-ae02-4b2c-993c-58a874b0da38","title":"First Note","content":"A worthy content"},
{"id":"2049e938-a01a-4521-9b02-b8af5ca416c4","title":"Fifth Note","content":"A worthy content"}]

 

In the next part, we will consume this API in an Android application.