title: Example: Android bi-directional network socket using AsyncTask
body: <p>Most of the network socket examples I found for Android were one directional only. I needed a solution for a bi-directional data stream. I eventually learned of the AsyncTask. This example shows how to get data from a socket and send data back to it. Due to the blocking nature of a socket that is receiving data, that blocking needs to run in a thread other than the UI thread.</p>
  
  <p>For the sake of example, this code connects to a webserver. Pressing the "Start AsyncTask" button will open the socket. Once the socket is open, the web server waits for a request. Pressing the "Send Message" button will send a request to the server. Any response from the server will be displayed in the TextView. In the case of http, a web server will disconnect from the client once all the data has been sent. For other TCP data streams, the connection will stay up until one side disconnects.</p>
  
  <p>Screenshot:</p>
  
  <p><img src="https://i.stack.imgur.com/elu7s.gif" alt="Screenshot of Application"></p>
  
  <p>AndroidManifest.xml:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.exampleasynctask"
        android:versionCode="1"
        android:versionName="1.0"&gt;
      &lt;uses-sdk android:minSdkVersion="8" /&gt;
      &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
      &lt;application android:icon="@drawable/icon" android:label="@string/app_name"&gt;
          &lt;activity android:name=".MainActivity"
                    android:label="@string/app_name"&gt;
              &lt;intent-filter&gt;
                  &lt;action android:name="android.intent.action.MAIN" /&gt;
                  &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
              &lt;/intent-filter&gt;
          &lt;/activity&gt;
      &lt;/application&gt;
  &lt;/manifest&gt;
  </code></pre>
  
  <p>res\layout\main.xml:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:orientation="vertical"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent"
      &gt;
  &lt;Button android:id="@+id/btnStart" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Start AsyncTask"&gt;&lt;/Button&gt;
  &lt;Button android:id="@+id/btnSend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Send Message"&gt;&lt;/Button&gt;
  &lt;TextView android:id="@+id/textStatus" android:textSize="24sp" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Status Goes Here" /&gt;
  &lt;/LinearLayout&gt;
  </code></pre>
  
  <p>src\com.exampleasynctask\MainActivity.java:</p>
  
  <pre><code>package com.exampleasynctask;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.OutputStream;
  import java.net.InetSocketAddress;
  import java.net.Socket;
  import java.net.SocketAddress;
  
  import android.app.Activity;
  import android.os.AsyncTask;
  import android.os.Bundle;
  import android.util.Log;
  import android.view.View;
  import android.view.View.OnClickListener;
  import android.widget.Button;
  import android.widget.TextView;
  
  public class MainActivity extends Activity {
      Button btnStart, btnSend;
      TextView textStatus;
      NetworkTask networktask;
  
      @Override
      public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.main);
          btnStart = (Button)findViewById(R.id.btnStart);
          btnSend = (Button)findViewById(R.id.btnSend);
          textStatus = (TextView)findViewById(R.id.textStatus);
          btnStart.setOnClickListener(btnStartListener);
          btnSend.setOnClickListener(btnSendListener);
          networktask = new NetworkTask(); //Create initial instance so SendDataToNetwork doesn't throw an error.
      }
  
      private OnClickListener btnStartListener = new OnClickListener() {
          public void onClick(View v){
              btnStart.setVisibility(View.INVISIBLE);
              networktask = new NetworkTask(); //New instance of NetworkTask
              networktask.execute();
          }
      };
      private OnClickListener btnSendListener = new OnClickListener() {
          public void onClick(View v){
              textStatus.setText("Sending Message to AsyncTask.");
              networktask.SendDataToNetwork("GET / HTTP/1.1\r\n\r\n");
          }
      };
  
      public class NetworkTask extends AsyncTask&lt;Void, byte[], Boolean&gt; {
          Socket nsocket; //Network Socket
          InputStream nis; //Network Input Stream
          OutputStream nos; //Network Output Stream
  
          @Override
          protected void onPreExecute() {
              Log.i("AsyncTask", "onPreExecute");
          }
  
          @Override
          protected Boolean doInBackground(Void... params) { //This runs on a different thread
              boolean result = false;
              try {
                  Log.i("AsyncTask", "doInBackground: Creating socket");
                  SocketAddress sockaddr = new InetSocketAddress("192.168.1.1", 80);
                  nsocket = new Socket();
                  nsocket.connect(sockaddr, 5000); //10 second connection timeout
                  if (nsocket.isConnected()) { 
                      nis = nsocket.getInputStream();
                      nos = nsocket.getOutputStream();
                      Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
                      Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
                      byte[] buffer = new byte[4096];
                      int read = nis.read(buffer, 0, 4096); //This is blocking
                      while(read != -1){
                          byte[] tempdata = new byte[read];
                          System.arraycopy(buffer, 0, tempdata, 0, read);
                          publishProgress(tempdata);
                          Log.i("AsyncTask", "doInBackground: Got some data");
                          read = nis.read(buffer, 0, 4096); //This is blocking
                      }
                  }
              } catch (IOException e) {
                  e.printStackTrace();
                  Log.i("AsyncTask", "doInBackground: IOException");
                  result = true;
              } catch (Exception e) {
                  e.printStackTrace();
                  Log.i("AsyncTask", "doInBackground: Exception");
                  result = true;
              } finally {
                  try {
                      nis.close();
                      nos.close();
                      nsocket.close();
                  } catch (IOException e) {
                      e.printStackTrace();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
                  Log.i("AsyncTask", "doInBackground: Finished");
              }
              return result;
          }
  
          public void SendDataToNetwork(String cmd) { //You run this from the main thread.
              try {
                  if (nsocket.isConnected()) {
                      Log.i("AsyncTask", "SendDataToNetwork: Writing received message to socket");
                      nos.write(cmd.getBytes());
                  } else {
                      Log.i("AsyncTask", "SendDataToNetwork: Cannot send message. Socket is closed");
                  }
              } catch (Exception e) {
                  Log.i("AsyncTask", "SendDataToNetwork: Message send failed. Caught an exception");
              }
          }
  
          @Override
          protected void onProgressUpdate(byte[]... values) {
              if (values.length &gt; 0) {
                  Log.i("AsyncTask", "onProgressUpdate: " + values[0].length + " bytes received.");
                  textStatus.setText(new String(values[0]));
              }
          }
          @Override
          protected void onCancelled() {
              Log.i("AsyncTask", "Cancelled.");
              btnStart.setVisibility(View.VISIBLE);
          }
          @Override
          protected void onPostExecute(Boolean result) {
              if (result) {
                  Log.i("AsyncTask", "onPostExecute: Completed with an Error.");
                  textStatus.setText("There was a connection error.");
              } else {
                  Log.i("AsyncTask", "onPostExecute: Completed.");
              }
              btnStart.setVisibility(View.VISIBLE);
          }
      }
  
      @Override
      protected void onDestroy() {
          super.onDestroy();
          networktask.cancel(true); //In case the task is currently running
      }
  }
  </code></pre>