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

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

可以看到,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);
        }
    }
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以回答您的问题。以下是使用Kotlin语言在Android使用OkHttp获取JSON数据并解析的代码示例: 首先,您需要在您的项目中添加OkHttp库的依赖项。在您的app的build.gradle文件中添加以下代码: ```groovy dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.0' } ``` 接下来,您可以使用以下代码获取JSON数据: ```kotlin val client = OkHttpClient() val request = Request.Builder() .url("https://example.com/data.json") .build() client.newCall(request).enqueue(object : Callback { override fun onFailure(call: Call, e: IOException) { // 处理失败情况 } override fun onResponse(call: Call, response: Response) { val responseData = response.body()?.string() // 处理响应数据 } }) ``` 在上面的代码中,我们使用OkHttp创建了一个新的HTTP请求并将其排队以异步执行。当响应返回时,我们将调用回调方法以处理响应。 现在,我们需要解析JSON数据。您可以使用Kotlin内置的JSON解析器或Gson等第三方库。以下是使用Kotlin自带的解析器的代码示例: ```kotlin // 假设我们的JSON数据如下: // { // "name": "John Smith", // "age": 30, // "avatarUrl": "https://example.com/avatar.jpg" // } data class User(val name: String, val age: Int, val avatarUrl: String) val user = Json.decodeFromString<User>(responseData) val avatarUrl = user.avatarUrl // 使用Glide库加载图片 Glide.with(context) .load(avatarUrl) .into(imageView) ``` 在上面的代码中,我们首先定义了一个名为User的数据类,该类具有与JSON数据结构相匹配的属性。然后,我们使用Kotlin的JSON解析器从JSON字符串中解析出User对象。最后,我们使用Glide库加载用户的头像图片。 希望这可以帮助您开始使用Kotlin和OkHttp获取和解析JSON数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值