Android

Asynchronous HTTP Client In Android

Written by Yasir Ameen

In my previous tutorial Android Working With HTTP , i discussed how to create custom Http clientfor using HttpUrlConnection. In this tutorial i will discuss asynchronous Http client. An asynchronous Http client for Android built on top of Apache’s HttpClient libraries.

Let’s Dig Into Asynchronous HTTP Client

Before writing anything, add a following dependency in your project build

compile 'com.loopj.android:android-async-http:1.4.9'

Topic i am going to cover in this post are

  • Fetching Raw String
  • How to Show Progress Dialog in AsyncHttpResponseHandler Request
  • Downloading Image File Using BinaryHttpResponseHandler
  • Downloading Any File Using BinaryHttpResponseHandler
  • Downloading File Using FileAsyncHttpResponseHandler
  • Working With JSONObject And JSONArray
  • Creating Custom List Adapter With JsonHttpResponseHandler
  • Making POST/GET Request To The Server
  • Uploading an Image File To PHP Server As Base64 Encoded String
  • Uploading a File To PHP Server [Coming Soon]
  • Uploading a Multipart File To PHP Server [Coming Soon]
  • Working With Cookies And Session [Coming Soon]

Important: Keep in mind that, all the codes snippet is ready to use, all code is inside onCreate() method.

 

Fetching Raw String

It is very easy to fetch raw string from the web using Asynchronous Http Client. Just call TextHttpResponseHandler() callback and receive result as responseString.

 new AsyncHttpClient().get("http://www.yasirameen.com";, new TextHttpResponseHandler() {

    @Override
    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {

        Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, String responseString) {

        // responseString contain Html of www.yasirameen.com
        Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
    }

   
});

 

How to Progress Dialog in Async Request

You can show progress dialog when making requests, call onStart() and onFinish() methods of AsynchHttpClient(), see the code below

AsyncHttpClient client = new AsyncHttpClient();
client.post("http://www.yasirameen.com", params, new TextHttpResponseHandler() {

    ProgressDialog pd;
    @Override
    public void onStart() {

        pd = new ProgressDialog(MainActivity.this);
        pd.setTitle("Please Wait..");
        pd.setMessage("AsyncHttpResponseHadler is in progress");
        pd.setIndeterminate(false);
        pd.setCancelable(false);
        pd.show();

    }

    @Override
    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {

        Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, String responseString) {

        Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onFinish() {
        pd.dismiss();
    }
});

 

Downloading Image File Using BinaryHttpResponseHandler

Using Asynchronous Http Client you can download any file by specifying the content type of file you are going to download. In the following code snippet, I am downloading image file which is in .png format by describing its content types.

You can see list of MIME Types here.

 


final String SourceFilname = "http://demo.yasirameen.com/android_alone.jpg";
AsyncHttpClient client = new AsyncHttpClient();
String[] fileType = {

                   "image/png",
                   "image/jpeg",
                   "image/gif"
                };
client.get(SourceFilname, new BinaryHttpResponseHandler(fileType) {
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {

        try {   
            //Splitting a File Name from SourceFileName
            String DestinationName = SourceFilname.substring(SourceFilname.lastIndexOf('/')+1, SourceFilname.length());
            //Saving an image into DCIM Folder
            File _f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),DestinationName);
            FileOutputStream output =new  FileOutputStream(_f);
            output.write(binaryData);
            output.close();
         
            //Refreshing MediaScanner, so that our downloaded image can be shown in Gallery
            Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
            File f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),DestinationName);
            Uri contentUri = Uri.fromFile(f);
            mediaScanIntent.setData(contentUri);
            sendBroadcast(mediaScanIntent);
       
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {

    }
});

 

Downloading Any File Using BinaryHttpResponseHandler

As i described above that we can download any file using Asynchronous Http Client with  BinaryHttpResponseHandler() , just pass the content type of file and you are done.


final String SourceFilname = "http://demo.yasirameen.com/sample_java.pdf";
AsyncHttpClient client = new AsyncHttpClient();
String[] allowedType = {

        "application/pdf"
};
client.get(SourceFilname, new BinaryHttpResponseHandler(allowedType) {
    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] binaryData) {


        try {

            //Splitting a File Name from SourceFileName
            String DestinationName = SourceFilname.substring(SourceFilname.lastIndexOf('/')+1, SourceFilname.length());
            //Saving a File into Download Folder 
            File _f = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),DestinationName);
            FileOutputStream output =new  FileOutputStream(_f);
            output.write(binaryData);
            output.close();
            


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] binaryData, Throwable error) {

    }
});

