您的位置:首页 > 理论基础 > 计算机网络

Android建立网络连接,利用JSON数据获取百度图片搜索结果及GSON的简单使用

2017-02-14 10:38 1021 查看

1、建立网络连接的基本方式

Android中建立网络连接最主要的方式是利用HttpURLConnection,示例如下:

public class HttpUtil {
public static byte[] getUrlBytes(String urlSpec) throws IOException {
//将地址信息封装成URL
URL url = new URL(urlSpec);

//创建指向URL链接的HttpURLConnection对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

try {
//保存返回结果
ByteArrayOutputStream out = new ByteArrayOutputStream();

//真正开始访问指定地址
InputStream in = connection.getInputStream();

//HTTP_OK才是成功建立链接
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new IOException(connection.getResponseMessage() +
": with " +
urlSpec);
}

int bytesRead;
byte[] buffer = new byte[1024];

//不断从网络下载数据,并保存到out中
while ((bytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
out.close();

//下载完毕后,将结果转化成byte array
return out.toByteArray();
} finally {
//断开连接
connection.disconnect();
}
}

public static String getUrlString(String urlSpec) throws IOException{
//将byteArray转化为String
return new String(getUrlBytes(urlSpec));
}
}


2、下载百度图片对应的JSON数据

我们进入百度图片,例如“微距摄影”这个类别,其http地址如下:

http://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&sf=2&fmq=1480332039000_R_D&pv=&ic=0&nc=1&z=&se=&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E5%BE%AE%E8%B7%9D%E6%91%84%E5%BD%B1


其中:

http://image.baidu.com/search/index?


可以看作基础的http地址,后续的tn、ipn、ct等均是额外的访问参数。

例如:word后就是访问的类别,对应中文的“微距摄影”。

现在,基于这个地址,我们来看看如何获取百度图片搜索得到的结果:

public List<GalleryItem> fetchItems() {
..............
try {
//解析基础地址
String url = Uri.parse("http://image.baidu.com/search/index?")
.buildUpon()
//增加参数,这里指定结果以json格式返回
.appendQueryParameter("tn", "resultjson")
//指定类别为微距摄影
.appendQueryParameter("word", "微距摄影")
.build().toString();

Log.d("ZJTest", url);

String jsonString = HttpUtil.getUrlString(url);

Log.d("ZJTest", jsonString);
............
} catch (JSONException | IOException e) {
e.printStackTrace();
}

return items;
}


我们增加了log信息,看看生成的url:

02-14 09:59:49.154 32471-32506/stark.a.is.zhang.photogallery D/ZJTest: http://image.baidu.com/search/index?tn=resultjson&word=%E5%BE%AE%E8%B7%9D%E6%91%84%E5%BD%B1[/code] 
可以看到,url的信息结构与前面的http地址相似。

这里我们只使用了tn、word参数,还可以按照同样的方式,增加其它的要求。

我们再看看返回的结果,为了方便观察,我们修改一下返回结果的格式,增加一些回车和空格:

02-14 09:59:49.354 32471-32506/stark.a.is.zhang.photogallery D/ZJTest:
{
"queryEnc":"%E5%BE%AE%E8%B7%9D%E6%91%84%E5%BD%B1",
"queryExt":"微距摄影",
"listNum":1965,
"displayNum":208527,
"gsm":"1000000001e",
"bdSearchTime":"",
"isNeedAsyncRequest":0,
"bdIsClustered":"1",
"data":[
{
"thumbURL":"http://f.hiphotos.baidu.com/image/h%3D300/sign=e444f9f5a0014c08063b2ea53a7a025b/359b033b5bb5c9ea18ae77bfdc39b6003af3b308.jpg",
"middleURL":"http://f.hiphotos.baidu.com/image/h%3D200/sign=1250a848b199a90124355c362d940a58/359b033b5bb5c9ea18ae77bfdc39b6003af3b308.jpg",    "largeTnImageUrl":"",
"hasLarge" :0,    "hoverURL":"http://f.hiphotos.baidu.com/image/h%3D300/sign=e444f9f5a0014c08063b2ea53a7a025b/359b033b5bb5c9ea18ae77bfdc39b6003af3b308.jpg",    "pageNum":0,
"objURL":"http://imgsrc.baidu.com/forum/pic/item/a8ec8a13632762d006deaa12a0ec08fa503dc6bf.jpg",    "fromURL":"http://tieba.baidu.com/p/1690102901",
"fromURLHost":"tieba.baidu.com",
"currentIndex":"",
"width":900,
"height":597,
"type":"jpg",
"filesize":"",
"bdSrcType":"-1",
"di":"0",
"adid":"0",
"is":"",
"simid_info":null,
"face_info":null,
"xiangshi_info":null,
"adPicId":"0",
"pi":"0",
"bdSetImgNum":0,
"bdImgnewsDate":"1970-01-01 08:00",
"fromPageTitle":"微距摄影",
"fromPageTitleEnc":"微距摄影",
"bdSourceName":"",
"bdFromPageTitlePrefix":"",
"token":""
},
{
"thumbURL":"http://img4.imgtn.bdimg.com/it/u=1193418232,3244632658&fm=23&gp=0.jpg",
"middleURL":"http://img4.imgtn.bdimg.com/it/u=1193418232,3244632658&fm=21&gp=0.jpg",
"largeTnImageUrl":"",
"hasLarge" :0,
"hoverURL":"http://img4.imgtn.bdimg.com/it/u=1193418232,3244632658&fm=23&gp=0.jpg",
"pageNum":1,
"objURL":"http://img4.duitang.com/uploads/item/201408/30/20140830185456_Eijik.jpeg",    "fromURL":"http://www.duitang.com/people/mblog/196468797/detail/",
"fromURLHost":"www.duitang.com",
"currentIndex":"",
"width":1200,
"height":800,
"type":"jpeg",
"filesize":"",
"bdSrcType":"0",
"di":"119581535480",
"adid":"0",
"is":"0,0",
"simid_info":null,
"face_info":null,
"xiangshi_info":null,
"adPicId":"0",
"pi":"0",
"bdSetImgNum":0,
"bdImgnewsDate":"1970-01-01 08:00",
"fromPageTitle":"<strong>微距摄影<\/strong>照片",
"fromPageTitleEnc":"微距摄影照片",
"bdSourceName":"",
"bdFromPageTitlePrefix":"",
"token":""
},
.........................


从上面的返回结果可以看出,JSON对象中的data域是一个数组,其中的每一项为实际的图片数据。

例如,我们可以获取data中的objURL,然后根据此地址获得实际的图片。

我们看看这部分完整的示例代码:

public class ImageFetcher {
public List<GalleryItem> fetchItems() {
//我们在GalleryItem中存储解析出的JSON数据
List<GalleryItem> items = new ArrayList<>();

try {
String url = Uri.parse("http://image.baidu.com/search/index?")
.buildUpon()
.appendQueryParameter("tn", "resultjson")
.appendQueryParameter("word", "微距摄影")
.build().toString();

String jsonString = HttpUtil.getUrlString(url);

//将得到的返回结果分装到JSONObject中
JSONObject jsonBody = new JSONObject(jsonString);

//然后,解析JSONObject
parseItems(items, jsonBody);
} catch (JSONException | IOException e) {
e.printStackTrace();
}

return items;
}

private void parseItems(List<GalleryItem> items, JSONObject jsonBody)
throws IOException, JSONException {
//根据返回的JSON数据格式,我们知道“data”域对应JSONArray
JSONArray dataArray = jsonBody.getJSONArray("data");

for (int i = 0; i < dataArray.length(); ++i) {
JSONObject dataObject = dataArray.getJSONObject(i);

GalleryItem item = new GalleryItem();
//保存JSONArray中每一项的objURL,利用该Url就可以获取实际的数据
item.setUrl(dataObject.getString("objURL"));

items.add(item);
}
}
}


获取URL后的下载及解析图片的内容,在此篇博客中就不再进一步叙述了。

3、补充

上面获取JSON数据的方法实际上是不得已的“野路子”,如果百度图片修改了JSON结果的格式,那么代码也要随之修改。

一般正常情况下,应该使用云服务提供的API,然后按照API定义的JSON格式处理返回结果,例如使用Google、比应等提供的API接口。

不过为了使用云服务,必须申请对应的Api key,这就涉及到一些申请过程和收费了,具体的可以参考这些服务的说明文档。

使用云服务的好处在于:接口稳定,而且有一些便捷的方法可以使用,例如flickr提供的接口(这段代码的主要部分引用于Android权威指南):

public void fetchItems() {
try {
String url = Uri.parse("https://api.flickr.com/services/rest/")
.buildUpon()
//这就是云服务便利的地方,提供了方法给客户端使用
.appendQueryParameter("method", "flickr.photos.getRecent")
//这里需要填写申请到的api_key
.appendQueryParameter("api_key", API_KEY)
.appendQueryParameter("format", "json")
...........
.build().toString();

String jsonString = HttpUtil.getUrlString(url);

//得到结果后,按照云服务约定的方式,解析JSON对象,方法与上面的代码类似
....................
} catch(IOException ioe) {
............
}
}


4、使用GSON来简化json数据的解析

对于固定格式的json数据而言,每次都用上述方式,分析数据格式然后逐步解析比较繁琐。

幸好有现成的第三方库Gson可以使用。

Gson的使用比较简单,主要是按照Json的格式定义序列化的Bean对象。

以上面百度图片返回的结果为例:

public class Response {
//每个成员与Json中的key值一致
private String queryEnc;
private String queryExt;
private String listNum;
private String displayNum;
private String gsm;
private String bdSearchTime;
private String isNeedAsyncRequest;
private String bdIsClustered;
//保存Json中的data数组
private List<Data> data;

public String getQueryEnc() {
return queryEnc;
}

public void setQueryEnc(String queryEnc) {
this.queryEnc = queryEnc;
}

public String getQueryExt() {
return queryExt;
}

public void setQueryExt(String queryExt) {
this.queryExt = queryExt;
}

public String getListNum() {
return listNum;
}

public void setListNum(String listNum) {
this.listNum = listNum;
}

public String getDisplayNum() {
return displayNum;
}

public void setDisplayNum(String displayNum) {
this.displayNum = displayNum;
}

public String getGsm() {
return gsm;
}

public void setGsm(String gsm) {
this.gsm = gsm;
}

public String getBdSearchTime() {
return bdSearchTime;
}

public void setBdSearchTime(String bdSearchTime) {
this.bdSearchTime = bdSearchTime;
}

public String getIsNeedAsyncRequest() {
return isNeedAsyncRequest;
}

public void setIsNeedAsyncRequest(String isNeedAsyncRequest) {
this.isNeedAsyncRequest = isNeedAsyncRequest;
}

public String getBdIsClustered() {
return bdIsClustered;
}

public void setBdIsClustered(String bdIsClustered) {
this.bdIsClustered = bdIsClustered;
}

public List<Data> getData() {
return data;
}

public void setData(List<Data> data) {
this.data = data;
}
}


同样,再定义一个Data对象:

public class Data {
//同样,Data中的成员与Json内data的key值一致
private String thumbURL;
private String middleURL;
private String hasLarge;
private String objURL;
private String fromURLHost;
private String currentIndex;
private String width;
private String height;
private String type;
private String filesize;
private String bdSrcType;
private String di;
private String adid;
private String is;
private String simid_info;
private String face_info;
private String xiangshi_ifno;
private String adPicId;
private String pi;
private String bdSetImgNum;
private String bdImgnewsDate;
private String fromPageTitle;
private String fromPageTitleEnc;
private String bdSourceName;
private String bdFromPageTitlePrefix;
private String token;

public String getThumbURL() {
return thumbURL;
}

public void setThumbURL(String thumbURL) {
this.thumbURL = thumbURL;
}

public String getMiddleURL() {
return middleURL;
}

public void setMiddleURL(String middleURL) {
this.middleURL = middleURL;
}

public String getHasLarge() {
return hasLarge;
}

public void setHasLarge(String hasLarge) {
this.hasLarge = hasLarge;
}

public String getObjURL() {
return objURL;
}

public void setObjURL(String objURL) {
this.objURL = objURL;
}

public String getFromURLHost() {
return fromURLHost;
}

public void setFromURLHost(String fromURLHost) {
this.fromURLHost = fromURLHost;
}

public String getCurrentIndex() {
return currentIndex;
}

public void setCurrentIndex(String currentIndex) {
this.currentIndex = currentIndex;
}

public String getWidth() {
return width;
}

public void setWidth(String width) {
this.width = width;
}

public String getHeight() {
return height;
}

public void setHeight(String height) {
this.height = height;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

public String getFilesize() {
return filesize;
}

public void setFilesize(String filesize) {
this.filesize = filesize;
}

public String getBdSrcType() {
return bdSrcType;
}

public void setBdSrcType(String bdSrcType) {
this.bdSrcType = bdSrcType;
}

public String getDi() {
return di;
}

public void setDi(String di) {
this.di = di;
}

public String getAdid() {
return adid;
}

public void setAdid(String adid) {
this.adid = adid;
}

public String getIs() {
return is;
}

public void setIs(String is) {
this.is = is;
}

public String getSimid_info() {
return simid_info;
}

public void setSimid_info(String simid_info) {
this.simid_info = simid_info;
}

public String getFace_info() {
return face_info;
}

public void setFace_info(String face_info) {
this.face_info = face_info;
}

public String getXiangshi_ifno() {
return xiangshi_ifno;
}

public void setXiangshi_ifno(String xiangshi_ifno) {
this.xiangshi_ifno = xiangshi_ifno;
}

public String getAdPicId() {
return adPicId;
}

public void setAdPicId(String adPicId) {
this.adPicId = adPicId;
}

public String getPi() {
return pi;
}

public void setPi(String pi) {
this.pi = pi;
}

public String getBdSetImgNum() {
return bdSetImgNum;
}

public void setBdSetImgNum(String bdSetImgNum) {
this.bdSetImgNum = bdSetImgNum;
}

public String getBdImgnewsDate() {
return bdImgnewsDate;
}

public void setBdImgnewsDate(String bdImgnewsDate) {
this.bdImgnewsDate = bdImgnewsDate;
}

public String getFromPageTitle() {
return fromPageTitle;
}

public void setFromPageTitle(String fromPageTitle) {
this.fromPageTitle = fromPageTitle;
}

public String getFromPageTitleEnc() {
return fromPageTitleEnc;
}

public void setFromPageTitleEnc(String fromPageTitleEnc) {
this.fromPageTitleEnc = fromPageTitleEnc;
}

public String getBdSourceName() {
return bdSourceName;
}

public void setBdSourceName(String bdSourceName) {
this.bdSourceName = bdSourceName;
}

public String getBdFromPageTitlePrefix() {
return bdFromPageTitlePrefix;
}

public void setBdFromPageTitlePrefix(String bdFromPageTitlePrefix) {
this.bdFromPageTitlePrefix = bdFromPageTitlePrefix;
}

public String getToken() {
return token;
}

public void setToken(String token) {
this.token = token;
}
}


Bean对象定义完毕后,就可以使用Gson了,示例如下:

public class ImageFetcher {
public List<GalleryItem> fetchItems() {
List<GalleryItem> items = new ArrayList<>();

try {
String url = Uri.parse("http://image.baidu.com/search/index?")
.buildUpon()
.appendQueryParameter("tn", "resultjson")
.appendQueryParameter("word", "微距摄影")
.build().toString();

String jsonString = HttpUtil.getUrlString(url);

//创建Gson
Gson gson = new Gson();

//Gson按照Response中的定义,将字符串解析成Response对象
Response response = gson.fromJson(jsonString, Response.class);
parseItems(items, response);
} catch (JSONException | IOException e) {
e.printStackTrace();
}

return items;
}

private void parseItems(List<GalleryItem> items, Response response)
throws IOException, JSONException {
//然后就可以直接调用对象的接口得到需要的数据了
List<Data> dataList = response.getData();
for (Data data : dataList) {
GalleryItem item = new GalleryItem();
item.setUrl(data.getObjURL());

items.add(item);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: