Networking, Web Service, and Remote APIs - Pushing the Limits - Android Programming: Pushing the Limits (2014)

Android Programming: Pushing the Limits (2014)

Part III. Pushing the Limits

Chapter 17. Networking, Web Service, and Remote APIs

A majority of all Android applications perform some kind of network communication over the Internet. Even

single-player games today provide social integration with an online web service. So, the data an application

generates should be stored online so that users will have access to the same data from other devices.

As a developer of Android applications, you need to consider all aspects of networking. If your application

wastes networking resources, it will consume more power and possibly increase the cost to users because of

mobile data charges.

In this chapter, I cover how to perform network calls as efficiently as possible. I introduce my favorite APIs for

HTTP-based communication. Then I move on to describe three different types of web services and how you can

integrate them into your application. If you’ll be using a web service in your application, you can likely integrate

it by using a technique very similar to one of the three I describe.

I complete this chapter with guidelines for reducing the power your application consumes in regard to network

operations. All network calls come with an additional drain on the battery, and you want to reduce this drain as

much as possible.

Android Networking

Although Android supports both TCP and UDP communication, most of the network calls for applications are

done over HTTP, which is built on top of TCP. In this section, I write mostly about HTTP communication and

related topics. I briefly cover connectionless protocols, like mDNS, in Chapter 18.

The first and most important rule to remember when it comes to networking on Android is: Never perform

network calls on the main thread. Starting with Android version 3.0 (Honeycomb), the main thread is protected

by the system, and your application will crash if it tries to do a network call from the main thread.

Second, and almost as important: Always do networking on Android from a Service and avoid performing

network calls from within an Activity . There are several reasons for doing so, but the most important one is

that you need to consider the fast changes in the Activity state if you perform network operations there.

The user might press Home in the middle of a network call, just to return to your application a second later. By

moving all network operations to a Service, you can avoid this issue. It also makes for a better overall design

because with this approach, you reduce the amount of code in your Activities, making it less complicated.

However, in many cases you will be forced to perform network operations directly from an Activity,

as I show later in this chapter in the section “Foursquare API Using OAuth2” Please consider these cases as

exceptions to the rule. As much as possible, try to perform the network calls from a Service.

I recommend using either a callback interface or the LocalBroadcastManager to communicate network

results between the Activity and the Service. Another way is to store the results from a network call

directly into a ContentProvider and let the provider notify registered clients about the changes to any

data, as shown in Figure 17-1.

4. ContentProvider

1. User triggers a

Activity

notifies all connected

network refresh

clients

Content

3. Service insert data to

Service

Provider

ContentProvider

2. Service fetches data

from the Internet

Internet

Figure 17-1 Network calls from a Service inserting data into a ContentProvider

that notifies an Activity

HttpUrlConnection

The Android API has two APIs for HTTP communication, the Apache HttpClient and HttpUrlConnection.

Both have the same level of support in regard to features, but only HttpUrlConnection is recommended

because it’s the one being actively maintained by Google. Google has also implemented a number of useful

features that you otherwise would have to implement yourself, such as transparent response compression and

response cache.

private void enableHttpResponseCache() {

try {

long httpCacheSize = 10 * 1024 * 1024; // 10 MiB

File httpCacheDir = new File(getCacheDir(), “http”);

Class.forName(“android.net.http.HttpResponseCache”)

.getMethod(“install”, File.class, long.class)

.invoke(null, httpCacheDir, httpCacheSize);

} catch (Exception httpResponseCacheNotAvailable) {

}

}

The response cache is available from Android 4.0 (ICS) on, so if your application will also run on an earlier

version of Android, use the preceding approach to initiate the cache using Reflections. If your application will

target Android 4.0 at the minimum, you can use the following code to install the response cache:

try {

HttpResponseCache httpResponseCache = HttpResponseCache.

install(new File(getCacheDir(), “http”), CACHE_SIZE);

} catch (IOException e) {

Log.e(TAG, “Error installing response cache!”, e);

}

Choose a suitable cache size for your application. If you’re retrieving only small amounts of data, pick a cache

of only a few megabytes. The cache is application-private, so you don’t have to worry about leaking cached

responses to other applications on the device.

A Simple HTTP GET

Most network calls from applications will be in the form of simple HTTP GET requests. Here is an example of

how to perform such a request:

public JSONObject getJsonFromServer(URL url,

long lastModifiedTimestamp) {

try {

HttpURLConnection urlConnection = url.openConnection();

urlConnection.setRequestMethod(“GET”);

urlConnection.setInstanceFollowRedirects(true);

urlConnection.setIfModifiedBecause(lastModifiedTimestamp);

urlConnection.setUseCaches(true);

urlConnection.connect();

if (urlConnection.getResponseCode()

== HttpURLConnection.HTTP_OK) {

if (urlConnection.getContentType().

contains(“application/json”)) {

int length =

(HttpURLConnection) urlConnection.

getContentLength();

InputStream inputStream = urlConnection.

getInputStream();

String jsonString = readStreamToString(inputStream, length);

return new JSONObject(jsonString);

}

} else {

// TODO: Error handling...

}

} catch (IOException e) {

Log.e(TAG, “Error perform HTTP call!”, e);

} catch (JSONException e) {

Log.e(TAG, “Error parsing JSON!”, e);

}

return null;

}

private String readStreamToString(InputStream inputStream, int length)

throws IOException {

try {

BufferedReader bufferedReader =

new BufferedReader(new InputStreamReader(inputStream));

StringBuilder stringBuilder = new StringBuilder(length);

char[] buffer = new char[length];

int charsRead;

while ((charsRead = bufferedReader.read(buffer)) != -1) {

stringBuilder.append(buffer, 0, charsRead);

}

return stringBuilder.toString();

} finally {

inputStream.close();

}

}

This example is a typical one for using HttpUrlConnection to make an HTTP GET and parse the response to

a JSONObject. The important thing to note here is the readStreamToString() method. Although you

may find code examples for how to read an InputStream to a String online, the preceding shows the

correct way of reading from a stream. Without any exception, you should always exhaust an InputStream

