由於最近在做的一個遊戲項目有一個熱門排行榜, 熱門排行榜是一個列表,介面大致如下: 排名 人物名稱 頭像圖片 分數 排名 人物名稱 頭像圖片 分數 排名 人物名稱 頭像圖片 分數 排名 人物名稱 頭像圖片 分數 排名 人物名稱 頭像圖片 分數 排名 人物名稱 頭像圖片 分數 排行 人物名稱 頭像圖片 分數 列表中有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中的每個對象的格式為: 排名,人物名稱,本地頭像圖片的路徑,分數