android json解析使用总结(三) — 三级城市联动的实现

/**      
* 作者:crazyandcoder      
* 联系:      
*      QQ   : 275137657      
*      email: lijiwork@sina.com      
* 转载请注明出处!      
*/  


三级城市联动的实现

             

所谓的三级城市选择联动就是说当我们选择省份时将会出现该省份下所有的城市,当我们选择其中某一个城市时又将会出现该城市下所有的区,如果存在区的话。在本次实例中,主要用到了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() {

			@Override
			public 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);
			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {
			}
		});

		// 市选择
		mCitySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public 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);
			}

			@Override
			public void onNothingSelected(AdapterView<?> parent) {

			}
		});

		// 区选择
		mAreaSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {

			@Override
			public 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);
			}

			@Override
			public 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




  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 使用Ajax和JSON实现省市区三级联动,可以实现在前端页面上选择省份后,联动显示该省份下的城市列表,再选择城市联动显示该城市下的区县列表。具体实现方式可通过使用jQuery的get()和post()方法获取后台传来的JSON数据,然后通过遍历JSON数据并插入到相应的下拉框中实现。 ### 回答2: 随着互联网的迅速发展,更好的用户体验已经成为了网站开发的一个重要需求。联动菜单是一种常见的交互方式,可以让用户快速选择需要的信息。省市区三级联动就是一种常见的联动菜单,当用户选择一个省份时,相关的城市和区县信息会跟着自动显示出来。在这里,我们将介绍如何使用ajax和json实现省市区三级联动实现联动的前提是你需要拥有一个包含省市区数据的json文件,这个json文件可以手动创建,也可以通过爬虫获取。接下来是实现的步骤: 步骤一:HTML页面的构建 首先在HTML页面上创建个下拉菜单,分别代表省、市、区。代码如下: ``` <select id="province"> <option>选择省份</option> </select> <select id="city"> <option>选择城市</option> </select> <select id="area"> <option>选择区县</option> </select> ``` 步骤二:数据的获取与渲染 当用户选择省份时,应该从json文件中获取相关联的城市数据。同样,当用户选择城市时,应该从json文件中获取相关联的区县数据。获取数据需要使用ajax,具体代码如下所示: ``` $(function() { $.ajax({ url: 'data.json', // 数据的文件路径 success: function(data) { // 渲染省份下拉框 var provinces = data.provinces; var $province = $('#province'); for(var i = 0; i < provinces.length; i++) { $province.append('<option value="' + provinces[i].code + '">' + provinces[i].name + '</option>'); } // 渲染城市下拉框 $province.change(function() { var code = $(this).val(); var cities = data[code]; var $city = $('#city'); $city.children().not(':first').remove(); $('#area').children().not(':first').remove(); for(var i = 0; i < cities.length; i++) { $city.append('<option value="' + cities[i].code + '">' + cities[i].name + '</option>'); } }); // 渲染区县下拉框 $city.change(function() { var code = $(this).val(); var areas = data[code]; var $area = $('#area'); $area.children().not(':first').remove(); for(var i = 0; i < areas.length; i++) { $area.append('<option value="' + areas[i].code + '">' + areas[i].name + '</option>'); } }); } }); }); ``` 其中,我们给省、市、区个下拉框分别绑定了change事件,当用户选择下拉框中的一项时,其它两个下拉框的内容应该跟着自动更新。 步骤:数据的格式化 最后是准备json数据的工作。要实现省市区三级联动,你需要将数据格式化为以下的形式: ``` { "provinces": [ { "name": "北京市", "code": 11 }, { "name": "上海市", "code": 31 }, ... ], "11": [ { "name": "北京市", "code": 1101 }, { "name": "朝阳区", "code": 110101 }, ... ], ... } ``` 其中,provinces是省份数据,11、31等是省份对应的城市数据,1101,110101等是城市对应的区县数据。这样,当用户选择一个省份时,可以根据省份的code来获取对应的城市数据。当用户选择一个城市时,可以根据城市的code来获取区县数据。 总结 至此,我们通过ajax和json实现了一个省市区三级联动的功能。通过以上的步骤,不仅可以实现联动菜单,而且还可以使用户体验更加顺畅、友好。在实际开发中,我们可以根据以上的代码对数据的格式和渲染方式进行修改,以满足实际需求。 ### 回答3: 省市区三级联动是Web开发中比较常见而又较为复杂的一个功能实现。一般情况下,页面展示的省市区数据是从后端数据库中读取出来后动态生成的,而前端主要负责用户数据的收集和展示。传统的实现方式是使用JavaScript获取前端页面上的省市区选择器对应的DOM对象,然后将DOM对象和后端数据通过DOM操作和HTML模板渲染将所有的相关信息动态展示出来。 而ajax和json的出现,使得前端页面和后端数据交互变得更加高效和稳定。 AJAX能够帮助我们实现前后端数据的异步交互,而JSON则能够很好地解决数据格式的问题,使得前后端交互数据的传输更加方便、快捷和可靠。 基于ajax和json实现省市区三级联动,一般需要完成以下几个步骤: 1. 后端数据获取:使用后端编程语言(如PHP或Java)从数据库中获取对应的省市区相关数据,并以json格式返回给ajax方法的调用。 2. 数据展示:在前端页面中,获取每一个省、市、区的选择器DOM对象,并在DOM对象中注入相应的HTML代码(一般是通过使用HTML模板),以达到展示数据的目的。 3. 添加事件监听:在选择器DOM对象上添加事件监听器(如change事件),一旦有新的选择,则触发ajax方法向后台请求新的相关数据,再将新数据注入到省市区DOM对象中。 4. 数据交互:利用ajax方法向后台请求数据,并将数据以json格式返回到前端页面,再将数据转换为javascript对象,以方便使用使用ajax和json实现省市区三级联动,可以使得前后端交互数据的传输更加方便、快捷和可靠。同时,使用ajax和json实现三级联动功能可以避免掉传统方法中一些不必要、浪费流量的数据请求,缩短数据的传输时间和节省用户的流量,提高用户的感知体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值