Showing posts with label AsyncTask and HttpClient to post data to Servlet Tutoriall. Show all posts
Showing posts with label AsyncTask and HttpClient to post data to Servlet Tutoriall. Show all posts

Tuesday, May 28, 2013

AsyncTask and HttpClient to post data to Servlet Tutorial

AsyncTask and  HttpClient to post data to Servlet Tutorial
              For many android applications it is essential that app  needs to connect to internet and make some HTTP requests.Steps below explain about making simple HTTP Requests in android.
Create your HttpClient and HttpPost objects to execute the POST request. The address is a String object representing your POST's destination, such as a Servelt,JSP page or PHP
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(address);

Setting POST data. A list of NameValuePairs are created and set as the HttpPost's entity.Ensure to catch the UnsupportedEncodingException thrown by HttpPost.setEntity().
List<NameValuePair> pairs = new ArrayList<NameValuePair>();
pairs.add(new BasicNameValuePair("key1", "value1"));

pairs.add(new BasicNameValuePair("key2", "value2"));

post.setEntity(new UrlEncodedFormEntity(pairs));

Execute the POST request. This returns an HttpResponse object, whose data can be extracted and parsed. Ensure to catch the ClientProtocolException and IOException thrown.
HttpResponse response = client.execute(post);.
Do not forget to declare Internet permissions in the manifest by adding the following line to AndroidManifest.xml. This allows your application to use any Internet connections.
AsyncTask:
               AsyncTask is an abstract class provided by Android which helps us to use the UI thread properly. This class allows us to perform long/background operations and show its result on the UI thread without having to manipulate threads
When to use AsyncTask?

            Android implements single thread model and whenever an android application is launched, a thread is created. Assuming we are doing network operation on a button click in our application. On button click a request would be made to the server and response will be awaited. Due to single thread model of android, till the time response is awaited our screen is non-responsive. So we should avoid performing long running operations on the UI thread. This includes file and network access.AsyncTask which runs separate thread in background  .Any meaningful GUI application needs to employ multiple threads, otherwise it is very likely to lock while doing any I/O operations - leaving bad impression on the user. Same is true for Android apps. In fact, android framework prompts user to close the app if it doesn't respond in 10 seconds or so. So it's absolutely essential to perform any task - that has even a remote possibility of taking a bit longer - in a background thread.


            To overcome this we can create new thread and implement run method to perform this network call, so UI remains responsive.
            But since Android follows single thread model and Android UI toolkit is not thread safe, so if there is a need to make some change to the UI based on the result of the operation performed, then this approach may lead some issues.


 Android framework has given a very good pattern which is enveloped into AsyncTask.
Note: AsyncTask should ideally be used for operations that take few seconds. Some tasks keep the thread running for long time so in that case it is recommended to use java.util.concurrent package such as Executor, ThreadPoolExecutor and FutureTask.

AsyncTask has four steps:When an asynchronous task is executed, the task goes through 4 steps:

onPreExecute(), invoked on the UI thread before the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.

doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.

onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.

onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.

Cancelling a task, A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.).


Threading rules:There are a few threading rules that must be followed for this class to work properly:The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.

The task instance must be created on the UI thread.

execute(Params...) must be invoked on the UI thread.
 Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.

The task can be executed only once (an exception will be thrown if a second execution is attempted.)

Memory observability

AsyncTask guarantees that all callback calls are synchronized in such a way that the following operations are safe without explicit synchronizations.
Set member fields in the constructor or onPreExecute(), and refer to them in doInBackground(Params...).
Set member fields in doInBackground(Params...), and refer to them in onProgressUpdate(Progress...) and onPostExecute(Result).
           The sample program demonstrates a how an Android application connects to the webserver server side programs like servlet.


1.Create  Android project with details as listed in table below
Property name
Property value
Project name
SRM_HttpPost
Package name
in.ac.srmuniv
Activity name
HttpPostActivity
Layout xml name
main
2.Copy the code  to the file main.xml in res/layout folder 
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <TableRow
        android:id="@+id/tableRow1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
      <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/name"
            android:textAppearance="?android:attr/textAppearanceLarge" />


        <EditText
            android:id="@+id/editText1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10" />
    </LinearLayout>

    </TableRow>

    <TableRow
        android:id="@+id/tableRow2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:id="@+id/textView2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/password"
                android:textAppearance="?android:attr/textAppearanceLarge" />

            <EditText
                android:id="@+id/editText2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:ems="10"
                android:inputType="textPassword" >

                <requestFocus />
            </EditText>

        </LinearLayout>

    </TableRow>

    <TableRow
        android:id="@+id/tableRow3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center" >
           
            <ProgressBar
                android:id="@+id/progressBar1"
                style="?android:attr/progressBarStyleLarge"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />

        </LinearLayout>

    </TableRow>

    <TableRow
        android:id="@+id/tableRow4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:orientation="horizontal" >

            <Button
                android:id="@+id/button1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:onClick="readWebpage"
                android:text="Submit" />

        </LinearLayout>

    </TableRow>