when reading. If you don’t, you leave data waiting in the lower layers of the platform that could waste resources

and keep your device from going to power saver mode, which is one of the most common mistakes when doing

network calls, so keep this in mind whenever you’re reading from an InputStream.

Uploading Files to a Server

Many applications will send data, like images or other files, to an online server. This has turned out to be one of

the more complex issues for developers because the standard Java APIs (including Android) doesn’t provide an

obvious, straightforward method for this issue. Sending data using HTTP involves doing an HTTP POST request

with the data in the body. However, the body requires some special formatting, and a number of header fields

must be set correctly.

The following example shows the necessary steps for posting a file to a server using HTTP POST.

public int postFileToURL(File file, String mimeType, URL url)

throws IOException {

DataOutputStream requestData = null;

try {

long size = file.length();

String fileName = file.getName();

// Create a random boundary string

Random random = new Random();

byte[] randomBytes = new byte[16];

random.nextBytes(randomBytes);

String boundary = Base64.

encodeToString(randomBytes, Base64.NO_WRAP);

HttpURLConnection urlConnection

= (HttpURLConnection) url.openConnection();

urlConnection.setUseCaches(false);

urlConnection.setDoOutput(true);

urlConnection.setRequestMethod(“POST”);

// Set the HTTP headers

urlConnection.setRequestProperty(“Connection”, “Keep-Alive”);

urlConnection.setRequestProperty(“Cache-Control”, “no-cache”);

urlConnection.setRequestProperty(“Content-Type”,

“multipart/form-data;boundary=” + boundary);

// If larger than MAX_FIXED_SIZE - use chunked streaming

if (size > MAX_FIXED_SIZE) {

urlConnection.setChunkedStreamingMode(0);

} else {

urlConnection.setFixedLengthStreamingMode((int) size);

}

// Open file for reading...

FileInputStream fileInput = new FileInputStream(file);

// Open connection to server...

OutputStream outputStream = urlConnection.getOutputStream();

requestData = new DataOutputStream(outputStream);

// Write first boundary for this file

requestData.writeBytes(“--” + boundary + CRLF);

// Let the server know the filename

requestData.writeBytes(“Content-Disposition: form-data; name=\””

+ fileName + “\”;filename=\”” + fileName + CRLF);

// ...and the MIME type of the file

requestData.writeBytes(“Content-Type: “ + mimeType + CRLF);

// Read the local file and write to the server in one loop

int bytesRead;

byte[] buffer = new byte[8192];

while ((bytesRead = fileInput.read(buffer)) != -1) {

requestData.write(buffer, 0, bytesRead);

}

// Write boundary indicating end of this file

requestData.writeBytes(CRLF);

requestData.writeBytes(“--” + boundary + “--” + CRLF);

requestData.flush();

return urlConnection.getResponseCode();

} finally {

if (requestData != null) {

requestData.close();

}

}

}

The important part here is to understand the boundary that is used to tell the server where the file data

starts and ends in the request body. Also, notice the check on whether the file size is larger than MAX_

FIXED_SIZE (in bytes), where chunked streaming or fixed-length streaming mode is used. For chunked

streaming, the parameter 0 means “system default” for the chunk size, which is what most clients should use

in this mode. Chunking basically means that the data is sent to the server in parts, with each part prepended

with the size. Chunked streaming can be more efficient for memory use and reduces the risk of getting an

OutOfMemoryException. However, using fixed-length streaming mode is usually faster, although it requires

more memory while performing the streaming.

Volley

The standard HttpUrlConnection works well for most occasions, but it easily becomes quite complex

when you’re doing a lot of different HTTP requests. You still need to perform the requests on a background

thread and to ensure that everything is closed and shut down properly when your application is done. To make

things a bit easier, Google has started working on a new HTTP library that intends to make networking for

Android applications easier and faster. You can retrieve the latest version of the Volley library by cloning the

Git repository.

$ git clone https://android.googlesource.com/platform/frameworks/volley

The Volley library is currently under development but is already stable enough for use in applications. It

provides a very easy-to-use API for doing the typical network calls, and it handles all background threading and

other low-level things for you.

The following example shows how you can use Volley in a Service that makes HTTP GET calls and treats the

response as JSON data:

public class VolleyExample extends Service {

private LocalBinder mLocalBinder = new LocalBinder();

private RequestQueue mResponseQueue;

@Override

public void onCreate() {

super.onCreate();

mResponseQueue = Volley.newRequestQueue(this);

mResponseQueue.start();

}

@Override

public void onDestroy() {

super.onDestroy();

mResponseQueue.stop();

mResponseQueue = null;

}

public void doJsonRequest(String url,

Response.Listener<JSONObject> response,

Response.ErrorListener error) {

JsonObjectRequest jsonObjectRequest

= new JsonObjectRequest(Request.Method.GET,

url, null, response, error);

mResponseQueue.add(jsonObjectRequest);

}

@Override

public IBinder onBind(Intent intent) {

return mLocalBinder;

}

public class LocalBinder extends Binder {

public VolleyExample getService() {

return VolleyExample.this;

}

}

}

You pass in two callbacks, one for a successful response and one for error. You don’t need to worry about

starting a new background thread for the network call or initiating the connection yourself; this is all taken

care of by the Volley library. All you need to do is add the new request to the RequestQueue so that it gets

processed.

public void doJsonUpdateRequest() {

Response.Listener<JSONObject> responseListener

= new Response.Listener<JSONObject>() {

@Override

public void onResponse(JSONObject response) {

handleJsonResponse(response);

}

};

Response.ErrorListener errorListener

= new Response.ErrorListener() {

@Override

public void onErrorResponse(VolleyError error) {

handleError(error);

}

};

mService.doJsonRequest(API_URL, responseListener, errorListener);

}

In the preceding example, you define a callback for a successful response and an error callback. Both of these

will run on a thread other than the main thread, so if you intend to modify your UI, be sure to post that update

using a Handler or an AsyncTask.

Currently, the Volley library doesn’t support uploading arbitrary binary files. If you need to do