Downloading File Using FileAsyncHttpResponseHandler

In Asynchronous Http Client Library, there is a FileAsyncHttpResponseHandler() available which is used to download any file without having to specify mime types file. When you use FileAsyncHttpResponseHandler() or BinaryHttpResponseHandler(), file downloaded into the cache.

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

       final String SourceFilname = "http://demo.yasirameen.com/android_alone.jpg";
       AsyncHttpClient client = new AsyncHttpClient();
       client.get("http://demo.yasirameen.com/android_alone.jpg", new FileAsyncHttpResponseHandler(getApplicationContext()) {
           @Override
           public void onFailure(int statusCode, Header[] headers, Throwable throwable, File file) {

               try {
                   //Splitting a File Name from SourceFileName
                   String DestinationName = SourceFilname.substring(SourceFilname.lastIndexOf('/')+1, SourceFilname.length());
                   //Saving an image into DCIM Folder
                   File newFile = new File(Environment.getExternalStorageDirectory(),DestinationName);
                   cacheCopy(file,newFile);
               }catch (IOException ex) {
                   ex.printStackTrace();
               }
           }

           @Override
           public void onSuccess(int statusCode, Header[] headers, File file) {

           }
       });

    }

    //Copy downloaded file into SD Card From cache
    public static void cacheCopy(File src, File dst) throws IOException {
        FileChannel inChannel = new FileInputStream(src).getChannel();
        FileChannel outChannel = new FileOutputStream(dst).getChannel();
        try {
            inChannel.transferTo(0, inChannel.size(), outChannel);
        } finally
        {
            if (inChannel != null) inChannel.close(); if (outChannel != null) outChannel.close();
        }
    }
    //function End..

}

//Copy downloaded file into SD Card From cache
public static void cacheCopy(File src, File dst) throws IOException {
 FileChannel inChannel = new FileInputStream(src).getChannel();
 FileChannel outChannel = new FileOutputStream(dst).getChannel();
 try {
     inChannel.transferTo(0, inChannel.size(), outChannel);
 } finally
          {
 if (inChannel != null) inChannel.close(); if (outChannel != null) outChannel.close();
    }
}

Working With JSONObject And JSONArray

Handling JSON is very using asynchronous http client, you don’t need to worry about parsing JSON into JSONObject or into JSONArray,  JsonHttpResponseHandler() does all the parsing for you, all you need to is make them use.

  • Getting JSONObject – You can simply receive

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://demo.yasirameen.com/games.json",new JsonHttpResponseHandler() {

    @Override
    public void onSuccess(int statusCode, Header[] headers, JSONObject response) {

        //Json object is returned as a response
    }
});
  • Getting JSONArray- You can simply receive
AsyncHttpClient client = new AsyncHttpClient();
client.get("http://demo.yasirameen.com/games.json",new JsonHttpResponseHandler() {

    @Override
    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {

        //Json Array is returned as a response
    }
});

Creating Custom List Adapter With JsonHttpResponseHandler

Let’s use the above code snippet in order to use JsonHttpResponseHandler()  to handle JSON data and show it on the ListView.

Creating ListItem Template

create a xml file list_item_template.xml in res=>layout folder paste the follwing xml, this xml file will be use a list_item_template.

<?xml version="1.0" encoding="utf-8">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <ImageView
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:layout_marginLeft="12dp"
        android:layout_marginTop="14dp"
        android:id="@+id/gameImage"
        android:paddingBottom="10dp"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text="Devil May Cry"
        android:textSize="18sp"
        android:id="@+id/tvtitle"
        android:paddingLeft="4dp"
        android:paddingRight="5dp"
        android:layout_alignTop="@+id/gameImage"
        android:layout_toRightOf="@+id/gameImage"
        android:layout_toEndOf="@+id/gameImage" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:text="Small Text"
        android:lines="1"
        android:ellipsize="end"
        android:paddingLeft="4dp"
        android:paddingRight="5dp"
        android:textSize="12sp"
        android:id="@+id/tvdesc"
        android:layout_below="@+id/tvtitle"
        android:layout_alignLeft="@+id/tvtitle"
        android:layout_alignStart="@+id/tvtitle"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceSmallPopupMenu"
        android:text="Plateform : PS3, XBOX 360"
        android:id="@+id/tvplateform"
        android:paddingLeft="4dp"
        android:paddingRight="5dp"
        android:paddingBottom="5dp"
        android:textSize="12sp"
        android:layout_below="@+id/tvdesc"
        android:layout_alignLeft="@+id/tvdesc"
        android:layout_alignStart="@+id/tvdesc" />

