现在的位置: 首页 > 综合 > 正文

Android–使用Http向服务器发送请求并取得返回结果,下载图片

2013年07月04日 ⁄ 综合 ⁄ 共 10090字 ⁄ 字号 评论关闭

由于最近在做的一个游戏项目有一个排行榜,

排行榜是一个列表,界面大致如下:

 

排名     人物名称     头像图片     分数

排名     人物名称     头像图片     分数

排名     人物名称     头像图片     分数

排名     人物名称     头像图片     分数

排名     人物名称     头像图片     分数

排名     人物名称     头像图片     分数

 

排行     人物名称     头像图片     分数

 

列表中有100条数据,列表下面有一个

控件显示游戏玩家自己的排名信息

 

需求如下:

每次进入排行榜界面,则将游戏玩家的

人物名称和分数提交到服务端,服务端

接收请求后对数据库中的数据进行排序,

取得前100名的数据,还有一条游戏玩家

的数据,总共101条数据,由于客户端

还需要下载头像图片,所以返回的数据

还有头像图片的下载地址,服务端将所有

的数据包装成一个Json数据返回给客户端

大致格式如下:

 

{"rank":
[
{"person":"\u66f9\u64cd","index":1,"score":35852},
{"person":"\u66f9\u64cd","index":2,"score":32563},
{"person":"\u5b59\u6743","index":3,"score":10000},
{"person":"\u5218\u5907","index":4,"score":9638},
{"person":"\u5218\u5907","index":5,"score":8888},
{"person":"\u5b59\u6743","index":6,"score":8886},
{"person":"\u5218\u5907","index":7,"score":7865},
{"person":"\u5218\u5907","index":8,"score":6950},
{"person":"\u5218\u5907","index":9,"score":6548},
{"person":"\u5218\u5907","index":10,"score":6540},
{"person":"\u66f9\u64cd","index":11,"score":5288}
],


"base":"(服务端地址)",

"head":
[
{"person":"\u66f9\u64cd","filename":"\/caocao\/20130718185726036.png", "size":12343},

{"person":"\u5b59\u6743","filename":"\/sunqun\/20130718185726046.png", "size":12343},

{"person":"\u5218\u5907","filename":"\/liubei\/20130718185726056.png", "size":12343}
]
}

 

rank的每个对象包括:人物名称,排名,分数

head的每个对象包括:人物名称,头像图片名称

base为服务端地址

 

大致流程如下:

1.进入排行榜界面,将游戏玩家的数据发送到服务端

2.取得服务端返回的Json数据,解析出rank数组,head数组和base字符串

3.使用头像图片路径下载头像图片到本地

4.新建一个ResultMessage类,属性包括:排名,人物名称,本地头像图片地址,分数

5.在解析rank数组时实例化ResultMessage,添加到List中并返回出去

 

主要有三个类:LoadImage.java,ResultMessage.java,Upload.java

 

LoadImage.java用于下载头像图片,由于每次进入排行榜界面都会向

服务端发送请求,每次都会返回头像图片的下载地址,所以需要

做下判断本地是否已经有此图片存在,还有就是判断图片大小是否

正确,因为会有这样一种情况,在下载图片时突然网络断开,这时

头像图片没有下载完整,下次进入排行榜界面的时候又向服务端

发送请求,又下载头像图片,此时程序判断出本地已经有此图片

存在,所以不会再下载图片,但是图片不完整,无法正常使用,

所以除了判断本地是否有图片之外,还需要判断图片的大小是不是

跟服务端发过来的大小一样,只有图片存在,并且大小一样的时候

才不下载图片

 

具体代码如下:

package com.joye3g.http;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.http.HttpStatus;

public class LoadImage {

	private static final int SUCCES = 1;//下载成功
	private static final int ERRO = -1;//下载失败
	private static final int EXIST = 0;//文件已存在
	private static int result = EXIST;//返回的下载结果
	private String localPath;//本地路径
	
	public LoadImage(String localPath) {
		this.localPath = localPath;
	}

	/**
	 * @param urlPathPrefix       网址前缀
	 * @param filename            文件名
	 * @param size                文件大小
	 * @return
	 * @throws IOException
	 */
	public int download(String urlPathPrefix, String filename, long size) throws IOException{
		String filePath = localPath + File.separator + filename.substring(filename.lastIndexOf("/") + 1);
		//判断filePath路径下有没有此图片存在,大小是否相同,如果不存在,则发送Http请求下载图片,存在则不下载
		if(isFileExist(filePath) && isSizeSame(filePath, size)){
			return result = EXIST;
		}else{
			//从URL中取得输入流
			InputStream is = getHttpInputStream(urlPathPrefix + filename);
			//创建新文件
			File file = createFile(filePath);
			//下载图片
			if(is != null) downLoadImage(file, is);  
		}
		return result;
	}

