標籤:android io處理 json解析 城市三級聯動
/** * crazyandcoder * 聯絡: * QQ : 275137657 * email: [email protected] * 轉載請註明出處! */
三級城市聯動的實現
所謂的三級城市選擇聯動就是說當我們選擇省份時將會出現該省份下所有的城市,當我們選擇其中某一個城市時又將會出現該城市下所有的區,如果存在區的話。在本次執行個體中,主要用到了json解析,檔案I/O流,android Spinner控制項等知識點,記錄一下實現過程,便於以後查閱參考。
三級城市聯動肯定少不了我國各個地區的地址資訊,該例子中的資料我們以json的格式放在工程assets目錄下,然後通過解析出來即可,不需要我們直接放在res/values/array.xml中,這樣可以減少很多代碼。首先我們來看一下城市的json格式檔案的內容:
從上面的檔案中我們可以清楚的看到全國的城市名按照json的格式排列。我們通過解析該檔案,然後放入到spinner中顯示出來即可。
下面便是本次實現的:
一、程式碼分析
布局很簡單,一個TextView用於顯示選擇的地址資訊,三個spinner分別用於載入省、市、區地址資料。代碼就不貼了。我們直接來看下主類。因為我們將省市區資料放在檔案當中的,所以第一步便是要將其讀取出來然後解析成string類型的資料,方便下面使用。讀取本地資源的方法都是統一的,不熟悉的話可以參考上篇部落格:
《java 流概念的理解》
直接上代碼:
/** * 從asset目錄下讀取城市json檔案轉化為String類型 * * @Title: InitData * @param * @return void * @throws @date * [2015年8月21日 上午9:40:00] */private String InitData() {StringBuffer sb = new StringBuffer();AssetManager mAssetManager = this.getAssets();try {InputStream is = mAssetManager.open("city.json");byte[] data = new byte[is.available()];int len = -1;while ((len = is.read(data)) != -1) {sb.append(new String(data, 0, len, "gb2312"));}is.close();return sb.toString();} catch (IOException e) {e.printStackTrace();}return null;}
接下來我們便對上面讀取出來的資料進行解析,也是本文中的重點內容,我們細細地來分析一下解析過程,解析的資料格式還是蠻複雜的,數組中包含數組。首先我們得定義幾個變數,便於我們儲存省市區資料。
// 省份private String[] mProvinceDatas;// 城市private String[] mCitiesDatas;// 地區private String[] mAreaDatas;// 列表選擇的省市區private String selectedPro = "";private String selectedCity = "";private String selectedArea = "";private Spinner mProvinceSpinner;private Spinner mCitySpinner;private Spinner mAreaSpinner;private ArrayAdapter<String> mProvinceAdapter;private ArrayAdapter<String> mCityAdapter;private ArrayAdapter<String> mAreaAdapter;// 儲存省對應的所有市private Map<String, String[]> mCitiesDataMap = new HashMap<String, String[]>();// 儲存市對應的所有區private Map<String, String[]> mAreaDataMap = new HashMap<String, String[]>();
01~06行:定義的數組用於儲存省市區資訊
09~11行:定義的變數用於儲存我們通過spinner選擇的省市區資料
21~24行:定義的變數用於儲存我們選擇一個省份後它所包含的所有城市資訊以及對應的地區資訊。
接下來我們詳細分析一下解析過程
/** * 開始解析城市資料 * * @Title: BeginJsonCitisData * @param * @return void * @throws @date * [2015年8月21日 上午10:02:23] */private void BeginJsonCitisData(String cityJson) {if (!TextUtils.isEmpty(cityJson)) {try {JSONObject object = new JSONObject(cityJson);JSONArray array = object.getJSONArray("citylist");// 擷取省份的數量mProvinceDatas = new String[array.length()];String mProvinceStr = null;// 迴圈遍曆for (int i = 0; i < array.length(); i++) {// 迴圈遍曆省份,並將省儲存在mProvinceDatas[]中JSONObject mProvinceObject = array.getJSONObject(i);if (mProvinceObject.has("p")) {mProvinceStr = mProvinceObject.getString("p");mProvinceDatas[i] = mProvinceStr;} else {mProvinceDatas[i] = "unknown province";}JSONArray cityArray;String mCityStr = null;try {// 迴圈遍曆省對應下的城市cityArray = mProvinceObject.getJSONArray("c");} catch (Exception e) {e.printStackTrace();continue;}mCitiesDatas = new String[cityArray.length()];for (int j = 0; j < cityArray.length(); j++) {// 迴圈遍曆城市,並將城市儲存在mCitiesDatas[]中JSONObject mCityObject = cityArray.getJSONObject(j);if (mCityObject.has("n")) {mCityStr = mCityObject.getString("n");mCitiesDatas[j] = mCityStr;} else {mCitiesDatas[j] = "unknown city";}// 迴圈遍曆地區JSONArray areaArray;try {// 判斷是否含有第三級地區劃分,若沒有,則跳出本次迴圈,重新執行迴圈遍曆城市areaArray = mCityObject.getJSONArray("a");} catch (Exception e) {e.printStackTrace();continue;}// 執行下面過程則說明存在第三級地區mAreaDatas = new String[areaArray.length()];for (int m = 0; m < areaArray.length(); m++) {// 迴圈遍曆第三級地區,並將地區儲存在mAreaDatas[]中JSONObject areaObject = areaArray.getJSONObject(m);if (areaObject.has("s")) {mAreaDatas[m] = areaObject.getString("s");} else {mAreaDatas[m] = "unknown area";}Log.d(TAG, mAreaDatas[m]);}// 儲存市對應的所有第三級地區mAreaDataMap.put(mCityStr, mAreaDatas);}// 儲存省份對應的所有市mCitiesDataMap.put(mProvinceStr, mCitiesDatas);}} catch (JSONException e) {e.printStackTrace();}}}上面的代碼其實已經注釋的很詳細了,我們再來仔細的分析記錄一下。
14行:我們首先拿到要解析的根節點,從city.json檔案中我們可以清楚的看到,這個根節點是一個數群組類型。數組的內容便是我們需要的省份資訊。
20~29行:迴圈遍曆所有的省份,並將遍曆的結果存入到mProvinceDatas[]中去。
31~49行:將每個省份下對應的城市 遍曆存放到mCitiesDatas[]中去。
53~61行:這一段代碼比較重要,主要意思是:對於直轄市,它是沒有第三級地區的,所以,當我們遍曆時發現如果沒有第三級地區,我們將直接跳過該城市,遍曆下個城市。
63~75行:這一段就是遍曆第三級地區,並將遍曆的結果存入到mAreaDatas[]中去。
78行:城市和地區一一對應。便於後面通過城市擷取該城市所對應的地區的資料。
82行:省份和城市一一對應。便於後面通過省份擷取該省份所對應的城市的資料。
上面便是解析的全部過程,注釋還是比較詳細的,接下來就比較簡單了。將解析出來的結果放入到spinner中的適配器當中去顯示資料即可。這裡的適配器我們選取ArrayAdapter。
mProvinceAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, mProvinceDatas);mProvinceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);mProvinceSpinner.setAdapter(mProvinceAdapter);// 省份選擇mProvinceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {selectedPro = "";selectedPro = (String) parent.getSelectedItem();// 根據省份更新城市地區資訊updateCity(selectedPro);Log.d(TAG, "mProvinceSpinner has excuted !" + "selectedPro is " + selectedPro);}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});// 市選擇mCitySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {selectedCity = "";selectedCity = (String) parent.getSelectedItem();updateArea(selectedCity);Log.d(TAG, "mCitySpinner has excuted !" + "selectedCity is " + selectedCity);}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});// 區選擇mAreaSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {selectedArea = "";selectedArea = (String) parent.getSelectedItem();tv_address.setText("已選擇: " + selectedPro + selectedCity + selectedArea);Log.d(TAG, "mAreaSpinner has excuted !" + "selectedArea is " + selectedArea);}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});
/** * 根據市 選擇對應的區 * * @Title: updateArea * @param @param * city * @return void * @throws @date * [2015年8月21日 下午3:52:17] */private void updateArea(String city) {String[] areas = mAreaDataMap.get(city);// 存在區if (areas != null) {// 存在區mAreaSpinner.setVisibility(View.VISIBLE);mAreaAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, areas);mAreaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);mAreaSpinner.setAdapter(mAreaAdapter);mAreaAdapter.notifyDataSetChanged();mAreaSpinner.setSelection(0);} else {tv_address.setText("已選擇: " + selectedPro + selectedCity);mAreaSpinner.setVisibility(View.GONE);}}/** * 根據省份更新城市資料 * * @Title: updateCityAndAreaData * @param @param * pro 省份 * @return void * @throws @date * [2015年8月21日 下午3:20:15] */private void updateCity(String pro) {String[] cities = mCitiesDataMap.get(pro);for (int i = 0; i < cities.length; i++) {// 存在區mCityAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, cities);mCityAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);mCitySpinner.setAdapter(mCityAdapter);mCityAdapter.notifyDataSetChanged();mCitySpinner.setSelection(0);}}
整體的代碼注釋比較詳細,最後附上整個工程的原始碼。
:JsonDemo
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
android json解析使用總結(三) — 三級城市聯動的實現