这是“ Android完整应用程序教程”系列的第二部分。 完整的应用程序旨在提供一种通过互联网搜索表演电影/演员的简便方法。 在本系列的第一部分( “主要活动UI” )中,我们创建了Eclipse项目并为应用程序的主要活动设置了基本界面。 在这一部分中,我们将了解如何使用外部HTTP API,以及如何将API的搜索功能集成到我们的应用程序中。
对于电影和演员查询,我们将使用TMDb API 。 从官方网站:
“对于想将电影和演员数据以及海报或电影爱好者集成在一起的任何开发人员,TMDb API都是强大的资源。 所有API方法都支持XML,YAML和JSON。”
与大多数可用的API一样,您将需要一个有效的密钥才能使用该API。 第一步是在TMDb的“注册”页面上创建一个免费帐户。 注册后,登录您的帐户并找到用于生成API密钥的链接。
可用的API方法的列表可以在TMDb API文档页面上找到,最重要的方法如下:
- Movie.search :提供搜索电影的最简单,最快的方法。
- Person.search :用于搜索演员,女演员或制作成员。
对于电影搜索,URL示例如下:
http://api.themoviedb.org/2.1/Movie.search/zh/xml/APIKEY/Transformers
对于人物搜索,示例网址如下:
http://api.themoviedb.org/2.1/Person.search/en/xml/APIKEY/Brad+Pitt
(其中APIKEY必须替换为有效的API密钥)
如您所见,该API非常简单易用。 它仅涉及在特定URL上执行HTTP GET请求,然后将响应检索为预定义的格式。
接下来,我们将看到如何利用Android的网络功能来使用API并提供所提供数据的表示形式。 请注意,我们将使用XML格式进行响应,但这将在下一个教程中进行展示。
为了在Android环境中处理HTTP请求/响应,可以使用java.net包中的标准类。 因此,诸如URL , URLConnection , HttpURLConnection等之类的所有类都可以以已知方式使用。 但是,您可以通过使用Apache HTTP Client库来避免处理底层细节。 该库基于著名的Apache Commons HTTP Client框架。
让我们开始使用代码。 我们将创建一个名为“ HttpRetriever”的类,该类将负责执行所有HTTP请求,并将以文本格式和流(用于图像处理)的形式返回响应。 此类的代码如下:
package com.javacodegeeks.android.apps.moviesearchapp.services;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import com.javacodegeeks.android.apps.moviesearchapp.io.FlushedInputStream;
import com.javacodegeeks.android.apps.moviesearchapp.util.Utils;
public class HttpRetriever {
private DefaultHttpClient client = new DefaultHttpClient();
public String retrieve(String url) {
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
if (getResponseEntity != null) {
return EntityUtils.toString(getResponseEntity);
}
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
public InputStream retrieveStream(String url) {
HttpGet getRequest = new HttpGet(url);
try {
HttpResponse getResponse = client.execute(getRequest);
final int statusCode = getResponse.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(getClass().getSimpleName(), "Error " + statusCode + " for URL " + url);
return null;
}
HttpEntity getResponseEntity = getResponse.getEntity();
return getResponseEntity.getContent();
}
catch (IOException e) {
getRequest.abort();
Log.w(getClass().getSimpleName(), "Error for URL " + url, e);
}
return null;
}
public Bitmap retrieveBitmap(String url) throws Exception {
InputStream inputStream = null;
try {
inputStream = this.retrieveStream(url);
final Bitmap bitmap = BitmapFactory.decodeStream(new FlushedInputStream(inputStream));
return bitmap;
}
finally {
Utils.closeStreamQuietly(inputStream);
}
}
}
对于HTTP请求的实际执行,我们使用DefaultHttpClient类的实例,顾名思义,该实例是HTTP客户端的默认实现,即HttpClient接口的默认实现。 我们还使用HttpGet类(以表示GET请求),并为其构造函数参数提供目标URL。 HTTP客户端执行请求,并提供HttpResponse对象,该对象包含实际的服务器响应以及任何其他信息。 例如,我们可以检索响应状态代码,并将其与成功HTTP请求的代码( HttpStatus.SC_OK )进行比较。 对于成功的请求,我们将引用随附的HttpEntity对象,并从中访问实际的响应数据。 对于文本响应,我们使用EntityUtils类的静态toString方法将实体转换为String。 如果我们希望以字节流的形式检索数据(例如,为了处理二进制下载),请使用HttpEntity类的getContent方法,该方法将创建实体的新InputStream对象。
请注意,还有第三种方法可以直接返回Bitmap对象。 这将对教程系列的后续部分有所帮助,我们将从互联网上下载图像。 在该方法中,我们像往常一样执行GET请求并检索InputStream 。 然后,我们使用BitmapFactory类的encodeStream方法创建一个新的Bitmap对象。 请注意,我们不直接提供下载的InputStream ,而是首先用FlushedInputStream类包装它。 如官方Android开发人员博客文章所述,先前版本的encodeStream方法中存在一个错误,当通过缓慢的连接下载图像时,可能会导致问题。 自定义类FlushedInputStream扩展了FilterInputStream ,以解决此问题。 该类的代码如下:
package com.javacodegeeks.android.apps.moviesearchapp.io;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int b = read();
if (b < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
这样可以确保skip()实际上跳过提供的字节数,除非我们到达文件末尾。 最后,我们使用自定义Utils类的closeStreamQuietly方法来处理关闭InputStream时可能发生的异常。 代码如下:
package com.javacodegeeks.android.apps.moviesearchapp.util;
import java.io.IOException;
import java.io.InputStream;
public class Utils {
public static void closeStreamQuietly(InputStream inputStream) {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException e) {
// ignore exception
}
}
}
最后,为了能够执行HTTP请求,必须授予相应的权限。 因此,将android.permission.INTERNET添加到项目的AndroidManifest.xml文件中,该文件现在如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.javacodegeeks.android.apps.moviesearchapp"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".MovieSearchAppActivity"
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>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>
因此,我们准备了用于执行HTTP GET请求的基础结构。 在以下教程中,我们将使用它来检索满足应用程序需求的XML数据和图像。 您可以在此处下载到目前为止创建的Eclipse项目。
- “ Android完整应用程序教程”系列
- Android文字转语音应用
- 带有Yahoo API的Android反向地理编码– PlaceFinder
- Android基于位置的服务应用程序– GPS位置
- 使用VirtualBox在PC上安装Android OS
- 拥抱Android的强大功能:快速概述
翻译自: https://www.javacodegeeks.com/2010/10/android-full-app-part-2-using-http-api.html