</RelativeLayout>

above xml will create layout look like below.

custom listview template

Writing Game Adapter Class

Create a class in your project and name it GameAdapter.java and extend it to the BaseAdapter Class and dont forget to add Picasso Library in your project. The tricky part is describe in this class for creating very responsive custom listview with.

compile 'com.squareup.picasso:picasso:2.5.2'

Note: I am using Picasso  Image library here for downloading image separately, add Picasso dependency before writing Adapter Class.

 

  public class GameAdapter extends BaseAdapter {

    private final JSONArray jsonArray;
    private final Activity activity;

    public GameAdapter(Activity activity, JSONArray jsonArray){

        this.activity = activity;
        this.jsonArray = jsonArray;
    }

    @Override
    public int getCount() {
        if(null==jsonArray) return  0;
        return jsonArray.length();
    }

    @Override
    public JSONObject getItem(int i) {
        if(null==jsonArray) return null;

        JSONObject x = null;
        try {
            x = jsonArray.getJSONObject(i);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return x;
    }

    @Override
    public long getItemId(int i) {
        JSONObject jsonObject = getItem(i);
        return jsonObject.optLong("id");
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        if(view == null) {
            view = activity.getLayoutInflater().inflate(R.layout.list_item_template,null);
        }

        TextView tvtitle = (TextView) view.findViewById(R.id.tvtitle);
        TextView tvdesc = (TextView) view.findViewById(R.id.tvdesc);
        TextView tvplatform = (TextView) view.findViewById(R.id.tvplateform);
        ImageView imgView = (ImageView) view.findViewById(R.id.gameImage);

        JSONObject jsondata = getItem(i);

        String imgurl = "http://demo.yasirameen.com/uploads/";

        try {

            tvtitle.setText(jsondata.getString("title"));
            tvdesc.setText(jsondata.getString("desc"));
            tvplatform.setText(jsondata.getString("platforms"));

            String itemImage = jsondata.getString("image");
            Picasso.with(activity.getApplicationContext())
                    .load(imgurl+itemImage)
                    .into(imgView);

        } catch (JSONException e) {
            e.printStackTrace();
        }
        
        return view;
    }
}

 

Now open MainActivity.java and call JsonHttpResponseHandler() along with GameAdapter and you are done 🙂

AsyncHttpClient client = new AsyncHttpClient();
client.get("http://demo.yasirameen.com/games.json",new JsonHttpResponseHandler() {
   
    @Override
    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
        
        ListView lv = (ListView) findViewById(R.id.listView);
        lv.setAdapter(new GameAdapter(MainActivity.this,response));

    }
});

Run the app and you will see how fast is the response also the images are downloading with automatic cache handling.

asynchronous Http client json

———————————————————————————————————————————-

Making POST/GET Request To The Server

AsyncHttpResponseHandler class is already handling GET request in every action we fire from Asynchronous Http Client, but if you want to pass parameter when making GET/POST request to the server, use RequestParams class.

RequestParams params = new RequestParams();
params.put("param","value");

 

Complete Example Of POST Request

It is very easy to post parameter to php server using Asynchronous HTTP Client. Just create an object of RequestParams class and pass whatever you want to send to the server using the put() method.

Here is a simple php script, which expects username and password as a POST request.

<?php

if(isset($_POST['username']) && isset($_POST['userpass'])) {

    $username = $_POST['username'];
    $userpass = $_POST['userpass'];

    if($username == "admin" && $userpass == "admin123@") {
        echo 'Login Success';
    }
    else {
        echo "Login Failed";
    }
}

Here is the code as client in Android.


RequestParams params = new RequestParams();
params.put("username","admin");
params.put("userpass","admin123");

