TABLE OF CONTENTS (HIDE)

Android Programming

Networking

HTTP Clients

Reference: "Connecting to the Network" @ http://developer.android.com/training/basics/network-ops/connecting.html.

How it works

This section explains how to setup a networking program on Android. You may do Example 1 below first, and then read the explanation.

Classes java.net.HttpURLConnection and java.net.URL

A client program can use the java.net.HttpURLConnection class to establish a connection to an HTTP server. The HttpURLConnection support HTTPS, streaming uploads and downloads, configurable timeouts, IPv6, and connection pooling.

The steps are:

  1. Construct a java.net.URL with the intended URL (e.g., http://www.android.com).
    URL url = new URL("http://www.android.com");
  2. Obtain a new java.net.HttpURLConnection via URL's openConnection() method.
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  3. To upload a request body, setDoOutput(true) to the connection, and write the the stream returned by getOutputStream().
    conn.setDoOutput(true);
    OutputStream out = new BufferedOutputStream(conn.getOutputStream());
    ......
  4. Read the response message (header and body). The response body can be read from the stream returned by getInputStream().
    InputStream in = new BufferedInputStream(conn.getInputStream());
    ......
  5. Disconnect.
    conn.disconnect();

Read the API for "java.net.HttpURLConnection" and "java.net.URL".

For example,

URL url = new URL(......);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
   // Optionally write request body
   conn.setDoOutput(true);
   conn.setChunkedStreamingMode(0); // unknown stream length
   OutputStream out = new BufferedOutputStream(conn.getOutputStream());
   ... write ...

   // Get response code
   int responseCode = conn.getResponseCode();

   // Read response body 
   InputStream in = new BufferedInputStream(urlConnection.getInputStream());
   ... read ...   
} finally {
   conn.disconnect();
}
Permissions

To perform network operations in Android, your application manifest (AndroidManifest.xml) must include the following permissions:

<manifest ......>
   <uses-permission android:name="android.permission.INTERNET" />
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
   ......
    <application
        android:usesCleartextTraffic="true"
        ......
    </application>
</manifest>

Notes: android:usesCleartextTraffic="true" is needed to support HTTP; otherwise, only HTTPS is supported.

Background Task via android.os.AsyncTask

In Android, the networking operations must be run on a separate thread from the main UI thread, because of its unpredictable delays. This can be carried out via:

  1. Extending an android.os.AsyncTask<Params, Progress, Result>, where Params and Result are the types for the doInBackground() method below.
  2. Override method "Result doInBackground(Params... params)" to carry out operations in the background.
  3. Override method "void onPostExecute(Result result)" to process the result returned by doInBackground().
  4. To start the AsyncTask, create an instance and invoke execute(Params... params), which triggers doInBackground() with the parameters and onPostExecute().

Read the API for "android.os.AsyncTask".

For example,

import android.os.AsyncTask
......
 
// Extend an AsyncTask to run the networking operations away from the main UI thread.
private class NetworkingTask extends AsyncTask<String, Void, String> {  // <Param, Progress, Result>
 
   // Run the networking operation in the background
   @Override
   protected String doInBackground(String... strUrls) {
      // networking operations
      ......
   }
 
   // Process the result returned by doInBackground()
   @Override
   protected void onPostExecute(String result) {
      ......
   }
}
 
......
 
// To invoke the networking task with the given URL
new NetworkingTask().execute(strUrl);

Example 1: Send an HTTP Request and Check the Response Code

Start a new Android Studio project with "Empty Views Activity" and name of "Test HTTP".

The screen contains a Button and a TextView. Clicking the Button triggers an HTTP request (e.g., http://www.android.com) and displays the response code (e.g., 200 for "OK" and 404 for "file not found") displayed in the TextView.

TestHTTP 1
TestHTTP 2
AndroidManifest.xml

Add the permissions for network operations as follows:

<manifest ......>
   <uses-permission android:name="android.permission.INTERNET" />
   
   <application 
      android:usesCleartextTraffic="true"
      ......
      ......>
   ......
   </application>
</manifest>

Notes: android:usesCleartextTraffic="true" is needed to support HTTP; otherwise, only HTTPS is supported.

activity_main.xml
<?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"
    tools:context="com.example.testhttp.MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:id="@+id/txtResponseId"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#cccccc"
        android:gravity="center" />
 
    <Button
        android:id="@+id/btnSendId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="32dp"
        android:text="@string/btnSendLabel"
        android:onClick="btnOnClickHandler" />
</RelativeLayout>
strings.xml

Add this entry:

<string name="btnSendLabel">SEND</string>
MainActivity.java
package ......;
 
import .......;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import android.os.AsyncTask;
import android.widget.Button;
import android.widget.TextView;
import android.view.View;
import android.widget.Toast;

public class MainActivity ...... {
 
   TextView txtResponse;
   Button   btnSend;
 
   @Override
   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
 
      txtResponse = (TextView) findViewById(R.id.txtResponseId);
      btnSend     = (Button) findViewById(R.id.btnSendId);
   }
 
   public void btnOnClickHandler(View v) {
      btnSend.setEnabled(false);  // Disable the button
      new HttpTask().execute("https://www.ntu.edu.sg"); // Send HTTP request
      //new HttpTask().execute("https://www.android.com"); // Send HTTP request
      //new HttpTask().execute("http://ip_addr:port/hello");
      //new HttpTask().execute("http://10.0.2.2:9999/hello");  // Tomcat at localhost:9999
      Toast.makeText(this, "Send", Toast.LENGTH_LONG).show(); // Toast a message
   }
 
   // Run the HTTP request in a background thread, separating from the main UI thread
   private class HttpTask extends AsyncTask<String, Void, String> {
        @Override
        protected String doInBackground(String... strURLs) {
           URL url = null;
           HttpURLConnection conn = null;
            try {
               url = new URL(strURLs[0]);
               conn = (HttpURLConnection) url.openConnection();
               // Get the HTTP response code (e.g., 200 for "OK", 404 for "Not found")
               // and pass a string description in result to onPostExecute(String result)
               int responseCode = conn.getResponseCode();
               if (responseCode == HttpURLConnection.HTTP_OK) {  // 200
        	         return "OK (" + responseCode + ")"; 
        	      } else {
        	         return "Fail (" + responseCode + ")";
               }
            } catch (IOException e) {
                return "Unable to retrieve web page. URL may be invalid.";
            }
        }
 
        // Displays the result of the AsyncTask.
        // The String result is passed from doInBackground().
        @Override
        protected void onPostExecute(String result) {
           txtResponse.setText(result);  // put it on TextView
       }
    }
}

Try running the app. Make sure that you emulator/phone has 3G/4G/5G signal for network connection!!! otherwise, it will not run???

Try changing the URL in btnOnClickHandler() to "https://www.android.com/999.html" (expect "404 Not Found") and "https://www.android.com999" (expect IOException). Explain the results.

Try accessing your tomcat server's hello app via http://ip_addr:port/hello (You need to check the IP Address of your Tomcat server). You can also use a special IP of 10.0.2.2 if the server is running on the host machine of the android emulator.

Notes:

  1. The localhost (127.0.0.1) refers to the android emulator, not the host machine. Use the IP address of the server; or use a special IP 10.0.2.2 for the host machine of the emulator.
  2. You can also use pre-defined constants for HTTP response codes, e.g., HttpURLConnection.HTTP_OK (for 200), HttpURLConnection.HTTP_NOT_FOUND (for 404), and etc.

(Optional) Example 2: Retrieve the Response Message

Read "Connecting to the Network" @ http://developer.android.com/training/basics/network-ops/connecting.html.

Or using "WebView" widget. See "Building webapps in WebView".

Link to Android's References and Resources