	/**
	 * 下载图片
	 * @param file  文件
	 * @param is	从URL取得的输入流
	 */
	private void downLoadImage(File file, InputStream is){
		FileOutputStream fs = null;
		try {
			fs = new FileOutputStream(file);
			byte[] buffer = new byte[4 * 1024];
			int len = 0;
			while((len = is.read(buffer)) != -1){
				fs.write(buffer, 0, len);
			}
			fs.flush();
			result = SUCCES;
		} catch (Exception e) {
			result = ERRO;
			e.printStackTrace();
		}finally{
			try {
				if(fs != null){
					fs.close();
				}
				if(is != null){
					is.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 根据URL取得输入流
	 * @param urlPath   网络路径
	 * @return
	 * @throws IOException
	 */
	private InputStream getHttpInputStream(String urlPath) throws IOException{
		URL url = new URL(urlPath);
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		if(conn.getResponseCode() == HttpStatus.SC_OK) {
			return conn.getInputStream();
		}
		return null;
	}

	/**
	 * 判断文件是否已经存在
	 * @param fileName     文件路径
	 * @return
	 */
	private boolean isFileExist(String fileName){
		File file = new File(fileName);
		return file.exists();
	}

	/**
	 * 在指定路径下创建新文件
	 * @param fileName      文件路径
	 * @return
	 * @throws IOException
	 */
	private File createFile(String fileName) throws IOException{
		File file = new File(fileName);
		if(!file.createNewFile()){
			file.delete();
			file.createNewFile();
		}
		return file;
	}
	
	/**
	 * 若文件已存在,判断文件大小是否正确
	 * @param filePath         图片路径
	 * @param size             文件大小
	 * @return
	 */
	private boolean isSizeSame(String filePath, long size){
		File file = new File(filePath);
		return file.length() == size;
	}
}

 

ResultMessage.java具体代码如下:

package com.joye3g.http;

public class ResultMessage {
	
	private int index;
	private String name;
	private int score;
	private String imagePath;
	
	public ResultMessage(int index, String name, int score, String imagePath) {
		this.index = index;
		this.name = name;
		this.score = score;
		this.imagePath = imagePath;
	}

	public String getImagePath() {
		return imagePath;
	}

	public void setImagePath(String imagePath) {
		this.imagePath = imagePath;
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}
}

 

UpLoad.java用于向服务端发送请求并接受返回的数据,

对返回的数据进行包装再返回出去,首先在构造函数中

传入要上传到服务端的人物名称,分数和上下文对象,

上下文对象主要用于取得程序的安装路径和UUID,

使用方法很简单:

UpLoad upload = new UpLoad("曹操", 23456, getApplicationContext());

List<ResultMessage> messages  = upload.post("服务端地址");

 

UpLoad.java具体代码如下:

package com.joye3g.http;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
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 java.util.UUID;
import java.util.zip.GZIPInputStream;
import org.apache.http.HttpStatus;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.telephony.TelephonyManager;

/**
 * @author ZLQ
 *
 */
public class Upload {

	private static final String GZIP = "gzip";
	private Context context;
	private JSONObject jsonData;

	/**
	 * 构造函数
	 * @param name
	 *            要上传的人物名称
	 * @param score
	 *            要上传的分数
	 * @param context
	 *            上下文对象,用于取得UUID和本地路径
	 */
	public Upload(String name, int score, Context context) {

		jsonData = new JSONObject();
		this.context = context;

		try {
			jsonData.put("person", name);
			jsonData.put("uploaduser", getUUID());
			jsonData.put("score", score);
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 发送post请求
	 * @param url
	 *            URL路径
	 * @return 返回一个List<Message>链表
	 */
	public List<ResultMessage> post(String url) {
		List<ResultMessage> messages = null;
		try {
			messages = sendHttpResponse(url);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return messages;
	}

	/**
	 * 发送请求,返回结果
	 * @param url
	 *            URL路径
	 * @return 返回一个List<Message>链表
	 * @throws JSONException
	 * @throws Exception
	 */
	private List<ResultMessage> sendHttpResponse(String url)
			throws IOException, JSONException {
		URL uri = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) uri.openConnection();
		conn.setRequestMethod("POST"); // Post方式
		conn.setDoOutput(true);// 允许输出
		conn.setRequestProperty("connection", "keep-alive"); // 客户端到服务器端的连接持续有效
		conn.setRequestProperty("Content-Type", "application/x-javascript; charset=UTF-8");
		conn.setRequestProperty("accept-encoding", "gzip,deflate");//设置 gzip的请求头 
		DataOutputStream outStream = new DataOutputStream(conn.getOutputStream());
		outStream.write(jsonData.toString().getBytes());//将数据内容写入到流中
		outStream.flush();
		outStream.close();
		return getReturnMessage(conn);//返回服务端返回的结果
	}

	/**
	 * 取得服务端返回的结果
	 * @param conn
	 * @return
	 * @throws IOException
	 * @throws JSONException
	 */
	private List<ResultMessage> getReturnMessage(HttpURLConnection conn)
			throws IOException, JSONException {

		List<ResultMessage> messages = null;
		String content_encode = conn.getContentEncoding();
		String content = null;

		if (conn.getResponseCode() == HttpStatus.SC_OK) {
			if (null != content_encode && !"".equals(content_encode)
					&& content_encode.equals(GZIP)) {
				//对服务端返回的内容进行解压
				content = unGzip(conn.getInputStream());
			}

			JSONObject objMain = new JSONObject(content);
			JSONArray ranks = objMain.getJSONArray("rank");//取得rank数组
			JSONArray heads = objMain.getJSONArray("head");//取得head数组
			String base = objMain.getString("base");//取得地址前缀

			LoadImage load = new LoadImage(getLocalPath());
			Map<String, String> map = new HashMap<String, String>();

			//取得heads数组中的对象
			for (int i = 0; i < heads.length(); i++) {
				JSONObject head = heads.getJSONObject(i);
				String person = head.getString("person");
				String filename = head.getString("filename");
				long size = head.getLong("size");
				map.put(person, filename);
				load.download(base, filename, size);//下载图片
			}

			//取得除去最后一条的所有数据
			messages = new ArrayList<ResultMessage>();
			for (int i = 0; i < ranks.length() - 1; i++) {
				JSONObject rankObj = ranks.getJSONObject(i);
				messages.add(rank(rankObj, map));
			}

			//取得最后一个数据
			JSONObject rankObj = ranks.getJSONObject(ranks.length() - 1);
			messages.add(rank(rankObj, map));
		}
		conn.disconnect();
		return messages;
	}

	// 解析数据
	private ResultMessage rank(JSONObject rank, Map<String, String> map)
			throws JSONException {
		int num = rank.getInt("index");
		String person = rank.getString("person");
		String filename = map.get(person);
		//拼接本地图片路径
		String imagePath = getLocalPath() + File.separator
				+ filename.substring(filename.lastIndexOf("/") + 1);
		int score = rank.getInt("score");
		//实例化一个ResultMessage对象
		ResultMessage message = new ResultMessage(num, person, score, imagePath);
		return message;
	}

	/**
	 * 对服务器返回的内容进行解压并返回解压后的内容
	 * @param is
	 * @return
	 * @throws IOException
	 * @throws UnsupportedEncodingException
	 */
	private static String unGzip(InputStream is) throws IOException,
	UnsupportedEncodingException {
		GZIPInputStream in = new GZIPInputStream(is);
		ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
		int len = -1;
		byte[] buffer = new byte[1024];
		while ((len = in.read(buffer)) != -1) {
			arrayOutputStream.write(buffer, 0, len);
		}
		in.close();
		arrayOutputStream.close();
		is.close();
		return new String(arrayOutputStream.toByteArray(), "utf-8");
	}

	/**
	 * 返回UUID
	 * @return
	 */
	private String getUUID() {
		final TelephonyManager tm = (TelephonyManager) context
				.getSystemService(Context.TELEPHONY_SERVICE);
		final String tmDevice, tmSerial, androidId;
		tmDevice = "" + tm.getDeviceId();
		tmSerial = "" + tm.getSimSerialNumber();
		androidId = ""
				+ android.provider.Settings.Secure.getString(
						context.getContentResolver(),
						android.provider.Settings.Secure.ANDROID_ID);

		UUID deviceUUID = new UUID(androidId.hashCode(),
				((long) tmDevice.hashCode() << 32 | tmSerial.hashCode()));
		return deviceUUID.toString();
	}

	/**
	 * 返回应用程序的安装路径
	 * @return
	 */
	private String getLocalPath() {
		return context.getApplicationContext().getFilesDir().getAbsolutePath();
	}
}

 

返回的messages中的每个对象的格式为:

排名,人物名称,本地头像图片的路径,分数

 

小结:

UUID,是手机的唯一标识,服务端通过UUID判断是否是同个用户提交数据

本地路径,程序安装在手机中,用户有可能会将程序移动到其他地方,所以数据,

如图片,数据文件等等文件应该放在程序路径下,这样程序移动时数据会一起

移动,不会出现程序移动后之前的数据找不到

GZIPInputStream,数据在网络中传递,速度和流量是一个重要方面,所以服务端应该先

将数据进行压缩再发送到客户端,客户端接收后再进行解压缩,这样可以减少流量开支

除此之外,通过网络传输数据,最好是对数据进行加密,保证安全性和完整性

 

抱歉!评论已关闭.