</TableLayout>
3.Copy the code in HttpPostActivity.java. Activity.
package in.ac.srmuniv;

importjava.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
importjava.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

importorg.apache.http.HttpEntity;
importorg.apache.http.HttpResponse;
importorg.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
importorg.apache.http.client.HttpClient;
importorg.apache.http.client.entity.UrlEncodedFormEntity;
importorg.apache.http.client.methods.HttpPost;
importorg.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
importorg.apache.http.params.HttpParams;

importandroid.os.AsyncTask;
import android.os.Bundle;
importandroid.app.Activity;
importandroid.app.ProgressDialog;
importandroid.content.Context;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.EditText;
importandroid.widget.ProgressBar;
importandroid.widget.TextView;
import android.widget.Toast;

public class HttpPostActivity extends Activity {
    EditText e1,e2;
    ProgressDialog dialog = null;
    TextView tv;
    Context c;
    private static final int REGISTRATION_TIMEOUT = 3 * 1000;
    private static final int WAIT_TIMEOUT = 30 * 1000;
    private final HttpClient httpclient = new DefaultHttpClient();

    final HttpParams params = httpclient.getParams();
    HttpResponse response;
    private String contentnull;
    private boolean error = false;
    private ProgressBar pb;

    @Override
    protected void onCreate(Bundle savedInstanceState)                     {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        Button b=(Button)findViewById(R.id.button1);
          e1=(EditText)findViewById(R.id.editText1);
          e2=(EditText)findViewById(R.id.editText2);
         
          pb=(ProgressBar)findViewById(R.id.progressBar1);
            pb.setVisibility(View.GONE);
          c=this;
       
    }

public void readWebpage(View view) {
    final String s1=e1.getText().toString();
    final String s2=e2.getText().toString();
    pb.setVisibility(View.VISIBLE);              
   
      
    newMyAsyncTask().execute(s1,s2);

  }

    @Override
    public booleanonCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.http_post, menu);
        return true;
    }
    private class MyAsyncTask extends AsyncTask<String, Integer, String>{
   

        @Override
        protected String doInBackground(String... params) {
            // TODO Auto-generated method stub
            String s=postData(params);
            return s;
        }

        protected void onPostExecute(String result){
            pb.setVisibility(View.GONE);
            Toast.makeText(getApplicationContext(), result, Toast.LENGTH_LONG).show();
        }
        protected voidonProgressUpdate(Integer... progress){
            pb.setProgress(progress[0]);
        }

        public String postData(String valueIWantToSend[]) {
            // Create a new HttpClient and Post Header
            HttpClient httpclient = new DefaultHttpClient();
            HttpPost httppost = new HttpPost("http://10.0.2.2:8080/ServletParams/AndroidServlet");
             String origresponseText="";
            try {
                // Add your data
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
                nameValuePairs.add(new BasicNameValuePair("param1",valueIWantToSend[0]));
                nameValuePairs.add(new BasicNameValuePair("param2", valueIWantToSend[1]));
                httppost.setEntity(newUrlEncodedFormEntity(nameValuePairs));
         /* execute */
                HttpResponse response = httpclient.execute(httppost);
                  HttpEntity rp = response.getEntity();
origresponseText=readContent(response);
            } 
      catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
            } 
      catch (IOException e) {
                // TODO Auto-generated catch block
            }
          String responseText = origresponseText.substring(7, origresponseText.length());
            return responseText;
        }
       

    }
    String readContent(HttpResponse response)
    {
        String text = "";
        InputStream in =null;
         
        try {
            in = response.getEntity().getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder sb = new StringBuilder();
            String line = null;
            while ((line = reader.readLine()) != null) {
                  sb.append(line + "\n");
                }
                text = sb.toString();
        } catch(IllegalStateException e) {
            e.printStackTrace();
           
        } catch (IOException e) {
              e.printStackTrace();
        }
        finally {
            try {

              in.close();
            } catch (Exception ex) {
            }
            }

return text;
    }
   
}