AsyncHttpClient client = new AsyncHttpClient();
client.post("http://demo.yasirameen.com/check_login.php", params, new TextHttpResponseHandler() {
    @Override
    public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {

        Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, String responseString) {

        Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
    }
});

Uploading an Image File To PHP Server As Base64 Encoded String

You can send an image file to php server using the technique that, you convert your image to Base64Encode String and then send the Encoded String to server, then server decode it back using Base64Decode to an image. Here is the example/

PHP script which expects encodedString and image as a post parameter.

<?php
header('content-type : bitmap; charset=utf-8');
if(isset($_POST["image"])) {

    $encoded_string = $_POST["encoded_string"];
    $image_name = $_POST["image"];

    $decoded_string = base64_decode($encoded_string);

    $path = 'uploads/'.$image_name;

    $file = fopen($path,'wb');
    $is_written = fwrite($file,$decoded_string);
    fclose($file);
    
    echo 'Image Uploading Success';
}

Following is the full working implementation of sending image to a server as Base64Encode String.


public class MainActivity extends AppCompatActivity {

    private static final int PICK_IMAGE_REQUEST = 1;

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

        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE_REQUEST);

    }
    
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {

            Uri uri = data.getData();

            String str = getImageBase64(uri);

            RequestParams params = new RequestParams();
            params.put("encoded_string",str);
            params.put("image","newImage.png");

            AsyncHttpClient client = new AsyncHttpClient();
            client.post("http://localhost/xyz/image_upload.php", params, new TextHttpResponseHandler() {

                ProgressDialog pd;
                @Override
                public void onStart() {

                    pd = new ProgressDialog(MainActivity.this);
                    pd.setTitle("Please Wait");
                    pd.setMessage("Uploading Image In Progress");
                    pd.setIndeterminate(false);
                    pd.setCancelable(true);
                    pd.show();

                }

                @Override
                public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) {

                    Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onSuccess(int statusCode, Header[] headers, String responseString) {

                    Toast.makeText(MainActivity.this, responseString, Toast.LENGTH_SHORT).show();
                }
                

                @Override
                public void onFinish() {
                    pd.dismiss();
                }
            });

        }
    }

    //Converting Selected Image to Base64Encode String
    private String getImageBase64(Uri selectedImage) {
        Bitmap myImg = null;
        try {
            myImg = decodeUri(selectedImage);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        // Must compress the Image to reduce image size to make upload easy
        myImg.compress(Bitmap.CompressFormat.PNG, 50, stream);
        byte[] byte_arr = stream.toByteArray();
        // Encode Image to String
        return  android.util.Base64.encodeToString(byte_arr, 0);
    }

    //Reducing Image Size of a selected Image
    private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException {

        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o);

        // The new size we want to scale to
        final int REQUIRED_SIZE = 500;

        // Find the correct scale value. It should be the power of 2.
        int width_tmp = o.outWidth, height_tmp = o.outHeight;
        int scale = 1;
        while (true) {
            if (width_tmp / 2 < REQUIRED_SIZE
                    || height_tmp / 2 < REQUIRED_SIZE) {
                break;
            }
            width_tmp /= 2;
            height_tmp /= 2;
            scale *= 2;
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeStream(getContentResolver().openInputStream(selectedImage), null, o2);

    }

    
}

 

So far i am ending here, i will come back with File Uploading/Multipart Uploading etc..

 


	

About the author

Yasir Ameen

I'm a programmer, teacher, and speaker. I work out of my home in Pakistan, Karachi for the Mobile, especially Android Platform. I discuss about technology, gadgets, codes, the devices we’re going and we’ve been. I’m excited about community, social equity, and media.

6 Comments

  • This is quite helpful in a lot of ways. Something was somehow unclear to me though. Where exactly in MainActivity is this ?:
    AsyncHttpClient client = new AsyncHttpClient();
    client.get(“http://demo.yasirameen.com/games.json”,new JsonHttpResponseHandler() {

    @Override
    public void onSuccess(int statusCode, Header[] headers, JSONArray response) {

    ListView lv = (ListView) findViewById(R.id.listView);
    lv.setAdapter(new GameAdapter(MainActivity.this,response));

    }
    });

    It seems to me that I can’t set the adapter in onSuccess method. Do we still need the OnCreatView method?

Leave a Comment