省市区县三级联动,用json文件本地加载

这篇博客详细介绍了如何利用JSON文件实现移动端省市区县的三级联动效果。通过注释详细阐述了实现过程,包括如何将JSON数据加载到本地,并在应用中进行展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

所有的原理的说明都在注释里,按顺序看非常详细。

布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_height="match_parent">

    <Spinner
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight="1"
        android:id="@+id/sheng"
        android:background="#e7e8e9"></Spinner>

    <Spinner
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight="1"
        android:id="@+id/shi"
        android:background="#a92521"></Spinner>
    <Spinner
        android:layout_width="0dp"
        android:layout_height="50dp"
        android:layout_weight="1"
        android:id="@+id/qu"
        android:background="#615221"></Spinner>


</LinearLayout>

主程序:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import android.widget.TextView;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class MainActivity extends AppCompatActivity {

    private Spinner spinner_sheng,spinner_shi,spinner_qu;

    //全局的jsonObject
    private JSONObject jsonObject;//把全国的省市区的信息以json的格式保存,解析完成后赋值为null
    private String[] allProv;//所有的省
    private static final String TAG = "我想告诉你:";
    private ArrayAdapter<String> provinceAdapter;//省份数据适配器
    private ArrayAdapter<String> cityAdapter;//城市数据适配器
    private ArrayAdapter<String> areaAdapter;//区县数据适配器

    private String[] allSpinList;//在spinner中选出来的地址,后面需要用空格隔开省市区

    private String provinceName;//省的名字
    private String areaName;//区的名字

    private Map<String, String[]> cityMap = new HashMap<String, String[]>();
    //key:省p---value:市n  value是一个集合
    private Map<String, String[]> areaMap = new HashMap<String, String[]>();
    //key:市n---value:区s    区也是一个集合

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();//初始化Spinner按钮
        initJsonData();//初始化json数据,此方法用来打开json文件并且存储里面的内容到json对象
        initCityData();//现在city.json的所有内容都在jsonObject中,解析此对象;
        //上面这个方法运行后,我获得三个东西,一个是 allProv[]数组,里面存着所有的省,里面有34个数据
        //一个是 cityMap,里面存着的键值都是allProv[]里面的省,与键值相对应的是allCity[]数组,里面是这个省的市。共有34个键值。
        //还有一个是areaMap,里面的键值都是allCity[]里面的市,与键值相对应的是allArea[]数组,里面是这个省市的左右的区县,共有2766个键值

        //心得:属于json解析的已经完成了,其实解析json对象就那么一两个方法,但是得十分明白json数据的结构
        //才能在面对复杂的json对象时,从中获取全部的键值;接下来就是属于从Map中取值以及Spinner组件的使用方法啦

        setSpinnerData();//为spinner设置值
        //所谓的省市县三级联动,无非是靠三个嵌套完成的,整个过程是这样的:首先在页面启动的时候
        //执行spinner_sheng.setSelection(0);这个方法的效果跟点击Spinner的省按钮选择第一条一样,然后
        //然后执行省按钮的点击事件里的updateCity("北京", null);然后在updateCity方法里面执行updateArea(cities[0]);
        //默认显示第一个市。然后再在updateArea设置当存在县级单位时选择第一个;当选择省时只是spinner_sheng.setSelection()
        //方法执行时参数不是0罢了。因为你选择了省才会为你更新市的信息,选择了市才会为你更新县的消息,所以说这种嵌套是单向性的
    }

    private void setSpinnerData() {
        provinceAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);//系统默认的
        for (int i = 0; i < allProv.length; i++) {
            //给spinner省赋值,设置默认值
            provinceAdapter.add(allProv[i]);//添加每一个省
        }
        provinceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);//按下的效果
        spinner_sheng.setAdapter(provinceAdapter);
        spinner_sheng.setSelection(0);//设置选中的省,默认

        //市
        cityAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        cityAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner_shi.setAdapter(cityAdapter);

        //区县
        areaAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        areaAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner_qu.setAdapter(areaAdapter);

        setListener();//设置spinner的点击监听
    }

    private void setListener() {
        spinner_sheng.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                provinceName = adapterView.getSelectedItem() + "";//获取点击列表spinner item的省名字
                updateCity(provinceName, null);
                Log.i(TAG, "选择了:"+provinceName + "省");
            }

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

            }
        });

        spinner_shi.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                Log.i(TAG, "你点击了"+parent.getSelectedItem()+"市");
                updateArea(parent.getSelectedItem() + "");
            }

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

            }
        });

        spinner_qu.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                Log.i(TAG, "你点击了"+parent.getSelectedItem());
            }

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

            }
        });


    }


    private void updateCity(Object object, Object city) {
        String[] cities = cityMap.get(object);
        cityAdapter.clear();//清空adapter的数据
        for (int i = 0; i < cities.length; i++){
            cityAdapter.add(cities[i]);//将这个列表“市”添加到adapter中
        }
        Log.i(TAG, "这是"+object+"所有的市级行政单位");
        cityAdapter.notifyDataSetChanged();//刷新
        if (city == null) {
            updateArea(cities[0]);//更新区,没有市则默认第一个给它
        }
        //spinner_shi.setSelection(0);
    }

    private void updateArea(Object object) {
        String[] area = areaMap.get(object);
        areaAdapter.clear();//清空
        if (area != null) {
            for (int i = 0; i < area.length; i++){
                areaAdapter.add(area[i]);//填入到这个列表
            }
            areaAdapter.notifyDataSetChanged();//刷新
            Log.i(TAG, "这是"+String.valueOf(area)+"所有的县或区");
        }else {
            Log.i(TAG, String.valueOf(object)+"没有下一级行政单位");
        }
    }

    private void initCityData() {
        int x = 0;
        int q =0;
        try {
            //观察city.json你会发现(如果city.json你打开后是乱码,那就换一种编码方式):
            // 第1层       citylist
            //第2层     "p"          "c"
            //  第3层            "n"    "a"
            //   第4层                  "s"
            //citylist这个数组里面的包含的子项是一个键值"p"对应的省名和一个键值"c"对应的市或者区的
            //数组,其中c数组里面的键值"n"对应的是市名或者区名,"a"对应的是一个数组里面的子项"s"
            //均是县名,所以说初始化这个json对象时,其结构有三层最多需要遍历数组三次。取得时候只取每层
            //对应名字。比如说遍历第一层,只取p对应的value值就行啦;
            JSONArray jsonProv = jsonObject.getJSONArray("citylist");//获取整个json数据,就是获取
            // "p"的数量
            allProv = new String[jsonProv.length()];//封装数据
            for (int i = 0; i < jsonProv.length(); i++) {//遍历第一层数组,获取省
                JSONObject jsonP = jsonProv.getJSONObject(i);//jsonArray转jsonObject
                String provStr = jsonP.getString("p");//获取所有的省
                Log.i("guu", "现在是:"+provStr);
                allProv[i] = provStr;//封装所有的省
                JSONArray jsonCity = null;
                try {
                    jsonCity = jsonP.getJSONArray("c");//在所有的省中取出所有的市,转jsonArray
                    Log.i("guu", "现在取出"+provStr+"省的"+jsonCity);
                } catch (Exception e) {
                    continue;
                }
                //所有的市
                String[] allCity = new String[jsonCity.length()];//所有市的长度
                for (int c = 0; c < jsonCity.length(); c++) {//遍历第二层数组,获得“c”对应的市或区
                    JSONObject jsonCy = jsonCity.getJSONObject(c);//转jsonObject
                    String cityStr = jsonCy.getString("n");//取出所有的市
                    allCity[c] = cityStr;//封装市集合
                    Log.i("guu", "allCity["+c+"]="+cityStr);
                    JSONArray jsonArea = null;
                    x++;//我想知道这个json文件中记录了多少个市
                    try {
                        jsonArea = jsonCy.getJSONArray("a");//在从所有的市里面取出所有的区,转jsonArray
                    } catch (Exception e) {
                        Log.i(TAG, cityStr+"没有下一级行政单位");
                        continue;//如果市或者区这一层不能取出键值"a"的数组,说明没有,那么下面的
                        //for循环不搞了,直接进行本本层次的for循环;
                    }
                    String[] allArea = new String[jsonArea.length()];//所有的区
                    for (int a = 0; a < jsonArea.length(); a++) {//遍历第三层数组,取出所有的区
                        JSONObject jsonAa = jsonArea.getJSONObject(a);
                        String areaStr = jsonAa.getString("s");//获取所有的区
                        allArea[a] = areaStr;//封装起来
                        q++;//我想知道这个json文件中记录了多少个省
                    }
                    areaMap.put(cityStr, allArea);//第三层数组被遍历结束后某个市取出所有的区集合
                    //假如现在是刚遍历完淄博市的所有区县,那么这个cityStr键值对应的名字就是“淄博市”
                    //allArea里面所存储的就是淄博市所有的区县的名称
                }//这个第二层for循环跑起来时,每次都会执行 String[] allArea = new String[jsonArea.length()];
                //全中国有多少市就会执行多少次,有多少县或者县级区就会创建多少个String型变量。
                cityMap.put(provStr, allCity);//第二层数组被遍历结束后某个省取出所有的市,
                Log.i(TAG, "中国有"+i+"个省");
            }//这个第一层for循环跑起来时,每次都会执行 allProv = new String[jsonProv.length()];
            //全中国有多少省加上直辖市就会执行多少次,有多少市或者市级区就会创建多少个String型变量。
            //第一层数组遍历结束
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Log.i("guu", "中国有"+x+"个市;有"+q+"个区县");
        jsonObject = null;//清空所有的数据
    }

    private void initJsonData() {
        try {
            StringBuffer sb = new StringBuffer();
            InputStream is = getAssets().open("city.json");//打开json数据
            Log.i("guu", "打开city.json文件夹");
            byte[] by = new byte[is.available()];//转字节
            int len = -1;
            while ((len = is.read(by)) != -1) {
                sb.append(new String(by, 0, len, "gb2312"));//根据字节长度设置编码
            }
            is.close();//关闭流
            jsonObject = new JSONObject(sb.toString());//创建json对象,内容为整个city.json的值
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initView() {
        spinner_sheng = (Spinner) findViewById(R.id.sheng);
        spinner_shi = (Spinner) findViewById(R.id.shi);
        spinner_qu = (Spinner) findViewById(R.id.qu);
    }
}

我把源码放在这里了:下载后需要解压这个文件然后导入city.json到assets文件里,怎么导入我就不说了;点击打开链接

导入后是这个样子的:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值