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

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

2017-09-16 16:54 681 查看

第四篇:获取网络数据(下)

上次我们成功获得了来自网络的Json字符串,但是显然还需要对json字符串进行处理,使其变成我们需要的url和文字说明。

而GSON恰好就是我们需要的工具。GSON是Google提供的用来在Java对象和JSON数据之间进行映射的Java类库,它可以将一个Json字符转成一个Java对象,或者将一个Java对象转化为Json字符串。 它具有以下几个特点:快速、高效 ;代码量少、简洁 ;面向对象;数据传递和解析方便。
正好借着这个机会我们也可以学习外部库的使用。

第一部分:GSON

为了使用GSON库,首先在app/build.gradle中添加依赖,这也是使用其他外部库的第一步:
dependencies {
...
compile 'com.google.code.gson:gson:2.6.2'
}


如果你使用的是Eclipse,那么请去Google官网下载相应的jar包,效果完全一样。

然后GSON是基于事件驱动的,根据所需要取的数据通过建立一个对应于JSON数据的JavaBean类才能解析出所需JSON数据,也就是为GSON提供处理后的格式标准。关于JavaBean类我推荐想了解的看一下这一篇博文,说得很简单易懂。不过使用AS的话并不需要人工编写Bean类,因为已经有非常懒人的插件GsonFormat了,下面讲一讲怎么用:

首先在菜单里找到File->Settings..->Plugins–>Browse repositores..,然后搜索GsonFormat



然后点击右边的Install安装,完成后重启AS,这样这个插件就可以用了。

实际使用时我们需要先新建一个类BingPic(名称可以自行改动),然后在菜单里找到Code->Generate..->GsonFormat,然后把json字符串粘贴进弹出的窗口就可以生成相应的Bean类了,实际效果就像下面这样:





最后就是在DataAsyncTask里重新实现doInBackground()方法了,直接上代码:
@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());
Type type= new TypeToken<BingPic>(){}.getType();
Gson gson = new Gson();
BingPic bingPic = gson.fromJson(data,type);
Log.i(TAG, "请求成功");
} else {
Log.i(TAG, "请求失败");
}
urlConn.disconnect();
}catch (Exception e){
e.printStackTrace();
}
return null;
}
可以看到实际过程分为三步:获取Bean类格式->声明Gson变量->调用fromJson()方法生成BingPic类型的变量。这样我们需要的数据就存储在这个bingPic变量里了。

第二部分:信息的处理

转换是完成了,可是我们还需要把这些转换后的数据展现出来。
首先回到getData()方法,上次我们把DataAsyncTask放在了这里,但是我们知道这里应该返回一个List,那么DataAsyncTask就应该返回一个List。而为了让它能够返回数据,这里就要用到AsyncTask的get()方法了,使用方法如下:
public List<Map<String,Object>> getData()
{
try{
myTask = new DataAsyncTask();
list.addAll(myTask.execute(0).get());
}catch (Exception e){
e.printStackTrace();
}
return list;
}
addAll()我们上次已经讲过了,不过添加上这行代码编译器也会立刻提醒你类型不对,仔细一看就能发现get()实际返回的是onPostExecute(Result)里的Result参数,也就是doInBackground()的返回值。这样的话我们就在doInBackground()里完成List的构建就可以了,需要注意的是DataAsyncTask本身的继承和构造方法都要相应修改:
package com.xugino.bingpicanother;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static android.content.ContentValues.TAG;

class DataAsyncTask extends AsyncTask<Integer,Void,List<Map<String,Object>>> {

private List<Map<String,Object>> list;

DataAsyncTask(){
super();
list = new ArrayList<>();
}

@Override
protected List<Map<String,Object>> 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) {
int i;
Map<String,Object> map;
String data = readStream(urlConn.getInputStream());
Type type= new TypeToken<BingPic>(){}.getType();
Gson gson = new Gson();
BingPic bingPic = gson.fromJson(data,type);
for(i=0;i<5;i++){
map=new HashMap<>();
map.put("pic",getBitmap("http://cn.bing.com"+bingPic.getImages().get(i).getUrl()));
map.put("text",bingPic.getImages().get(i).getCopyright());
map.put("time",bingPic.getImages().get(i).getEnddate());
list.add(map);
}
Log.i(TAG, "请求成功");
} else {
Log.i(TAG, "请求失败");
}
urlConn.disconnect();
}catch (Exception e){
e.printStackTrace();
}
return list;
}

private static Bitmap getBitmap(String path) throws IOException {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() == 200){
InputStream inputStream = conn.getInputStream();
Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeStream(inputStream),150,150,true);
conn.disconnect();
return bitmap;
}
conn.disconnect();
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();
}
}
新增添的getBitmap()方法用于从图片的url得到可以显示的bitmap,需要注意createScaledBitmap()方
4000
法是带有缩放变形的生成,这也是为了能把整张图都放进来。

当然Adapter也要相应的修改一下:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView==null){
viewHolder = new ViewHolder();
convertView=mInflater.inflate(R.layout.list_item,null);
viewHolder.pic=convertView.findViewById(R.id.item_pic);
viewHolder.text=convertView.findViewById(R.id.item_text);
viewHolder.time=convertView.findViewById(R.id.item_time);
viewHolder.btn=convertView.findViewById(R.id.download_btn);
convertView.setTag(viewHolder);
}else{
viewHolder=(ViewHolder)convertView.getTag();
}

viewHolder.pic.setImageBitmap((Bitmap) data.getList().get(position).get("pic"));
viewHolder.text.setText((CharSequence) data.getList().get(position).get("text"));
viewHolder.time.setText((CharSequence) data.getList().get(position).get("time"));
viewHolder.btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {

}
});
return convertView;
}


为了方便访问减少冗余操作,重新实现DataResource()和initData():
public class DataResource {

private List<Map<String,Object>> list;
private DataAsyncTask myTask;

public DataResource(){
list=new ArrayList<>();
}

public List<Map<String,Object>> getList()
{
return list;
}

public void getData()
{
try{
myTask = new DataAsyncTask();
list.addAll(myTask.execute(0).get());
}catch (Exception e){
e.printStackTrace();
}
}
}


private void initData(){
data.getData();
mList.addAll(data.getList());
mAdapter.notifyDataSetChanged();
}


最后调试一下来看看效果:



可以说是符合预期了,不过瑕疵多了点。
下一期的话先暂停一点进度,做一点面子工程来让用户用着舒服一点。

(说明:这次做的很多已经跟最初贴上去的那个git项目有不少出入了,基本都是改良和规范,新的代码我也贴上github了大家自取)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 前端 gson json