uploading, use the method described in the earlier section, “Uploading Files to a Server.” However,

continue to use Volley for other requests if possible.

If you’re doing lots of different HTTP requests, I highly recommend using the Volley library. Because it’s also

hosted as a part of the Android Open Source Project, it’s likely to become a central part of the Android platform

in the future.

OkHttp and SPDY

A big problem with HTTP is that it allows only one request and response at a time per connection, which forces

browsers and other clients to spawn multiple sockets in order to perform requests in parallel. This issue is less

problematic for clients because there will be relatively few connections from one application at any given time;

however, it makes a huge difference for servers. In 2009, Google started working on an updated HTTP protocol

to address these issues. The result was a new wire protocol named SPDY (pronounced speedy) that allows

multiple HTTP requests to be multiplexed over a single socket connection. This protocol has become a de facto

open standard for the next generation of HTTP. This protocol doesn’t replace HTTP; instead, it modifies how

requests and responses are sent over the wire. The IETF working group for HTTP has announced that it will start

the work on HTTP 2.0 and use the SPDY protocol as a starting point.

If you have full control of both the clients and the server, it may be worth investigating the use of SPDY as an

alternative to regular HTTP/1.1—doing so will greatly reduce the network’s load and increase the performance.

SPDY is already seeing good support in the major web browsers, and there are several implementations for

different platforms available, including Android.

If you choose to use SPDY as your communication protocol, I recommend that you choose the third-party

library called OkHttp, which is developed by Square, Inc., and available as open source on GitHub (http://

square.github.io/okhttp). The library is available as a Maven dependency by including the following

line in your Gradle script:

compile ‘com.squareup.okhttp:okhttp:1.1.1’

This library is simply a new and improved HTTP client with support for the SPDY protocol. It uses the

HttpUrlConnection interface, so switching to this in your existing code should require little work.

The following code shows how you can use the OkHttp library in Android:

public class OkHttpExample {

private final OkHttpClient mOkHttpClient;

public OkHttpExample() {

mOkHttpClient = new OkHttpClient();

}

public String okHttpDemo(URL url) throws IOException {

HttpURLConnection urlConnection = mOkHttpClient.open(url);

InputStream inputStream = null;

urlConnection.setRequestMethod(“GET”);

urlConnection.connect();

if (urlConnection.getResponseCode()

== HttpURLConnection.HTTP_OK) {

inputStream = urlConnection.getInputStream();

return readStreamToString(inputStream,

urlConnection.getContentLength());

}

return null;

}

private String readStreamToString(InputStream inputStream,

int length)

throws IOException {

try {

BufferedReader bufferedReader =

new BufferedReader(new InputStreamReader(inputStre

am));

StringBuilder stringBuilder = new StringBuilder(length);

char[] buffer = new char[length];

int charsRead;

while ((charsRead = bufferedReader.read(buffer)) != -1) {

stringBuilder.append(buffer, 0, charsRead);

}

return stringBuilder.toString();

} finally {

inputStream.close();

}

}

}

When you create a new instance of the OkHttpClient, it will set up everything you need, such as connection

polling and response cache. This implementation is extremely fast even on regular HTTP requests, so using

it may it be a good idea in general. When using OkHttp for SPDY communication, you’ll notice a huge

improvement in performance for your network calls.

Web Sockets

Web Sockets is the latest darling of the web and is an extension running on top of standard HTTP. It allows for

asynchronous message-based communication between a client and a server. It starts with a regular HTTP GET

request that contains special HTTP headers indicating that the client wants to upgrade the connection to a Web

Socket connection.

Here is an example of the clients GET request for initiating a Web Socket connection:

GET /websocket HTTP/1.1

Host: myserver.com

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Key: MjExMjM0MTI0MTI0MTI0MTIzCg==

Sec-WebSocket-Protocol: chat

Sec-WebSocket-Version: 13

Origin: http://myserver.com

If the client request is accepted, the server responds with the following:

HTTP/1.1 101 Switching Protocols

Upgrade: websocket

Connection: Upgrade

Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=

Sec-WebSocket-Protocol: chat

The values in the preceding headers aren’t valid for every case but should be calculated according to

the Web Socket protocol specification. Normally, you don’t need to bother about these details when

using a readymade library for Web Socket communication.

When a Web Socket is established, both sides (client and server) can send messages to each other asynchronously.

More importantly, you now have a way to quickly notify the client from your server. Messages can be either text

or binary and are usually quite small. If you need to transmit a large file between the client and server, stick to

standard HTTP instead. Web Sockets is intended for sending notifications with a relatively small payload.

I recommend that you choose a suitable data format when communicating over Web Sockets. In most cases,

JSON is sufficient and allows for a simple implementation. JSON messages should be sent as text-messages over

Web Sockets. For more advanced scenarios with mixed-type data, I recommend using Google Protocol Buffers,

as I describe in Chapter 9.

Although you can implement your own Web Sockets client using the standard Socket class in Android, I highly

recommend that you use one of the many third-party libraries available. You can choose from several; the one I

show here is the one I consider most stable at the moment, the Web Socket implementation for Java by Nathan

Rajlich (also known as TooTallNate), which you can find at http://java-websocket.org. In addition,

it contains a server implementation for Web Sockets, which is useful in Chapter 18. To use this library, simply

include the following dependency in your Gradle file:

compile ‘org.java-websocket:Java-WebSocket:1.3.0’

When using Web Sockets through this library, you don’t use the HttpUrlConnection: instead, you create a

WebSocketClient and connect to a URI.

The following code is a complete example of using this library to connect to a Web Socket online:

public class ChatService extends Service {

private static final String TAG = “ChatService”;

private ChatWebSocketClient mChatWebSocketClient;

private ChatClient mChatClient;

private LocalBinder mLocalBinder = new LocalBinder();

public IBinder onBind(Intent intent) {

return mLocalBinder;

}

public IBinder onBind(Intent intent) {

return null;

}

public void connectToChatServer(URI serverUri) {

new ChatWebSocketClient(serverUri).connect();

}

public void disconnect() {

if (mChatWebSocketClient != null) {

mChatWebSocketClient.close();

}

}

public void setChatClient(ChatClient chatClient) {

mChatClient = chatClient;

}

public void sendMessage(String message) {

if(mChatWebSocketClient != null) {

mChatWebSocketClient.send(message);

}

}

public boolean isConnected() {

return mChatWebSocketClient != null;

public interface ChatClient {

void onConnected();

void onMessageReceived(String from, String body, Date timestamp);

void onDisconnected();

}

private class ChatWebSocketClient extends WebSocketClient {

public ChatWebSocketClient(URI serverURI) {

super(serverURI);

}

@Override

public void onOpen(ServerHandshake serverHandshake) {

// Called when the Web Socket is connected

mChatWebSocketClient = this;

if(mChatClient != null) {

mChatClient.onConnected();

}

Notification notification = buildNotification();

startForeground(1001, notification);

}

@Override

public void onMessage(String message) {

// Called when a text message is received

if(mChatClient != null) {

try {

JSONObject chatMessage = new JSONObject(message);

String from = chatMessage.getString(“from”);

String body = chatMessage.getString(“body”);

Date timestamp =

new Date(chatMessage.getLong(“timestamp”));

mChatClient.onMessageReceived(from, body, timestamp);

} catch (JSONException e) {

Log.e(TAG, “Malformed message!”, e);

}

}

}

@Override

public void onMessage(ByteBuffer bytes) {

// Called when a binary message is received

}

@Override

public void onClose(int code, String reason, boolean remote) {

// Called when the connection is closed

mChatWebSocketClient = null;

if(mChatClient != null) {

mChatClient.onDisconnected();

}

stopForeground(true);

}

@Override

public void onError(Exception e) {

// Called on in case of communication error

}

}

private class LocalBinder extends Binder {

public ChatService getService() {

return ChatService.this;

}

}

}

This is a guide for implementing Web Socket support in your code. In a real-life application, you should add

additional security and error checks. The important thing here is that when you call WebSocketClient.

connect(), it spawns a new thread on which this Web Socket will live, which means you don’t have to do the

background thread yourself when using this library.

The ChatClient extends the WebSocketClient class and implements the different event callbacks. All

these callbacks occur on the thread that the Web Socket is running on, so never block these calls because doing

so will stall any other traffic on the same Web Socket.

It’s good practice to use the onOpen() and onClose() callbacks for determining when the you can start

communicating over the Web Socket. In the preceding example, the mChatClient member is set and reset

(to null) in the respective method, allowing for a simple null check when sending a message.

I return to the topic of Web Sockets in Chapter 18, where I describe how you can communicate directly between

two devices.

Integrating Web Services

Most web services that you will use in your Android app usually fit into one of three categories: those that

don’t require authentication for a user, those that do require authentication for a user but lack a native SDK for

Android, and those that require user authentication and provide an SDK for Android. In this section, I provide

three examples that illustrate each of these categories.

Google Static Maps v2

In Chapter 13, I cover the use of the new and powerful Location API for Android. Although it’s fairly easy to use,

it may sometimes be more than you need. If your application needs to show only a static map that the user

won’t interact with, you can use Google Static Maps v2 API instead, which is a web service from Google that

allows you to fetch a piece of Google Maps as a bitmap image (PNG, GIF, or JPEG).

Here is a simple static method for retrieving a static map:

public class StaticMapsFetcher {

public static final String BASE_URL

= “http://maps.googleapis.com/maps/api/staticmap”;

// TOOD Create this before release!

public static final String API_KEY = null;

public static final String UTF8 = “UTF-8”;

private static final String TAG = “StaticMapsFetcher”;

public static Bitmap fetchMapWithMarkers(String address,

int width,

int height,

String maptype,

List<String> markers) {

HttpURLConnection urlConnection = null;

try {

StringBuilder queryString = new StringBuilder(“?”);

if (address != null) {

queryString.append(“center=”).

append(URLEncoder.encode(address, UTF8)).

append(“&”);

}

if (width > 0 && height > 0) {

queryString.append(“size=”).

append(String.format(“%dx%d”, width, height)).

append(“&”);

}

if (maptype != null) {

queryString.append(“maptype=”).

append(maptype).append(“&”);

}

if (markers != null) {

for (String marker : markers) {

queryString.append(“markers=”).

append(URLEncoder.encode(marker, UTF8));

}

}

if (API_KEY != null) {

queryString.append(“key=”).append(API_KEY).append(“&”;

}

queryString.append(“sensor=false”);

URL url = new URL(BASE_URL + queryString.toString());

urlConnection = url.openConnection();

urlConnection.connect();

if (urlConnection.getResponseCode()

== HttpURLConnection.HTTP_OK) {

BufferedInputStream bufferedInputStream

= new BufferedInputStream(urlConnection.

getInputStream());

return BitmapFactory.decodeStream(bufferedInputStream);

} else {

return null;

}

} catch (IOException e) {

Log.e(TAG, “Error fetching map!”, e);

} finally {

if (urlConnection != null) {

urlConnection.disconnect();

}

}

}

}

Note that the API_KEY is left as null; this is allowed, but not recommended, for the Google Static Maps API.

Before you release an application that uses this API, you should create a new API key using the Google API

Developer Console.

Also note how the use of URLEncoder.encode() for the values of each parameter. This guarantees that

whatever the value is, it will be encoded properly in the URL. When a web service is called, an error stating a bad

request is common because the server cannot parse the request parameters properly.

This example shows how the simplest web services can be integrated into an Android application. They

are one-way, don’t require authentication, and have only a few parameters. You can find more information

about the parameters for Google Static Maps API API at https://developers.google.com/maps/

documentation/staticmaps.

Foursquare API Using OAuth2

When you use a web service that requires a user account, you need to authenticate the user in some way.

However, because your application will be a third-party client for this service, you need some way to provide

authentication that doesn’t compromise the user’s credentials, meaning the username and password shouldn’t

pass through your code. To solve this issue, a standard named OAuth was developed. This standard is now on

its second version and is called OAuth2. It was designed so that web applications can allow one website to

integrate with a second one on behalf of a user. To use it on Android, you route the authentication through a

WebView that displays the service authentication web page for the user.

Although it’s possible to implement all of the steps for OAuth2 yourself, I recommend using a third-party library

that hides away some of the complexity. The one I recommend is called Scribe and can be found at https://

github.com/fernandezpablo85/scribe-java. Scribe provides a simple wrapper on top of the

HttpUrlConnection class for OAuth2-enabled services, so it’s an excellent use for Android.

In this OAuth2 example, the user’s friends are displayed on Foursquare. Although many of the API calls for

Foursquare don’t require authentication (like searching for venues), getting a list of Foursquare friends will

obviously require authentication by the user.

The following code shows an Activity that you can use to get authorization for a user’s Foursquare account

using OAuth2:

public class OAuthActivity extends Activity {

public static final String CLIENT_ID

= “<Client ID from foursquare.com/developer>”;

public static final String CLIENT_SECRET

= “<Client SECRET from foursquare.com/developer>”;

public static final Token EMPTY_TOKEN = null;

public static final String ACCESS_TOKEN = “foursquare.access_token”;

private static final String TAG = “FoursquareOAuth2”;

private OAuthService mOAuthService;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

@Override

protected void onResume() {

super.onResume();

mOAuthService = new ServiceBuilder()

.provider(Foursquare2Api.class)

.apiKey(CLIENT_ID)

.apiSecret(CLIENT_SECRET)

.callback(“oauth://foursquare”)

.build();

String authorizationUrl =

mOAuthService.getAuthorizationUrl(EMPTY_TOKEN);

WebView webView = (WebView) findViewById(R.id.oauth_view);

WebViewClient webViewClient = new WebViewClient() {

@Override

public boolean shouldOverrideUrlLoading(WebView view,

String url) {

if (url.startsWith(“oauth”)) {

Uri uri = Uri.parse(url);

String oauthCode = uri.getQueryParameter(“code”);

Verifier verifier = new Verifier(oauthCode);

new GetTokenAccess().execute(verifier);

return true;

}

return super.shouldOverrideUrlLoading(view, url);

}

};

webView.setWebViewClient(webViewClient);

webView.getSettings().setJavaScriptEnabled(true);

webView.loadUrl(authorizationUrl);

}

class GetTokenAccess extends AsyncTask<Verifier, Void, Token> {

@Override

protected Token doInBackground(Verifier... verifiers) {

Token accessToken = mOAuthService.

getAccessToken(EMPTY_TOKEN, verifiers[0]);

return accessToken;

}

@Override

protected void onPostExecute(Token token) {

if (token != null) {

Intent intent = new Intent();

intent.putExtra(ACCESS_TOKEN, token.getToken());

setResult(RESULT_OK, intent);

} else {

setResult(RESULT_CANCELED);

}

finish();

}

}

}

The actual authentication and authorization toward Foursquare goes through a custom WebViewClient. The

custom WebViewClient overrides the method shouldOverrideUrlLoading(), which allows you to

capture all calls to a URL that this WebView will do. In this case, you monitor for all calls that match the callback

URL, which will contain the access token needed for signing API requests.

The example needs to use an AsyncTask because you cannot do direct network calls on the main thread.

OAuthService.getAccessToken() will perform a network call to retrieve the access token used for the

API calls that require a signed-in user.

The following code uses the Activity from the previous example:

public class FoursquareActivity extends Activity {

public static final String TAG = “FoursquareActivity”;

public static final int OAUTH_REQUEST_CODE = 1001;

public static final String FRIENDS_URI =

“https://api.foursquare.com/v2/users/self/friends”;

private SharedPreferences mPreferences;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.foursquare_main);

mPreferences = PreferenceManager.

getDefaultSharedPreferences(this);

}

@Override

protected void onResume() {

super.onResume();

if (mPreferences.contains(OAuthActivity.ACCESS_TOKEN)) {

new GetFoursquareFriends().execute(“55.59612590”, “12.98140870”);

} else {

startActivityForResult(new Intent(this, OAuthActivity.class),

OAUTH_REQUEST_CODE);

}

}

@Override

protected void onActivityResult(int requestCode,

int resultCode,

Intent data) {

if (requestCode == OAUTH_REQUEST_CODE) {

if (resultCode == RESULT_OK) {

String accesToken = data.

getStringExtra(OAuthActivity.ACCESS_TOKEN);

mPreferences.edit().

putString(OAuthActivity.ACCESS_TOKEN,

accesToken).apply();

} else {

mPreferences.edit().

remove(OAuthActivity.ACCESS_TOKEN).apply();

}

}

}

class GetFoursquareFriends extends AsyncTask<String, Void, JSONObject> {

@Override

protected JSONObject doInBackground(String... lngLat) {

OAuthService service = new ServiceBuilder()

.provider(Foursquare2Api.class)

.apiKey(OAuthActivity.CLIENT_ID)

.apiSecret(OAuthActivity.CLIENT_SECRET)

.callback(“oauth://foursquare”)

.build();

String accessToken = mPreferences.

getString(OAuthActivity.ACCESS_TOKEN, null);

OAuthRequest request = new OAuthRequest(Verb.GET,

FRIENDS_URI);

request.addQuerystringParameter(“oauth_token”,

accessToken);

Token token = new Token(accessToken,

OAuthActivity.CLIENT_SECRET);

service.signRequest(token, request);

Response response = request.send();

if (response.isSuccessful()) {

try {

return new JSONObject(response.getBody());

} catch (JSONException e) {

Log.e(TAG, “Error building JSONObjet!”, e);

}

} else {

Log.d(TAG, “Bad request: “

+ response.getCode()

+ “ “

+ response.getMessage());

}

return null;

}

@Override

protected void onPostExecute(JSONObject response) {

if (response != null) {

try {

JSONArray friends = response.

getJSONObject(“response”).

getJSONObject(“friends”).

getJSONArray(“items”);

Log.d(TAG, “Friends: “ + friends);

} catch (JSONException e) {

Log.e(TAG, “JSON Exception”, e);

}

}

}

}

}

You start by checking whether an access token is already stored; if not, the OAuth2 Activity is started with

Activity.startActivityForResult(). When the OAuth2 process is completed, successful or not,

onActivityResult() from the preceding example is called with the results.

Using the AsyncTask from the preceding example, you can set up an OAuthRequest with the new access

token. In this case, an array of all the user’s friends on Foursquare is retrieved.

I use the preceding code only to illustrate how to use Scribe and OAuth2 in your application. Because

OAuth2 requires user interaction, this is one of the few cases where you must perform network

operations from an Activity.

You can use the Scribe library for any API that supports OAuth2 for authorization. Check the documentation of

the library for officially supported services.

Facebook SDK for Android

Because OAuth2 was designed for the web, it’s not a perfect match for a native Android application. Many

services have solved this problem in a similar way using a native Android app instead. For instance, Facebook

has a great web service that allows you to integrate its Graph API and other Facebook APIs into your Android

application. Because users who want to use the Facebook integration in your application most likely will have the

Facebook app installed as well, they perform a similar authorization process by using Android Activities.

The Facebook SDK for Android (version 3.0 and later) allows you to easily integrate Facebook authorization and

authentication for your application using its library project. You can then use this API to simply track users in

your application or integrate with Facebook services and send messages and photos. The Facebook SDK for

Android is available at https://developers.facebook.com/android.

First, you need to register your application on the Facebook Developer site (https://developers.

facebook.com/apps). Click Create New App and enter the name of your app while leaving the rest of the

fields empty or in their default. Next, open the Native Android app section and fill in the details related to your

app, as shown in Figure 17-2.

The key hash for your application is generated with the following command in your terminal:

$ keytool -exportcert -alias androiddebugkey –keystore ~/.android/debug.

keystore | openssl sha1 -binary | openssl base64

When the online registration is complete, copy the app ID and add it as a String resource in your application’s

resources. Then you add a metadata element that points to this value as well as a reference to the Facebook

LoginActivity.

image

Figure 17-2 Creating a new Facebook app with Android support using the Facebook Developer console

Here is a snippet from the AndroidManifest.xml where the necessary components and metadata for

Facebook integration (marked in bold) are added:

<application

android:allowBackup=”true”

android:icon=”@drawable/ic_launcher”

android:label=”@string/app_name”

android:theme=”@style/AppTheme” >

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

<activity

android:name=”com.aptl.myfacebookdemo.MainActivity”

android:label=”@string/app_name” >

<intent-filter>

<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />

</intent-filter>

</activity>

<activity android:name=”com.facebook.LoginActivity”/>

<meta-data android:name=”com.facebook.sdk.ApplicationId”

android:value=”@string/facebook_app_id” />

</application>

Next, you need to implement the Facebook callbacks in MainActivity. Also, don’t forget to add the

INTERNET permission as just shown.

The UiLifecycleHelper class takes care of all the state changes related to your Activity states. All

you need to do is override the onCreate(), onResume(), onActivityResult(), onPause(), and

onDestroy() and do the equivalent callback on the helper class, as shown here:

public class MainActivity extends Activity

implements Session.StatusCallback {

private UiLifecycleHelper mUiLifecycleHelper;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

LoginButton authButton =

(LoginButton) findViewById(R.id.authButton);

authButton.setReadPermissions(Arrays.asList(“user_birthday”,

“friends_birthday”));

mUiLifecycleHelper = new UiLifecycleHelper(this, this);

mUiLifecycleHelper.onCreate(savedInstanceState);

}

@Override

protected void onResume() {

super.onResume();

mUiLifecycleHelper.onResume();

}

@Override

protected void onPause() {

super.onPause();

mUiLifecycleHelper.onPause();

}

@Override

protected void onDestroy() {

super.onDestroy();

mUiLifecycleHelper.onDestroy();

}

@Override

protected void onSaveInstanceState(Bundle outState) {

super.onSaveInstanceState(outState);

mUiLifecycleHelper.onSaveInstanceState(outState);

}

image

@Override

protected void onActivityResult(int requestCode, int resultCode,

Intent data) {

super.onActivityResult(requestCode, resultCode, data);

mUiLifecycleHelper.onActivityResult(requestCode, resultCode,

data);

}

@Override

public void call(Session session, SessionState state,

Exception exception) {

// Callback for session state changes...

}

}

Note the LoginButton that’s added to the layout for this Activity. You can use it to provide a default

Facebook Login button to your application. It’s also possible to pass extra parameters, such as necessary

permissions and such, which will then be passed on to the authentication process. When the user taps the Login

button, a dialog box appears asking the user if she wants to allow your application to get the permissions it has

requested, as shown in Figure 17-3.

Figure 17-3 Dialog box asking the user for permissions

to access her specific Facebook data

You can add the Facebook Login button in the XML layout for your Activity as shown in the following. This

way, you can control where the button should appear while at the same time provide a familiar entry point for

the user to log in to Facebook.

<com.facebook.widget.LoginButton

android:id=”@+id/authButton”

android:layout_width=”wrap_content”

android:layout_height=”wrap_content”

android:layout_gravity=”center_horizontal”

android:layout_marginTop=”5dp” />

Once you have a valid authentication toward Facebook, you can use the Request class from the Facebook

SDK to perform requests. The methods provided by this class come in many different versions, some are

asynchronous and perform the network call on a separate background thread, while others are synchronous

and allow you to control the background threading yourself. In the following code example you can see a

request for the user’s friends made using the asynchronous method.

public void doLoadFriendList(View view) {

if(SessionState.OPENED_TOKEN_UPDATED.

equals(mSessionState)

|| SessionState.OPENED.equals(mSessionState)) {

Request.executeMyFriendsRequestAsync(mSession,

new Request.GraphUserListCallback() {

@Override

public void onCompleted(List<GraphUser> friends,

Response response) {

Log.d(TAG, “Friends loaded: “ + friends.size());

mFriendListAdatper.clear();

mFriendListAdatper.addAll(friends);

mFriendListAdatper.notifyDataSetChanged();

}

});

}

}

Using the Facebook SDK for Android to add Facebook integration to your application is significantly simpler

than using the web-based OAuth2 approach shown in the previous section. Facebook SDK for Android allows

you to provide a secure method for authorization without having to break the Android UI paradigm.

Finding Online Web Services and APIs

It’s impossible to provide a complete list for all the available web services online, mostly because that list

changes every day. However, a number of useful resources are online where you can find web services for

different things. A good place to start is at www.programmableweb.com, which provides an online directory

for many different web services and APIs. Two other very good directory resources for online web services and

APIs are www.apis.io and www.mashape.com.

If you need an online service, rest assured that you’ll be able to find some exiting web services or online APIs.

Although most of these services provide a free tier, several require you either to pay a fee (usually based on

usage or a monthly fee) or to contact the provider in order to set up a contract for their use. Often, it may be

cheaper to pay for an existing service than try to implement one from scratch, unless that’s your core business.

image

Network and Power Consumption

When it comes to power consumption, the second biggest cause of battery drain is often related to network

traffic (the display usually comes first). Users who disable mobile data will see an immediate decrease in battery

drain, but will also lose all features requiring online connectivity. Smartphone manufacturers, chipset vendors,

and Google have all implemented a number of ways to reduce the amount of network traffic and battery drain

in order to increase the battery’s life. However, unless application developers follow the guidelines and use the

tools at their disposal, these improvements are all in vain.

Because of the openness of the Android platform, a single application can keep the mobile radio in high-drive

mode more than needed, thus draining the battery faster. In later versions of Android, users can track the

network usage for each application (see Figure 17-4). Although network traffic from your app will not cost

you anything, excessive use will cost the user through battery loss and data traffic charges, probably resulting

in a very bad review rating. It’s in your best interest to make sure you don’t use more data than is absolutely

necessary.

Figure 17-4 Data Usage from the Settings application

shows how much data each application used during a

certain period

The radio hardware on a smartphone, that is the Wi-Fi and the cellular chip, has built-in power-saving features

on the hardware level that automatically kicks in when no network traffic is active (that is, no incoming or

outgoing data packages) and reduces the consumption of power to a very low level. When an application

wants to send data or when an application is waiting for incoming data and a package is received, the network

hardware will disable the power saving in order to be able to send data as fast and efficiently as possible.

If only one application on a device is making network calls, there’s no problem with consumption of power. The

problem occurs when many applications want to access the network, and they’re doing so in random order.

General Guidelines

Before performing a network call, first consider whether the user really needs this data right now. For instance,

if the data your application fetches is quite small, it’s probably okay to fetch it when the user launches the

application instead of continuously updating the data at regular intervals or when your app gets a notification

(either through Google Cloud Messaging or some other push notification service). Unnecessary network

requests is the most common mistake for applications that fetch data online. In many situations, you can wait

until the user explicitly requests the data (for instance, when the application is launched).

Second, consider how much data you need to retrieve. For example, in an e-mail application, it’s usually

enough to fetch only the ten latest e-mail headers, which could be more difficult to implement, especially on

the server-side, but will save data traffic and reduce the time required for the network call to complete. Using

different types of caches (like the response cache introduced for HttpUrlConnection in Android 4/ICS) and

retrieving smaller pages of data from the service will greatly reduce your application’s network traffic.

Also, because the HttpUrlConnection class now supports transparent compressions, make sure that the

data retrieved from the server is gzip-compressed if possible—this compress/decompress feature is enabled by

default by most major public web services. Another way to optimize the amount of data is to choose a better

data format, which usually involves a balance between size optimization and how dynamic the format is. If you

can, choose a format that allows you to extend your data definition without losing backward-compatibility.

Although JSON is good enough for most situations, and also allows you to use the same backend for web

clients, the best choice in terms of size is probably Google Protocol Buffers.

Finally, my third tip is related to the first one. If you need to notify the user about a new message or some other

online information that requires the user’s attention, you cannot wait until the user starts the application to

perform the network call. In such cases, you have two choices: polling the service at regular intervals or letting

the server push the information down to the client.

Power Efficient Network Polling

Network polling has several drawbacks but is sometimes the only viable way for you to check whether there’s

something new to fetch from an online service. Fortunately, Android provides a convenient API for doing

recurring polling through the AlarmManager API.

Following is an example of a method for scheduling a recurring polling at 15-minute intervals. Note the use of

ELAPSED_REALTIME as the type of alarm:

public void scheduleNetworkPolling() {

AlarmManager alarmManager = (AlarmManager)

getSystemService(ALARM_SERVICE);

int alarmType = AlarmManager.ELAPSED_REALTIME;

long interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES;

long start = System.currentTimeMillis() + interval;

Intent pollIntent

= new Intent(MyNetworkService.ACTION_PERFORM_POLL);

PendingIntent pendingIntent

= PendingIntent.getService(this, 0, pollIntent, 0);

alarmManager.setInexactRepeating(alarmType,

start, interval, pendingIntent);

}

If you need to awaken the device from a suspended mode, change ELAPSED_REALTIME to ELAPSED_

REALTIME_WAKEUP. Doing so, however, causes the device to consume more battery because it will go out of

suspend mode every 15 minutes.

The way the setInexactRepeating() works is that all applications that register for a wakeup using this

service with the same interval will be awakened at the same time. Regardless of when an application registered

for a 15-minute wakeup interval, it will receive its PendingIntent at the same time the other registered

applications do.

Although this approach doesn’t consume less battery, it will reduce the device’s overall consumption of power

if all applications that need a recurring polling interval use it. This will then ensure that no network polling

happens between the 15-minute intervals.

Server-Side Push

The best solution for reducing the number of network calls is to use a server-side push. This technique allows

the server to actively notify a client that there is new data to retrieve. The server-side push notification can

come in many forms. It can be an out-of-bounds message that comes through a messaging service not directly

connected to the Internet, like SMS, or it can be a regular TCP socket with a long keep-alive.

The most obvious choice for server-side push notifications is Google Cloud Messaging, which I explain in detail

in Chapter 19. However, two other solutions are available for server-side push.

SMS Push Notifications

As I explain in Chapter 15, you can register a BroadcastReceiver to receive incoming SMS as part of the

hidden Android APIs. This solution can work as an out-of-bounds server-side push notification that wakes up

the device and notifies it that there is new data to fetch online. Although this solution has a certain monetary

cost for the service provider, it can be used for notifications that happen less frequently or when you’re able to

send SMS for free (for instance, if you’re writing an application for a telecom operator).

The following code is a slightly modified version of the example in Chapter 15. In this case, the

method processSms() will return true or false depending on whether it’s a push notification

SMS you’re expecting. If true, the network service starts and you call abortBroadcast() and

setResultData(null); to ensure that the SMS is not propagated to the other receivers.

public class MySmsPushNotifier extends BroadcastReceiver {

// Copied from Telephony.java

public static final String SMS_RECEIVED_ACTION

= “android.provider.Telephony.SMS_RECEIVED”;

public static final String MESSAGE_SERVICE_NUMBER = “+461234567890”;

private static final String MESSAGE_SERVICE_PREFIX = “MYSERVICE”;

public void onReceive(Context context, Intent intent) {

String action = intent.getAction();

if (SMS_RECEIVED_ACTION.equals(action)) {

Object[] messages =

(Object[]) intent.getSerializableExtra(“pdus”);

for (Object message : messages) {

byte[] messageData = (byte[]) message;

SmsMessage smsMessage =

SmsMessage.createFromPdu(messageData);

if (processSms(smsMessage)) {

Intent networkIntent

= new Intent(MyNetworkService.

ACTION_PERFORM_NETWORK_CALL);

context.startService(networkIntent);

abortBroadcast();

setResultData(null);

}

}

}

}

private boolean processSms(SmsMessage smsMessage) {

String from = smsMessage.getOriginatingAddress();

if (MESSAGE_SERVICE_NUMBER.equals(from)) {

String messageBody = smsMessage.getMessageBody();

if (messageBody.startsWith(MESSAGE_SERVICE_PREFIX)) {

return true;

}

}

return false;

}

}

In order for your receiver to take priority over the default SMS receiver, you also need to modify the priority of

the intent-filter as shown here:

<receiver android:name=”.MySmsPushNotifier”>

<intent-filter android:priority=”9999”>

<action android:name=”android.provider.Telephony.SMS_RECEIVED” />

</intent-filter>

</receiver>

Web Sockets for Server-Side Push

I describe how to use Web Sockets earlier in this chapter. You can create a light-weight server-side push

notification service using Web Sockets. This method is not foolproof, and you need to adjust the timeout on the

socket on both the server and the client for this method to be efficient.

In the following example, the callbacks signal which state the push-notification socket is in:

class PushNotificationSocket extends WebSocketClient {

public PushNotificationSocket(URI serverURI) {

super(serverURI);

}

@Override

public void onOpen(ServerHandshake serverHandshake) {

// Web Socket opened - now registered for notifications

}

@Override

public void onMessage(String message) {

try {

JSONObject jsonObject = new JSONObject(message);

parseNotification(jsonObject);

} catch (JSONException e) {

Log.e(TAG, “Error parsing notification message!”, e);

}

}

@Override

public void onClose(int code, String reason, boolean remote) {

// Socket closed - reopen if this was unintentional

// due to a network timeout or similar

}

@Override

public void onError(Exception e) {

// Error, possibly due to timeout.

// Reconnect if possible.

}

}

This code is only partially complete but illustrates how Web Sockets can be used for a light-weight server-side

push notification. You also need a server that can respond to Web Socket requests. In Chapter 18, I provide an

example of such a server using the same Web Socket library used in this chapter. You can also use this library on

a server-side Java application.

Summary

In this chapter, I explained the best way to use a number of different APIs and libraries for doing networking

communication over HTTP. The standard HttpUrlConnection is sufficient for most situations, but if you will

do a lot of networking calls, you should take a look at the alternatives covered in this chapter.

I also discussed how to integrate three different types of web services, from the simplest ones that don’t require

any authentication to the more complicated ones that require OAuth2 or a native Android SDK. Most of the web

services you’ll encounter can fit into one of these three categories.

In the final part of this chapter, I provided some guidelines on what to consider when it comes to power

consumption and network operations. If possible, try to use Google Cloud Messaging from a server to notify

your application when new data is available. However, when server-side push is not possible, you should use

the periodic scheduling from the AlarmManager, which will help applications perform their network polling

at the same time, thus keeping the device in a suspended mode longer.

Networking is a complicated topic, and this chapter’s space doesn’t allow coverage of all options. Before

performing network calls, make sure that the network is available and listen for changes in the connectivity

using a BroadcastReceiver, as I describe in Chapter 8. If your application transmits large amounts of data,

like high-resolution photos, consider having an option to disable network communication for your application

when on a mobile network and only allow the traffic to occur over Wi-Fi. This is best done through some settings

UI, as I describe in Chapter 9. Finally, always assume that any network operation you initiate could fail and

produce a faulty or abnormal response. Implementing proper and thorough error-handling in your network

calls is very important. I highly recommend that you write automated unit tests, as I describe in Chapter 10, to

verify your code as much as possible.

Further Resources Documentation

For the HTTP protocol: http://www.w3.org/Protocols/

Websites

SPDY specification and whitepaper: http://dev.chromium.org/spdy/spdy-whitepaper

The latest draft for HTTP/2.0, based on SPDY: http://http2.github.io/http2-spec

The OAuth Bible from Mashape: https://github.com/Mashape/mashape-oauth/blob/master/FLOWS.md

How OAuth2 works by Aaron Parecki: http://aaronparecki.com/articles/2012/07/29/1/oauth2-simplified

How to perform regular updates without draining the battery: http://developer.android.com/training/efficient-downloads/regular_updates.html

How to make more energy and network efficient apps: http://developer.sonymobile.com/

knowledge-base/tutorials/android_tutorial/how-to-develop-energy-and-network-efficient-apps-tutorial