【Android前端】Bing每日图片列表应用制作记录——3.获取网络数据(上)

来源:互联网 发布:如何更改数据库所有者 编辑:程序博客网 时间:2024/05/22 17:25

这次也是因为一些变故拖了很久才更新,但是生活总是要继续。


第三篇:获取网络数据(上)

上次说过我们的预期效果是从网络加载数据,那么怎么对现有代码进行改造呢?
首先我们回到DataResource获取数据的函数getData()里:
public List<Map<String,Object>> getData()    {        for(int i=1;i<=5;i++){            map=new HashMap<>();            map.put("pic",R.mipmap.test);            map.put("text","这里应该是内容");            map.put("time","这里应该有时间");            list.add(map);        }        return list;    }
可以看到现在返回的List中的内容是我们加入的固定内容,那么应该修改的就是这部分了。那么下一个问题是:数据从哪里来?

第一部分:API

好了我们看看标题——这次用的是Bing每日图片的API,Url如下:http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=zh-CN。
试试直接在浏览器里访问:

得到的这串字符就是我们的目标了,这是JSON字符串,解释的话这里贴一段百科:
JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

总的来说,JSON字符串可以用文本来“储和表达数据”,这种格式目前也是非常常见的,具体的大家可以看一看这一篇博文。

回到API本体,不难看出,字符串中的startdate,url和copyright三个变量的数据就是我们需要的,我们的目标也就是把这三个变量的值放进HashMap再添加到List最终传给Adapter以展示出来。

PS:关于这个API稍微说一说参,n是数据条数,mkt是地区,但是很不幸的是这个API存在限制,一次最多返回8个image成员,当然已经够我们练习用了。

第二部分:HttpUrlConnection

Android中发送http网络请求是很常见的,在Android API Level 9(Android 2.2)之前使用的是DefaultHttpClient类发送http请求。DefaultHttpClient是Apache用于发送http请求的客户端,API支持强大性能完善,但是由于其太过复杂,Android团队在保持向后兼容的情况下,很难对DefaultHttpClient进行增强。为此Android团队自己实现了一个发送http请求的客户端类——–HttpURLConnection。相比于原来的DefaultHttpClient,HttpURLConnection比较轻量级,虽然功能没有DefaultHttpClient那么强大,但是能够满足大部分的需求,所以Android推荐使用HttpURLConnection代替DefaultHttpClient,并不强制使用HttpURLConnection。但从Android API Level 23(Android 6.0)开始,不能再在Android中使用DefaultHttpClient,强制使用HttpURLConnection。

这次我们就用HttpUrlConnection来实现请求网络数据,Http请求分为GET请求和POST请求,因为这次的需求很简单,所以只用get请求就可以了。
使用前别忘了在AndroidManifest.xml中申请网络使用权限:
<uses-permission android:name="android.permission.INTERNET" />
一个完整的http请求需要经历两个过程:客户端发送请求到服务器,然后服务器将结果返回给客户端,来直接上代码:
try{        String path = "http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=5&mkt=zh-CN";        URL url = new URL(path);        HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();        urlConn.setConnectTimeout(5000);        urlConn.connect();        if (urlConn.getResponseCode() == 200) {            //处理数据            Log.i(TAG, "请求成功");        } else {            Log.i(TAG, "请求失败");        }        urlConn.disconnect();    }catch (Exception e){        e.printStackTrace();    }
如上面一段代码所示,我们建立了一个新的HttpURLConnection对象,并用它连接了API相关的url,最后返回连接结果。细看代码,而if判断中的urlConn.getResponseCode() == 200正是代表连接成功(大家应该都见过404吧,关于返回码具体可以参照这一篇)。

这一段代码已经可以搭建一个简单的http请求了,但是很明显处理数据的部分我们还没有做,不过实现起来也很简单:HttpURLConnection类自带getInputStream()函数。但是这样并不够,因为我们还需要把InputStream格式的数据变成可处理的String类型,所以我们额外实现一个函数readStream():
private String readStream(InputStream inputStream) throws IOException{        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();        byte[] buffer = new byte[1024];        int len;        while((len=inputStream.read(buffer))!=-1){            outputStream.write(buffer,0,len);            outputStream.flush();        }        outputStream.close();        inputStream.close();        return  outputStream.toString();    }
简单来讲就是先将输入流变成ByteArrayOutputStream,再通过toString()方法得到String类型的结果,顺带一提get请求方式最多也只能得到2048字节大小的数据,所以不用担心。当然了还得在if段中调用:
if (urlConn.getResponseCode() == 200) {                String data = readStream(urlConn.getInputStream());                Log.i(TAG, "请求成功");                Log.i(TAG, data);            } else {                Log.i(TAG, "请求失败");            }
这样简单的请求数据过程算是实现了,但是还有一个更大的问题:
这个部分放在哪?

第三部分:AsyncTask

网络请求是非常忌讳放在主线程运行的,不仅会堵塞进程,造成的界面僵死更会让用户十分恼火,这里用的就是一个很简单的办法:AsyncTask。AsyncTask,也就是异步任务,是Android提供的轻量级的异步类,我们可以直接继承AsyncTask以在类中实现异步操作。

实际使用中我们最少要重写以下这两个方法:doInBackground(Params…) 后台执行,比较耗时的操作都可以放在这里,不过注意这里不能直接操作UI,此外在执行过程中可以调用publicProgress(Progress…)来更新任务的进度;而onPostExecute(Result)  相当于Handler 处理UI的方式,在这里面可以使用在doInBackground 得到的结果处理操作UI。 此方法在主线程执行,任务执行的结果作为此方法的参数返回。
还是直接用代码来说明吧,我们新建立一个DataAsyncTask类继承自AsyncTask:
package com.xugino.bingpicanother;import android.os.AsyncTask;import android.util.Log;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.ArrayList;import java.util.List;import java.util.Map;import static android.content.ContentValues.TAG;class DataAsyncTask extends AsyncTask<Integer,Void,Void> {    DataAsyncTask(){        super();    }    @Override    protected Void doInBackground(Integer... param) {        try{            String path = "http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=5&mkt=zh-CN";            URL url = new URL(path);            HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();            urlConn.setConnectTimeout(5000);            urlConn.connect();            if (urlConn.getResponseCode() == 200) {                String data = readStream(urlConn.getInputStream());                Log.i(TAG, "请求成功");                Log.i(TAG, data);            } else {                Log.i(TAG, "请求失败");            }            urlConn.disconnect();        }catch (Exception e){            e.printStackTrace();        }        return null;    }    private String readStream(InputStream inputStream) throws IOException{        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();        byte[] buffer = new byte[1024];        int len;        while((len=inputStream.read(buffer))!=-1){            outputStream.write(buffer,0,len);            outputStream.flush();        }        outputStream.close();        inputStream.close();        return  outputStream.toString();    }}


然后在getData()中调用:
package com.xugino.bingpicanother;import java.util.ArrayList;import java.util.List;import java.util.Map;public class DataResource {    private List<Map<String,Object>> list;    private DataAsyncTask myTask;    public DataResource(){        list=new ArrayList<>();    }    public List<Map<String,Object>> getData()    {        try{            myTask = new DataAsyncTask();            myTask.execute(0);        }catch (Exception e){            e.printStackTrace();        }        return list;    }}
然后运行看看:


毫无疑问这部分很成功,但是你再看看我们的App界面——一片空白,我们现在得到的只是json字符串而已,真正要把它转换成真正的数据显示出来还要经过更多的处理。

下一篇文章我们会使用Google家的gson来解析json字符串,学会使用这些外部依赖也是入门的一部分。
阅读全文
0 0
原创粉丝点击