3.AndroidManifest.xml code you should add INTERNET permission

<?xml version="1.0"encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.nawin"
    android:versionCode="1"
    android:versionName="1.0" >
<uses-permission android:name="android.permission.INTERNET"/>
    <uses-sdk
        android:minSdkVersion="11"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.nawin.HttpPostActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

</manifest>


4.Create a servlet code,you can create it using eclipse or Netbeans.Root context is ServletParams and name of the servlet is Androidservlet.

package in.ac.srmuniv;

import java.io.IOException;
importjava.io.ObjectOutputStream;
import java.io.PrintWriter;
importjava.util.Enumeration;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author Ganeshan
 */
public class AndroidServlet extends HttpServlet {

    public void doGet(HttpServletRequest request,HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html");

        ObjectOutputStream out = newObjectOutputStream(response
                .getOutputStream());
        Enumeration paramNames = request.getParameterNames();
        String params[]= new String[2];
        int i=0;
        while(paramNames.hasMoreElements()) {
            String paramName = (String)paramNames.nextElement();

            System.out.println(paramName );
            String[] paramValues = request.getParameterValues(paramName);
            params[i] = paramValues[0];

            System.out.println(params[i]);
            i++;

        }

        if(params[0].equals("nawin"))
        {

            if(params[1].equals("shiva"))
            {
                out.writeObject("success");
            }
            else
            {
                out.writeObject("wrong password");
            }
        }
        else
        {
            out.writeObject("wrong username"); 
        }
    } 
    public void doPost(HttpServletRequest request,HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

5.Run the Servlehttp://localhost:8080/ServletParams/ is the context path for the application
Run the Android application in the emulator and following screen shots provide how android app connects to servlet for login authentication

       
Figure 2  A Login form in android application Figure 3  When submit button is clicked it connects to servlet and post data
         

Figure 4 Servlet response to the posted data displayed through Toast with authentication success
Figure 5 Servlet response to the posted data displayed through Toast with authentication failure

Fig 6 Servlet running in local tomcat binded to  Netbeans IDE
CODE EXPLANATION
                 The HttpPostActivity uses private class MyAsyncTask extends AsyncTask<String, Integer, String> " generic type parameters refer to the doInBackground,onProgressUpdate,onPostExecute call back methods input  parameters respectively.UI handling can be done in any of the methods except in doInBackground method.
        The Apache HttpClient library simplifies handling HTTP requests. To use this library download the binaries with dependencies from http://hc.apache.org/ and add then to your project class path,but android core library ships with apache httpClient library.Google recommended in 2011 to use HttpURLconnection for http based connections.In our example when user clicks submit button method readWebpage() is called  which sets the progressbar visibility to true and invokes AsyncTask  doInBackground() method do the connection to the local tomcat server "http://10.0.2.2:8080/ServletParams/AndroidServlet" and post the parameters fetched from editText views. doInBackground() method returns the result in String which will be received by onPostExecute(String result).The result will be "success" or "failure" returned by Servlet .Android app decides to implement its application logic depending on the response received from server side .You can connect servlet to databases to fetch data  for validation to perform  authentication.

The Demonstrative project downloads image from URL while download is in progress progress bar is active 
1.Create  Android project with details as listed in table below
Property name
Property value
Project name
SRM_FileDownloadTutorial
Package name
in.ac.srmuniv.filedownload
Activity name
MainActivity
Layout xml name
activity_main
2.Copy the code  to the file activity_main.xml in res/layout folder 
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btnProgressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="40dip"
        android:text="Download Image" />

    <!-- Image view to show image after downloading -->

    <ImageView
        android:id="@+id/my_image"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <!-- Download Button -->
</LinearLayout>
3.Copy the code in MainActivity.java. Activity.
package in.ac.srmuniv.filedownload;

import java.io.BufferedInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity {

    // button to show progress dialog
    Button downLoad;

    // Progress Dialog
    private ProgressDialog progressDialog;
    ImageView my_image;
    // Progress dialog type (0 - for Horizontal progress bar)
    public static final int progress_bar_type = 0;

    // File url to download
    private static String file_url = "http://www.srmuniv.ac.in/sites/default/files/images/images11.jpg";

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

        // show progress bar button
        downLoad = (Button) findViewById(R.id.btnProgressBar);
        // Image view to show image after downloading
        my_image = (ImageView) findViewById(R.id.my_image);
        /**
         * Show Progress bar click event
         * */
        downLoad.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // starting new Async Task
                new DownloadFileFromURL().execute(file_url);
            }
        });
    }

    /**
     * Showing Dialog
     * */
    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
        case progress_bar_type:
            progressDialog = new ProgressDialog(this);
            progressDialog.setMessage("Downloading file. Please wait...");
            progressDialog.setIndeterminate(false);
            progressDialog.setMax(100);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.setCancelable(true);
            progressDialog.show();
            return progressDialog;
        default:
            return null;
        }
    }

    /**
     * Background Async Task to download file
     * */
    class DownloadFileFromURL extends AsyncTask<String,Integer, String> {
        /**
         * Before starting background thread
         * Show Progress Bar Dialog
         * */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            showDialog(progress_bar_type);
        }

        /**
         * Downloading file in background thread
         * */
        @Override
        protected String doInBackground(String... fileurl) {
            int count;
            try {
                URL url = new URL(fileurl[0]);
                URLConnection conection = url.openConnection();
                conection.connect();
                // getting file length
                int lenghtOfFile = conection.getContentLength();

                // input stream to read file - with 8k buffer
                InputStream input = new BufferedInputStream(url.openStream(), 8192);

                // Output stream to write file
                OutputStream output = new FileOutputStream("/sdcard/downloadedfile.jpg");

                byte data[] = new byte[1024];

                long total = 0;

                while ((count = input.read(data)) != -1) {
                    total += count;
                    // publishing the progress....
                    // After this onProgressUpdate will be called
                    publishProgress((int)((total*100)/lenghtOfFile));
                    // writing data to file
                    output.write(data, 0, count);
                }

                // flushing output
                output.flush();

                // closing streams
                output.close();
                input.close();

            } catch (Exception e) {
                Log.e("Error: ", e.getMessage());
            }

            return null;
        }

        /**
         * Updating progress bar
         * */
        protected void onProgressUpdate(Integer... downloadprogress) {
            // setting progress percentage
            progressDialog.setProgress(downloadprogress[0]);
        }

        /**
         * After completing background task
         * Dismiss the progress dialog
         * **/
        @Override
        protected void onPostExecute(String file_url) {
            // dismiss the dialog after the file was downloaded
            dismissDialog(progress_bar_type);

            // Displaying downloaded image into image view
            // Reading image path from sdcard
            String imagePath = Environment.getExternalStorageDirectory().toString() + "/downloadedfile.jpg";
            // setting downloaded into image view
            my_image.setImageDrawable(Drawable.createFromPath(imagePath));
        }

    }
}
4.Modify Androidmanifest.xml  to add permissions for connecting to internet and writing file to SD card.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="in.ac.srmuniv.filedownload"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk android:minSdkVersion="8" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".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>
    </application>
    <!-- Permission: Allow Connect to Internet -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- Permission: Writing to SDCard -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
