在本文中,我将解释如何使用IntentService来使用Restful Webservice。 我们知道我们可以使用Volley lib或简单的Http客户端直接在UI中使用Web服务 ,但是在某些情况下,我们更喜欢在Android Service中使用Web服务。
我们知道,Android Service比Android Activity的寿命更长,并且即使应用UI不再可用,如果我们希望完成任务,我们也应该使用Service 。 例如,我们可以考虑下载情况:假设我们要从远程服务器下载一些信息; 我们可以在用户界面(即活动)中进行操作,但是例如,如果用户移动到另一个应用程序,则下载将被中断。 如果我们希望即使该应用程序不再处于活动状态,也可以继续下载,则可以使用Service。
IntentService说明
当我们要使用Web服务时,我们必须意识到与服务器联系并获得响应所需的时间可能会很长。 即使我们执行此逻辑是一个单独的服务,该服务本身也会在主线程中运行,因此调用活动可能会滞后,等待该服务的响应,而OS可能会杀死它并显示令人讨厌的ANR消息。 我们可以避免在服务内部处理单独的线程时避免此问题,但是Android SDK提供了一个专门类,该类派生自Service类,称为IntentService,其定义为(来自Android API文档):
“ IntentService是
Service
的基类,可按需处理异步请求(表示为Intent
)。 客户端通过startService(Intent)
调用发送请求; 该服务将根据需要启动,使用工作线程依次处理每个Intent,并在工作耗尽时自行停止。这种“工作队列处理器”模式通常用于从应用程序的主线程卸载任务。”
考虑到繁重的工作是在单独的线程中完成的,我们不知道何时完成,并且调用Activity也不知道。 我们将描述如何在服务从远程Web服务检索数据时取回信息。
创建IntentService
例如,我们将使用Yahoo! 财务服务检索股票的当前卖价和买价。 最后,我们将构建一个像这样的应用程序:
第一步是创建服务:
public class QuoteService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
// Here we do the heavy work
}
}
在第4行的onHandleIntent
我们进行了“繁重的工作”,因此我们调用远程Web服务并解析响应。 在这种情况下,我们可以简单地使用XmlPullParser来解析数据:
// 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();
}
然后,在Manifest.xml中定义我们的服务:
<service android:name=".QuoteService" />
活动:Web服务客户端
下一步是创建调用服务的客户端活动。 我们正在使用IntentService,然后调用Activity调用该服务,然后将其忘记。 该活动非常简单,因为用户一旦单击“获取报价!” 按钮,我们使用以下命令调用服务:
startService(service_intent);
无论如何,我们应该考虑两个方面:
- 我们如何将数据传递给服务
- 我们如何从服务中获取数据并在UI中显示信息
为了将数据传递给服务,我们可以创建一个简单的java类,其中包含股票代号和我们希望在获得响应时由服务填充的值。 我们的班级应该是Parcelable班级:
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;
}
}
在第18和25行,我们实现了封送和取消封送我们的类所需的两种方法。
使用ResultReceiver从服务中检索数据
另一个有趣的方面是我们如何从IntentService取回值。 正如我们已经知道的那样,调用活动不会等待结果,因此我们必须寻找另一种方法。 一般来说,有多种方法可以解决此问题,在本文中,我将解释如何使用ResultReceiver 。 我认为这种方法非常简单和优雅。
第一步是创建一个扩展ResultReceiver的类,我们将其称为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);
}
}
这个课很简单。 在第19行,我们定义了调用活动必须实现的接口,以便在数据可用时得到通知。 在此接口中,我们定义了一个Bundle,用于保存检索到的数据。 然后在第14行,我们重写onReceiveResult并调用在先前接口中定义的回调方法。
从客户端的角度(因此我们的Activity),我们只需要实现定义的接口并将QuoteServiceReceiver传递给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;
}
当我们致电服务时:
startService(createCallingIntent(stock));
..和回调方法中:
@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());
}
..在这里,我们使用接收到的数据更新UI。
在使用远程Web服务的服务中:
@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);
}
....
}
- 可用的源代码@ github
翻译自: https://www.javacodegeeks.com/2014/04/consume-webservice-in-android-using-intentservice.html