Introduction

In this post we will build an Android App to communicate with the API we built in Part 3. The application will be very basic and is no way ready for production, but you will get the basic idea on how to move forward.

Requirements

  • Android Studio - Any version that supports your targeted Android version
  • Android Phone - Any Android phone will work, you can also use the Emulator
  • A Webserver with an API - As shown in Part 3

Getting Started

  1. Open Android Studio on your computer.
  2. Click on Start a new Android Studio Project.
  3. Enter all the Required information on the screen and click next, here's what I entered:
  4. Select the minimum version of Android you would like to support and click next, if you need more information on versions you can see here.
  5. Make sure Blank Activity is selected and click next.
  6. You can just click on Finish on the last screen.
  7. To perform the API requests to our server we will be using a Client
  8. To add it your App, open up your app's build.gradle file using the Project Explorer
  9. Under dependencies add compile 'com.loopj.android:android-async-http:1.4.9', it should look something like this:
  10. A notification should pop up on the top of the editor telling you that your Gradle files have changed since your last sync..., click on the Sync Now link on the right of that notification.
  11. We are now ready to start some actual coding.

Code

UI

We will first create a simple UI to toggle. Here are the steps to do it:

  • Using the Project Explorer we need to open up activity_main.xml which can be found under app/res/layout
  • If it isn't already selected we need open up the Text view using the button on the bottom of the screen.
  • We will add a simple Switch by removing the existing content and replacing it with:
<?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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
        <Switch
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Pin 18: "
            android:id="@+id/switch1"
            android:layout_marginLeft="10px"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true" />
</RelativeLayout>
If you look closely I have just added a `Switch` element with a label to the file, you can verify this by looking at the design view.

For this example App, I will be just controlling 1 pin but it can be extended for more pins by adding more of the `Switch` element and changing the `android:id` to be unique
  • You can go to the Run menu in the menu bar, and select Run if your phone is connected via USB to the computer. This should open up the app and you should see the toggle switch, you can even toggle it on or off. Of course we haven't hooked it up to anything yet so it won't do anything!

Adding the Logic

  • Now to add the API logic, we will create a new file under app/java/<your-package-name> by right clicking on the folder in the Project Explorer and selecting New -> Java Class. Lets name this class APIHelpers.

  • According to the HTTP Client documentation, we will now create add simple API Helpers to help us make the API requests with the following code:

package xyz.fivep.androidapiapp;

import com.loopj.android.http.*;

/**
 * Created by shrikant on 20/11/15.
 */
public class APIHelpers {
    private static final String BASE_URL = "http://192.168.8.108:8080/";

    private static AsyncHttpClient client = new AsyncHttpClient();

    public static void get(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.addHeader("Content-Type", "application/json");
        client.get(getAbsoluteUrl(url), params, responseHandler);
    }

    public static void post(String url, RequestParams params, AsyncHttpResponseHandler responseHandler) {
        client.addHeader("Content-Type", "application/json");
        client.post(getAbsoluteUrl(url), params, responseHandler);
    }

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

  • Now to add the logic to actually make the correct requests. We will first open up the MainActivity.java file, it should be under app/java/<your-package-name>

  • We first remove the menu by removing the following lines of code:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.menu_main, menu);
    return true;
  }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
  // Handle action bar item clicks here. The action bar will
  // automatically handle clicks on the Home/Up button, so long
  // as you specify a parent activity in AndroidManifest.xml.
  int id = item.getItemId();

  //noinspection SimplifiableIfStatement
  if (id == R.id.action_settings) {
      return true;
  }
  return super.onOptionsItemSelected(item);
}
  • Will first declare a variable and initialize it to to the toggle switch with the following code:
Switch mSwitch = (Switch) findViewById(R.id.switch1);
  • We will now make an API request to check the status of the pin so that the toggle is correctly placed when the App is started. We will do it with the following code:
RequestParams params = new RequestParams();
APIHelpers.get("api/list", params, new JsonHttpResponseHandler() {
  @Override
  public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
    try {
      mSwitch.setChecked(response.getBoolean("18"));
    } catch (JSONException e) {
        e.printStackTrace();
    }
  }
});

This piece of codes makes a request to the api/list endpoint, and on a successful response, we set the value of the switch to the Boolean value for the pin(here pin 18). We must surround all JSON gets with try/catch blocks because there is always a possibility that the object will not exist.

  • We will now add a Listener to the Switch that makes a request to the API if it is toggled. We use the following code:
mSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
  @Override
  public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    RequestParams params = new RequestParams();
    APIHelpers.post("api/toggle/18", params, new JsonHttpResponseHandler() {
      @Override
      public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
        Log.d("APIApp", "Successfully Toggled");
      }
      @Override
      public void onFailure(int statusCode, Header[] headers, String error, Throwable throwable) {
        Log.d("APIAPP", "Failed with status code: "+statusCode+ "and error: " + error);
      }
    });
  }
});

This code makes a similar call to the api/toggle/18 endpoint of the API to toggle it ON or OFF every time a user changes it.

  • You should now be able to run your app and watch the magic!!

Conclusion

There you have it, you can now control any GPIO pin on you Raspberry Pi using your Android Device! If you are actually going to use this app i would recommend adding in some error handling and also letting the User know when an API call has been successful.