</manifest>
5.Run the application in the emulator/device. 
 Figure Shows the Progress in action when Download button is clicked Figure Shows  download in progress

Figure Shows Downloaded image shown in image View
CODE EXPLANATION
                      In this example on a button click "Download" in Activity starts downloading the file in new Thread.The DownloadFileFromURL AsyncTask gets file url as input parameter and  doInBackground() method do file dowmloaing and file writing to SD card. The publishProgress() method call is done in the while loop(which is going to do time intensive job such as downloading data ,writing data to memory)of doInBackground() AsyncTask  callback method .
                 while ((count = input.read(data)) != -1) {
                    total += count;
                    // publishing the progress....
                    // After this onProgressUpdate will be called
                    publishProgress((int)((total*100)/lenghtOfFile));
                    // writing data to file
                    output.write(data, 0, count);
                }
    
      In our example data from network is read and it is written in to SD card.The call to  publishProgress method is done in while loop and amount of data read is  calculated in percentage every time data is read (advisable to call only when  a specific chunk of data is read ).The calculated data  is passed as parameter to  publishProgress method in turn will call onprogessUpdate() method.in which update of progress bar is done.
        protected void onProgressUpdated(Integer... downloadprogress) {
            // setting progress percentage
     progressDialog.setProgress(downloadprogress[0]);
        }
         The onPreExecute()method is called before the doInBackground() method..Here initialization codes before background processing is done.DialogBox is made visible with type horizontal.
 protected void onPreExecute() {
            super.onPreExecute();
            showDialog(progress_bar_type);


        }