We know how much web API is useful while working in Mobile or Web Application. Here the term API means the interface that consists of publicly exposed endpoint for a request. This is defined in the context of HTTP-based web server. An API takes request i.e. parameters or the input and processes it to produce some desired output to serve as response. We use APIs by calling them from our application. In this article we are going to learn how to call an API. We will be using volley to achieve that. Though it can be implemented using different tools also like HttpURLConnection, Retrofit etc. but we prefer volley as it is easy to implement and works fine with android.
Volley is a library that provides easy network calling with caching, retry, back-off options. You can customize it as per your requirement. It provides debug and trace tools also. Most important thing about volley is Google recommends it.
VOLLEY IMPLEMENTATION
To use volley with your android application first add dependency to your build.gradle(app level).
1 2 3 4 5 6 7 8 |
dependencies { ... compile 'com.android.volley:volley:1.0.0' } |
Then we will create an interface, say FetchDataListener to use it as listener. We will use it’s methods as callback while calling API request using volley. It will have some methods like onFetchComplete(), onFetchFailure(), onFetchStart() etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.digitstory.testapplication; import org.json.JSONObject; public interface FetchDataListener { void onFetchComplete(JSONObject data); void onFetchFailure(String msg); void onFetchStart(); } |
In the above code we are assuming all our API response will come in JSON format and we will convert them to JSONObject. You can change this to List<>, Map<> whatever you need. Next, we will implement our API classes. Our API classes will be generic so that we can use it for any API throughout the whole application. For that we will make two API classes – one for GET requests and another for POST requests to handle. The classes will be
- GETAPIRequest – To call GET APIs.
- POSTAPIRequest – To call POST APIs.
Now let’s have a look at the GETAPIRequest class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
package com.digitstory.testapplication; import android.content.Context; import com.android.volley.NoConnectionError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import org.json.JSONException; import org.json.JSONObject; public class GETAPIRequest { public void request(final Context context, final FetchDataListener listener, final String ApiURL) throws JSONException { if (listener != null) { //call onFetchComplete of the listener //to show progress dialog //-indicates calling started listener.onFetchStart(); } //base server URL String baseUrl="http://studypeek.com/test/"; //add extension api url received from caller //and make full api String url = baseUrl + ApiURL; JsonObjectRequest postRequest = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { if (listener != null) { if(response.has("response")) { //received response //call onFetchComplete of the listener listener.onFetchComplete(response); }else if(response.has("error")){ //has error in response //call onFetchFailure of the listener listener.onFetchFailure(response.getString("error")); } else{ listener.onFetchComplete(null); } } }catch (JSONException e){ e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (error instanceof NoConnectionError) { listener.onFetchFailure("Network Connectivity Problem"); } else if (error.networkResponse != null && error.networkResponse.data != null) { VolleyError volley_error = new VolleyError(new String(error.networkResponse.data)); String errorMessage = ""; try { JSONObject errorJson = new JSONObject(volley_error.getMessage().toString()); if(errorJson.has("error")) errorMessage = errorJson.getString("error"); } catch (JSONException e) { e.printStackTrace(); } if (errorMessage.isEmpty()) { errorMessage = volley_error.getMessage(); } if (listener != null) listener.onFetchFailure(errorMessage); } else { listener.onFetchFailure("Something went wrong. Please try again later"); } } }); RequestQueueService.getInstance(context).addToRequestQueue(postRequest.setShouldCache(false)); } } |
And code for POSTAPIRequest class will be
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
package com.digitstory.testapplication; import android.content.Context; import com.android.volley.NoConnectionError; import com.android.volley.Request; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.JsonObjectRequest; import org.json.JSONException; import org.json.JSONObject; public class POSTAPIRequest { public void request(final Context context, final FetchDataListener listener, JSONObject params, final String ApiURL) throws JSONException { if (listener != null) { //call onFetchComplete of the listener //to show progress dialog //-indicates calling started listener.onFetchStart(); } //base server URL String baseUrl="http://studypeek.com/test/"; //add extension api url received from caller //and make full api String url = baseUrl + ApiURL; //Requesting with post body as params JsonObjectRequest postRequest = new JsonObjectRequest(Request.Method.POST, url, params, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { if (listener != null) { if(response.has("response")) { //received response //call onFetchComplete of the listener listener.onFetchComplete(response); }else if(response.has("error")){ //has error in response //call onFetchFailure of the listener listener.onFetchFailure(response.getString("error")); } else{ listener.onFetchComplete(null); } } }catch (JSONException e){ e.printStackTrace(); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { if (error instanceof NoConnectionError) { listener.onFetchFailure("Network Connectivity Problem"); } else if (error.networkResponse != null && error.networkResponse.data != null) { VolleyError volley_error = new VolleyError(new String(error.networkResponse.data)); String errorMessage = ""; try { JSONObject errorJson = new JSONObject(volley_error.getMessage().toString()); if(errorJson.has("error")) errorMessage = errorJson.getString("error"); } catch (JSONException e) { e.printStackTrace(); } if (errorMessage.isEmpty()) { errorMessage = volley_error.getMessage(); } if (listener != null) listener.onFetchFailure(errorMessage); } else { listener.onFetchFailure("Something went wrong. Please try again later"); } } }); RequestQueueService.getInstance(context).addToRequestQueue(postRequest.setShouldCache(false)); } } |
As you can see in both above class we are calling our interface methods onFetchComplete(), onFetchFailure(), onFetchStart() whenever we get response or call failure or call to start(respectively) as per our requirement. These API will handle all API request(GET & POST) if the base URL is same for all.
Now it’s time to implement our interface FetchDataListener along with API calling.So we will create our Activity TestAPIActivity. But before that we need to clear what is RequestQueueService we have used in our both GETAPIRequest and POSTAPIRequest. RequestQueueService is the class to handle RequestQueue instance, retry-backoff options, error, alert, progess, caching for volley. Simple create the class RequestQueueService.java as fllowing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
package com.digitstory.testapplication; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.support.v4.app.FragmentActivity; import android.view.Window; import com.android.volley.DefaultRetryPolicy; import com.android.volley.Request; import com.android.volley.RequestQueue; import com.android.volley.toolbox.Volley; import java.util.HashMap; import java.util.Map; public class RequestQueueService { private static RequestQueueService mInstance; private RequestQueue mRequestQueue; private static Context mCtx; private static Dialog mProgressDialog; private RequestQueueService(Context context) { mCtx = context; mRequestQueue = getRequestQueue(); } public static synchronized RequestQueueService getInstance(Context context) { if (mInstance == null) { mInstance = new RequestQueueService(context); } return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { // getApplicationContext() is key, it keeps you from leaking the // Activity or BroadcastReceiver if someone passes one in. mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req) { req.setRetryPolicy(new DefaultRetryPolicy(5000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)); getRequestQueue().add(req); } public Map<String, String> getRequestHeader() { Map<String, String> headerMap = new HashMap<>(); return headerMap; } public void clearCache() { mRequestQueue.getCache().clear(); } public void removeCache(String key) { mRequestQueue.getCache().remove(key); } //To show alert / error message public static void showAlert(String message, final FragmentActivity context) { try { AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle("Error!"); builder.setMessage(message); builder.setPositiveButton("OK", null); builder.show(); }catch (Exception e){ e.printStackTrace(); } } //Start showing progress public static void showProgressDialog(final Activity activity) { activity.runOnUiThread(new Runnable() { @Override public void run() { if (mProgressDialog != null) { if (mProgressDialog.isShowing() == true) cancelProgressDialog(); } mProgressDialog = new Dialog(activity); mProgressDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); mProgressDialog.setContentView(R.layout.progress_indicator); mProgressDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); mProgressDialog.show(); mProgressDialog.setCancelable(false); } }); } //Stop showing progress public static void cancelProgressDialog() { if (mProgressDialog != null){ if (mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } } } } |
Create a layout file progress_indicator.xml in your layout folder and copy the following snippet. This is the code for so called loader or ProgressBar.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?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" android:background="@android:color/transparent"> <ProgressBar android:id="@+id/progreassIndicator" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="@android:color/transparent"/> </RelativeLayout> |
SAMPLE APIs to EXPERIMENT
We will call two APIs for our testing purpose, one is GET API another is POST API.
GET API
URL : http://studypeek.com/test/webapi.php?userId=1
Response :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "success": 1, "response": { "userId": 1, "firstName": "John", "lastName": "Doe", "age": 25 } } |
POST API
URL : http://studypeek.com/test/webapi.php
Request : { “userId”: 2 }
Response :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "success": 1, "response": { "userId": 2, "firstName": "Peter", "lastName": "Nille", "age": 28 } } |
Here both of the APIs having same base URL. So we will call the trailing part separately.
API CALL & RESULT
Now we will create our Activity to see things working perfectly. So create an activity called TestAPIActivity (You can choose any name) with layout. Layout of the activity would look like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" tools:context="com.digitstory.testapplication.TestAPIActivity"> <TextView android:id="@+id/resultTextView" android:padding="12dp" android:layout_marginTop="20dp" android:textColor="#000" android:hint="RESULT" android:textSize="15sp" android:background="#F2F2F2" android:layout_width="match_parent" android:layout_height="350dp" /> <LinearLayout android:layout_marginTop="20dp" android:layout_width="match_parent" android:weightSum="100" android:orientation="horizontal" android:layout_height="wrap_content"> <Button android:id="@+id/getApiBtn" android:textSize="20sp" android:textColor="#FFFFFF" android:text="GET API" android:layout_width="0dip" android:layout_weight="50" android:background="#3498DB" android:layout_height="wrap_content" /> <Button android:id="@+id/postApiBtn" android:textSize="20sp" android:textColor="#FFFFFF" android:text="POST API" android:layout_width="0dip" android:layout_weight="50" android:background="#000000" android:layout_height="wrap_content" /> </LinearLayout> </LinearLayout> |
And the code for the Activity is
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
package com.digitstory.testapplication; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import org.json.JSONObject; public class TestAPIActivity extends AppCompatActivity { private TextView resultTextView; private Button getApiBtn,postApiBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_test_api); resultTextView = (TextView)findViewById(R.id.resultTextView); getApiBtn = (Button)findViewById(R.id.getApiBtn); postApiBtn = (Button)findViewById(R.id.postApiBtn); //Attaching OnClickListener with Buttons getApiBtn.setOnClickListener(getApiListener); postApiBtn.setOnClickListener(postApiListener); } View.OnClickListener getApiListener=new View.OnClickListener() { @Override public void onClick(View view) { //Call getApiCall() method getApiCall(); } }; View.OnClickListener postApiListener=new View.OnClickListener() { @Override public void onClick(View view) { //Call postApiCall() method postApiCall(); } }; private void getApiCall(){ try{ //Create Instance of GETAPIRequest and call it's //request() method GETAPIRequest getapiRequest=new GETAPIRequest(); //Attaching only part of URL as base URL is given //in our GETAPIRequest(of course that need to be same for all case) String url="webapi.php?userId=1"; getapiRequest.request(TestAPIActivity.this,fetchGetResultListener,url); Toast.makeText(TestAPIActivity.this,"GET API called",Toast.LENGTH_SHORT).show(); }catch (Exception e){ e.printStackTrace(); } } //Implementing interfaces of FetchDataListener for GET api request FetchDataListener fetchGetResultListener=new FetchDataListener() { @Override public void onFetchComplete(JSONObject data) { //Fetch Complete. Now stop progress bar or loader //you started in onFetchStart RequestQueueService.cancelProgressDialog(); try { //Now check result sent by our GETAPIRequest class if (data != null) { if (data.has("success")) { int success = data.getInt("success"); if(success==1){ JSONObject response=data.getJSONObject("response"); if(response!=null) { //Display the result //Or, You can do whatever you need to //do with the JSONObject resultTextView.setText(response.toString(4)); } }else{ RequestQueueService.showAlert("Error! No data fetched", TestAPIActivity.this); } } } else { RequestQueueService.showAlert("Error! No data fetched", TestAPIActivity.this); } }catch (Exception e){ RequestQueueService.showAlert("Something went wrong", TestAPIActivity.this); e.printStackTrace(); } } @Override public void onFetchFailure(String msg) { RequestQueueService.cancelProgressDialog(); //Show if any error message is there called from GETAPIRequest class RequestQueueService.showAlert(msg,TestAPIActivity.this); } @Override public void onFetchStart() { //Start showing progressbar or any loader you have RequestQueueService.showProgressDialog(TestAPIActivity.this); } }; private void postApiCall(){ try{ //Create Instance of POSTAPIRequest and call it's //request() method POSTAPIRequest postapiRequest=new POSTAPIRequest(); //Attaching only part of URL as base URL is given //in our POSTAPIRequest(of course that need to be same for all case) String url="webapi.php"; JSONObject params=new JSONObject(); try { //Creating POST body in JSON format //to send in POST request params.put("userId",2); }catch (Exception e){ e.printStackTrace(); } postapiRequest.request(TestAPIActivity.this,fetchPostResultListener,params,url); Toast.makeText(TestAPIActivity.this,"POST API called",Toast.LENGTH_SHORT).show(); }catch (Exception e){ e.printStackTrace(); } } //Implementing interfaces of FetchDataListener for POST api request FetchDataListener fetchPostResultListener=new FetchDataListener() { @Override public void onFetchComplete(JSONObject data) { //Fetch Complete. Now stop progress bar or loader //you started in onFetchStart RequestQueueService.cancelProgressDialog(); try { //Now check result sent by our POSTAPIRequest class if (data != null) { if (data.has("success")) { int success = data.getInt("success"); if(success==1){ JSONObject response=data.getJSONObject("response"); if(response!=null) { //Display the result //Or, You can do whatever you need to //do with the JSONObject resultTextView.setText(response.toString(4)); } }else{ RequestQueueService.showAlert("Error! No data fetched", TestAPIActivity.this); } } } else { RequestQueueService.showAlert("Error! No data fetched", TestAPIActivity.this); } }catch (Exception e){ RequestQueueService.showAlert("Something went wrong", TestAPIActivity.this); e.printStackTrace(); } } @Override public void onFetchFailure(String msg) { RequestQueueService.cancelProgressDialog(); //Show if any error message is there called from POSTAPIRequest class RequestQueueService.showAlert(msg,TestAPIActivity.this); } @Override public void onFetchStart() { //Start showing progressbar or any loader you have RequestQueueService.showProgressDialog(TestAPIActivity.this); } }; } |
Let’s have a look at the output.
Hope you like this article. Share it to inspire us and let us bring cool stuffs like this for you.