Android開發執行個體-高校錄取分數線應用
本系列文章提供簡單Android應用開發執行個體方法,文章步驟如下所示:
1 擷取應用所需的資料來源
資料來源一般來源於互連網、個人搜集或者其他方式
2 應用UI設計
每個應用軟體都需要有一個簡單的UI設計草圖,便於開發人員更好的實現編碼
3 應用實現
實現完整的Android應用
特此說明:本系列文章的資料來源均採用互連網方式擷取,僅作為樣本示範
應用介紹
提供各個高校曆屆的分數線錄取查詢功能,作為高考學子填寫志願的參考應用。最終:
一、資訊載入
1 從Assets中擷取到學校資訊,學校儲存格式為:
1#10001#北京大學
1#10002#中國人民大學
1#10003#清華大學
1#10004#北京交通大學
其中1代表省份ID,10001代表學校ID,最後的為學校名稱
我們建立FileUtils類,提供擷取Assets下檔案的方法:
public static List loadFileContentForList(String filePath, Context ctx) throws IOException {InputStream is = ctx.getAssets().open(filePath);BufferedReader br = new BufferedReader(new InputStreamReader(is, gbk));ArrayList results = new ArrayList();String readLine = null;while((readLine = br.readLine()) != null) {results.add(readLine);}return results;}以上方法將檔案中的資料按行載入到列表中,由於在儲存資料來源時儲存為ASCII格式,所以此處採用gbk載入。
2 從網路中擷取高校查詢結果
採用Android內建的HttpClient進行實現,我們首先封裝一個簡單的HttpUtils處理類,提供httpGet要求方法:
/** * 擷取指定URL請求的結果資訊,以字串方式返回請求內容 * @param url 請求地址 * @param param 請求所需參數 * @return */public static String httpGet(String url, HashMap param) {HttpParams httpParams = new BasicHttpParams();HttpConnectionParams.setConnectionTimeout(httpParams, 5000);HttpConnectionParams.setSoTimeout(httpParams, 5000);HttpClient mHttpClient = new DefaultHttpClient(httpParams);String mUrl = url;if(param != null && param.size() > 0) {StringBuilder sb = new StringBuilder();sb.append(url);sb.append(?);for(Entry m : param.entrySet()) {sb.append(m.getKey());sb.append(=);sb.append(m.getValue());sb.append(&);}mUrl = sb.substring(0, sb.length()-1);}HttpGet httpRequest = new HttpGet(mUrl);try {HttpResponse httpResponse = mHttpClient.execute(httpRequest);if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {String str = EntityUtils.toString(httpResponse.getEntity());return str;}} catch (Exception e) {e.printStackTrace();} finally {httpRequest.abort();}return null;}3 為了便於控制項渲染資料,我們將所有資料均轉為SimpleAdapter可識別的格式ArrayList>
通過MUtils類提供各個資料的轉化:
loadSchool方法用於提供所有學校資訊資料轉化,其中Map的key表示省份ID,value為學校列表
@SuppressLint(UseSparseArrays)public static HashMap>> loadSchool(Context ctx) {HashMap>> result = new HashMap>>();try {List contents = FileUtils.loadFileContentForList(m/data, ctx);for(int i = 0, len = contents.size(); i < len; i++) {String[] item = contents.get(i).split(#);HashMap data = new HashMap();data.put(id, item[1]);data.put(name, item[2]);ArrayList> itemList = result.get(Integer.parseInt(item[0]));if(itemList == null) {itemList = new ArrayList>();result.put(Integer.parseInt(item[0]), itemList);}itemList.add(data);}} catch (IOException e) {e.printStackTrace();}return result;}loadResult方法用於將網路擷取的查詢結果資訊進行轉化,主要將返回的JSON格式進行處理
public static ArrayList> loadResult(final String schoolId, final int type, final int prov2) throws Exception{//從網路擷取查詢結果,返回格式為JSONString netStr = HttpUtils.httpGet(BASE_URL, new HashMap(){{put(_action, collegescore);put(num, 0);put(provid, prov2);put(wl, type);put(collegeid, schoolId);}});if(netStr == null) {//異常直接返回nullreturn null;}JSONArray resultArray = new JSONArray(netStr);ArrayList> result = new ArrayList>();for(int i = 0, len = resultArray.length(); i < len; i++) {//依次處理每一條資料資訊JSONObject jobj = resultArray.getJSONObject(i);HashMap d = new HashMap();int tempInt;d.put(year, jobj.getString(syear));tempInt = jobj.optInt(plan, -1);d.put(plan, (tempInt <= 0 ? -- : + tempInt));tempInt = jobj.optInt(score_min, -1);d.put(score_min, tempInt <= 0 ? -- : + tempInt);tempInt = jobj.optInt(score_avg, -1);d.put(score_avg, (tempInt <= 0 ? -- : + tempInt));tempInt = jobj.optInt(score_td, -1);d.put(score_td, (tempInt <= 0 ? -- : + tempInt));tempInt = jobj.optInt(score_max, -1);d.put(score_max, (tempInt <= 0 ? -- : + tempInt));d.put(batch, batchMap.get(jobj.getString(batch)));d.put(batch_diff, jobj.getString(batch_diff));result.add(d);}return result;}public static final HashMap batchMap = new HashMap(){{put(00, 不詳);put(01, 本科提前批);put(11, 本科一批);put(12, 本科二批);put(13, 本科三批);put(123, 本科二、三批);put(21, 專科);}};其中BASE_URL = http://kaoshi.edu.sina.com.cn/iframe/i_collegescore.php, batchMap從原有資料網站中擷取並初始化資料
二、Activity實現
Activity中所有變數定義如下所示:
//依次為省份選擇ID,使用者所在地ID,學校序號,文理科類型int prov1, prov2, school, type;ArrayList> resultData;//查詢錄取結果HashMap>> datas;//儲存省份下的學校資訊//依次為省份選擇彈窗、學校選擇彈窗和文理科選擇彈窗PopupWindow provWindow, schoolWindow, typeWindow;TextView prov1Sel, schoolSel, typeSel, prov2Sel, tipView, resultTitleView;ListView provList, schoolList, resultList;LinearLayout resultLayout;Button queryButton;//依次為省份資訊和文理科資訊(從strings.xml中擷取)String[] provs, types;
省份彈窗實現如下所示:
/** * 顯示省份彈窗。type=0表示學校省份彈窗,=1表示使用者所在地省份彈窗 * @param type */public void showProvWindow(final int type) {if (provWindow == null) {View v = LayoutInflater.from(this).inflate(R.layout.pop_list, null);provList = (ListView) v.findViewById(R.id.pop_list);provList.setAdapter(new ArrayAdapter(this,R.layout.pop_list_item, R.id.pop_list_item_name, provs));provWindow = new PopupWindow(v, Utils.screenWidth,Utils.screenHeight / 2, true);}provList.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView av, View arg1, int position,long arg3) {//ID為選擇序號+1if (type == 0) {prov1 = position + 1;prov1Sel.setText(provs[position]);} else {prov2 = position + 1;prov2Sel.setText(provs[position]);}if (provWindow != null) {provWindow.dismiss();}}});if (type == 0 && prov1 > 0) {provList.setSelection(prov1 - 1);} else if (type == 1 && prov2 > 0) {provList.setSelection(prov2 - 1);} else {provList.setSelection(0);}provWindow.showAsDropDown(type == 0 ? prov1Sel : prov2Sel, 0, 0);provWindow.update();}文理科類型彈窗實現如下所示:
public void showTypeWindow() {if (typeWindow == null) {View v = LayoutInflater.from(this).inflate(R.layout.pop_list, null);ListView tList = (ListView) v.findViewById(R.id.pop_list);tList.setAdapter(new ArrayAdapter(this, R.layout.pop_list_item,R.id.pop_list_item_name, types));typeWindow = new PopupWindow(v, Utils.screenWidth / 2,Utils.screenHeight / 2, true);tList.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView av, View arg1,int position, long arg3) {type = position;typeSel.setText(types[position]);if (typeWindow != null) {typeWindow.dismiss();}}});}typeWindow.showAsDropDown(typeSel, 0, 0);typeWindow.update();}學校下拉彈窗實現如下所示:
public void showSchoolWindow() {if (prov1 <= 0) {Toast.makeText(this, 請先選擇省份!, Toast.LENGTH_SHORT).show();return;}if (schoolWindow == null) {View v = LayoutInflater.from(this).inflate(R.layout.pop_list, null);schoolList = (ListView) v.findViewById(R.id.pop_list);schoolList.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView av, View arg1,int position, long arg3) {school = position;schoolSel.setText((String) datas.get(prov1).get(school).get(name));if (schoolWindow != null) {schoolWindow.dismiss();}}});schoolWindow = new PopupWindow(v, Utils.screenWidth,Utils.screenHeight / 2, true);}//每次點擊都需要更新資料,防止省份改變schoolList.setAdapter(new SimpleAdapter(this, datas.get(prov1),R.layout.pop_list_item, new String[] { name },new int[] { R.id.pop_list_item_name }));schoolList.setSelection(school);schoolWindow.showAsDropDown(schoolSel, 0, 0);schoolWindow.update();}因為Http請求不能在主線程實現,我們通過新開線程,通過Handler實現UI重新整理,請求查詢並渲染結果如下所示:
@Overridepublic void run() {try {resultData = MUtils.loadResult((String) datas.get(prov1).get(school).get(id), type + 1, prov2);} catch (Exception e) {resultData = null;}handler.sendEmptyMessage(0);}public void search() {if (!Utils.canAccessNetwork(this)) {tipView.setText(無法串連到網路!);changeView(false);return;}if (prov1 <= 0) {tipView.setText(請選擇學校!);changeView(false);return;}if (prov2 <= 0) {tipView.setText(請選擇您的所在地!);changeView(false);return;}tipView.setText(正在努力為您載入中...);changeView(false);new Thread(this).start();}Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {if (resultData == null) {tipView.setText(擷取結果失敗,請稍後再試!);changeView(false);} else {StringBuilder sb = new StringBuilder();sb.append(); sb.append(); sb.append(datas.get(prov1).get(school).get(name)); sb.append(); sb.append(在); sb.append(); sb.append(provs[prov2 - 1]); sb.append(); sb.append(的); sb.append(types[type]); sb.append(錄取線); sb.append(); resultTitleView.setText(Html.fromHtml(sb.toString())); resultList .setAdapter(new SimpleAdapter(MainActivity.this, resultData, R.layout.result_item, new String[] { year, score_max, score_avg, score_td, plan, batch, batch_diff }, new int[] { R.id.result_item_year, R.id.result_item_max, R.id.result_item_avg, R.id.result_item_real, R.id.result_item_persons, R.id.result_item_pici, R.id.result_item_xiancha })); changeView(true); } }; }; public void changeView(boolean flag) { if (flag) { resultLayout.setVisibility(View.VISIBLE); tipView.setVisibility(View.GONE); } else { resultLayout.setVisibility(View.GONE); tipView.setVisibility(View.VISIBLE); } }
完整的Activity代碼如下所示:
package com.gklq.zl;import java.util.ArrayList;import java.util.HashMap;import java.util.Timer;import java.util.TimerTask;import com.my.lib.Utils;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.text.Html;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.widget.AdapterView.OnItemClickListener;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.PopupWindow;import android.widget.SimpleAdapter;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity implements OnClickListener, Runnable {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);if (Utils.screenHeight <= 0) {Utils.initSize(this);}if (datas == null) {datas = MUtils.loadSchool(this);}setContentView(R.layout.activity_main);prov1Sel = (TextView) findViewById(R.id.prov1_sel);prov1Sel.setOnClickListener(this);schoolSel = (TextView) findViewById(R.id.school_sel);schoolSel.setOnClickListener(this);typeSel = (TextView) findViewById(R.id.type_sel);typeSel.setOnClickListener(this);prov2Sel = (TextView) findViewById(R.id.prov2_sel);prov2Sel.setOnClickListener(this);queryButton = (Button) findViewById(R.id.query_btn);queryButton.setOnClickListener(this);tipView = (TextView) findViewById(R.id.text_tip);resultLayout = (LinearLayout) findViewById(R.id.layout_result);resultTitleView = (TextView) findViewById(R.id.text_result);resultList = (ListView) findViewById(R.id.list_result);provs = getResources().getStringArray(R.array.province);types = getResources().getStringArray(R.array.type);}public void onClick(android.view.View v) {switch (v.getId()) {case R.id.prov1_sel:showProvWindow(0);break;case R.id.prov2_sel:showProvWindow(1);break;case R.id.type_sel:showTypeWindow();break;case R.id.school_sel:showSchoolWindow();break;case R.id.query_btn:search();break;default:break;}}@Overridepublic void run() {try {resultData = MUtils.loadResult((String) datas.get(prov1).get(school).get(id), type + 1, prov2);} catch (Exception e) {resultData = null;}handler.sendEmptyMessage(0);}public void search() {if (!Utils.canAccessNetwork(this)) {tipView.setText(無法串連到網路!);changeView(false);return;}if (prov1 <= 0) {tipView.setText(請選擇學校!);changeView(false);return;}if (prov2 <= 0) {tipView.setText(請選擇您的所在地!);changeView(false);return;}tipView.setText(正在努力為您載入中...);changeView(false);new Thread(this).start();}Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {if (resultData == null) {tipView.setText(擷取結果失敗,請稍後再試!);changeView(false);} else {StringBuilder sb = new StringBuilder();sb.append(