Consume Webservice in Android using intentService
In this post, I will explain how to consume Restful Webservice using IntentService. We know we can consume a Webservice directly in the UI using for example Volley lib or a simple Http client, but there are some cases when we prefer to consume a Webservice in an Android Service.
We know that Android Service has a “longer” life than an Android Activity and if we want a task is completed even if the app UI is no longer available we should use a Service. We can consider for example the download scenario: let’s suppose we want to download some information from a remote server; we can do it in the UI (i.e Activity) but if the user, for example, moves to another app the download will be interrupted. If we want to be sure that the download continues even if the app isn’t anymore active we can use Service.
IntentService description
When we want to consume a Webservice, we have to be aware that the time required to contact the server and get the response can be quite long. Even if we execute this logic is a separate service, the service itself runs in the main thread, so that the calling activity can lag, waiting for the response from the service, and the OS can kill it showing the annoying ANR message. We can avoid this problem handling a separate thread inside the service, but Android SDK provides a specialized class, derived from the Service class, called IntentService defined as (from Android API docs):
“IntentService is a base class for
Service
s that handle asynchronous requests (expressed asIntent
s) on demand. Clients send requests throughstartService(Intent)
calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.This “work queue processor” pattern is commonly used to offload tasks from an application’s main thread.”
Considering that the heavy work is made in a separate thread we don’t know when it will finish and the calling Activity is unaware of it. We will describe how to get back the information as the service retrieved data from the remote Webservice.
Creating the IntentService
As example we will use Yahoo! Finance Service to retrieve the current Ask and Bid value for a Stock. At the end we will build an app like this:
The first step is creating a service:
public class QuoteService extends IntentService { @Override protected void onHandleIntent(Intent intent) { // Here we do the heavy work } }
At line 4, in onHandleIntent
we do the “heavy work”, so we call the remote Webservice and parse the response. In this case we can simply use XmlPullParser to parse the data:
// Here we retrieve the stock quote using Yahoo! Finance Log.d("Srv", "Get stock"); String url = YAHOO_FINANCE_URL.replaceAll("#sym#", stock.getSymbol()); try { HttpURLConnection con = (HttpURLConnection) ( new URL(url)).openConnection(); con.setRequestMethod("GET"); con.connect(); InputStream is = con.getInputStream(); // Start parsing XML XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); parser.setInput(is, null); int event = parser.getEventType(); String tagName = null; String currentTag = null; Stock stockResult = new Stock(); while (event != XmlPullParser.END_DOCUMENT) { tagName = parser.getName(); Log.d("Srv", "Tag:" + tagName); if (event == XmlPullParser.START_TAG) { currentTag = tagName; } else if (event == XmlPullParser.TEXT) { if ("ASK".equalsIgnoreCase(currentTag)) // else if ("BID".equalsIgnoreCase(currentTag)) { // } } event = parser.next(); } } catch (Exception e) { e.printStackTrace(); }
Then we define our service in the Manifest.xml:
<service android:name=".QuoteService" />
Activity: Webservice client
The next step is creating the client activity that invokes the service. We are using an IntentService then the calling Activity calls the service and then forget it. The activity is quite trivial, because as soon as the user clicks “Get quote!” button we invoke the service using:
startService(service_intent);
Anyway, there are two aspects we should consider:
- How we pass the data to the service
- How we get the data back from the service and show the information in UI
To pass data to the service we can create a simple java class that holds the stock symbol and the values we want to be filled by the service as we get the response. Our class should be a Parcelable class:
public class Stock implements Parcelable { private String symbol; private double askValue; private double bidValue; public Stock() {} public Stock(String symbol, double askValue, double bidValue) { this.symbol = symbol; this.askValue = askValue; this.bidValue = bidValue; } // get and set method @Override public void writeToParcel(Parcel dest, int flags) { // We write the stock information in the parcel dest.writeString(symbol); dest.writeDouble(askValue); dest.writeDouble(bidValue); } public static final Creator<Stock> CREATOR = new Creator<Stock>() { @Override public Stock createFromParcel(Parcel source) { Stock stock = new Stock(); stock.setSymbol(source.readString()); stock.setAskValue(source.readDouble()); stock.setBidValue(source.readDouble()); return stock; } @Override public Stock[] newArray(int size) { return new Stock[0]; } }; @Override public int describeContents() { return 0; } }
At line 18 and 25, we implement the two methods required to marshal and unmarshal our class.
Retrieve data from service using ResultReceiver
Another interesting aspect is how we can get the values back from the IntentService. As we, already, know the calling activity doesn’t wait for the result, so we have to find another way. Generally speaking there are different ways to solve this problem, in this post I will explain how to use ResultReceiver. This method is quite simple and elegant in my opinion.
The first step is creating a class that extends ResultReceiver, that we call QuoteServiceReceiver
:
public class QuoteServiceReceiver extends ResultReceiver { private Listener listener; public QuoteServiceReceiver(Handler handler) { super(handler); } public void setListener(Listener listener) { this.listener = listener; } @Override protected void onReceiveResult(int resultCode, Bundle resultData) { if (listener != null) listener.onReceiveResult(resultCode, resultData); } public static interface Listener { void onReceiveResult(int resultCode, Bundle resultData); } }
This class is very simple. At line 19 we define an interface that the calling activity has to implement to get notified when the data isavailable. In this interface we define a Bundle that holds the data retrieved. Then at line 14 we override the onReceiveResult and call our callback method defined in the previous interface.
From the client point of view (so our Activity) we simply have to implements the interface defined and pass the QuoteServiceReceiver to the IntentService:
private Intent createCallingIntent(Stock stock) { Intent i = new Intent(this, QuoteService.class); QuoteServiceReceiver receiver = new QuoteServiceReceiver(new Handler()); receiver.setListener(this); i.putExtra("rec", receiver); i.putExtra("stock", stock); return i; }
and when we call the service:
startService(createCallingIntent(stock));
..and in the callback method:
@Override public void onReceiveResult(int resultCode, Bundle resultData) { Stock stock = resultData.getParcelable("stock"); Log.d("Srv", "Stock ["+stock+"]"); askValue.setText("" + stock.getAskValue()); bidValue.setText("" + stock.getBidValue()); }
..and here we update the UI, with the data received.
In the service that consumes the remote Webservice:
@Override protected void onHandleIntent(Intent intent) { Stock stock = intent.getParcelableExtra("stock"); final ResultReceiver rec = (ResultReceiver) intent.getParcelableExtra("rec"); .... // When data is ready if ("BID".equalsIgnoreCase(currentTag)) { stockResult.setBidValue(Double.parseDouble(parser.getText())); Bundle b = new Bundle(); b.putParcelable("stock", stockResult); rec.send(0, b); } .... }
- Source code available @ github
Reference: | Consume Webservice in Android using intentService from our JCG partner Francesco Azzola at the Surviving w/ Android blog. |
Hello,
I have gone through Bluetooth connection code by Katerina Zamani , and I am very much impressed with its precised explanation and now I am facing problem with its further part I.e connecting and communicating with other remote device..n I also refferd d “Bluetooth chat” by android SDK but I m unable to understand it..
So pleas u people post d rest part of Bluetooth activity, n I m waiting for ur reply….
thnku,