[Android | 小代码] 天气预报 简易Demo json解析数组+对象 Gson+Volley简单使用

来源:互联网 发布:淘宝买家版下载 编辑:程序博客网 时间:2024/06/05 11:48

2016年9月22日 课上小练习,使用spinner选择地区。加载Assets/citycode.json中地区所对应代码。然后根据Api在线加载天气信息。很简单,重点在于Json对象与数组混合,分层解析就好。以及Volley框架的使用。

新增了源代码下载。

本App为小练习,所以使用了Spinner选择地区,而没有使用Activity来更好的显示。请忽略这一点。图片从墨迹天气里截取的。

这里写图片描述

AndroidManifest.xml中 配置volley Application。会使用更方便些 ↓

<application        android:name=".AppController"        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:supportsRtl="true"        android:theme="@style/AppTheme">        //...Activity 标签<application/>

AppController 简单封装volley ↓

/** * Created by lic on 2016/9/22. */public class AppController extends Application {    public static final String TAG = AppController.class            .getSimpleName();    private RequestQueue mRequestQueue;    private ImageLoader mImageLoader;    private static AppController mInstance;    @Override    public void onCreate() {        super.onCreate();        mInstance = this;    }    public static synchronized AppController getInstance() {        return mInstance;    }    public RequestQueue getRequestQueue() {        if (mRequestQueue == null) {            mRequestQueue = Volley.newRequestQueue(getApplicationContext());        }        return mRequestQueue;    }    public ImageLoader getImageLoader() {        getRequestQueue();        //如果不用图片加载,可以不写        if (mImageLoader == null) {            mImageLoader = new ImageLoader(this.mRequestQueue,                    new LruBitmapCache());        }        return this.mImageLoader;    }    public <T> void addToRequestQueue(Request<T> req, String tag) {        // set the default tag if tag is empty        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);        getRequestQueue().add(req);    }    public <T> void addToRequestQueue(Request<T> req) {        req.setTag(TAG);        getRequestQueue().add(req);    }    public void cancelPendingRequests(Object tag) {        if (mRequestQueue != null) {            mRequestQueue.cancelAll(tag);        }    }}

LruBitmapCache volley图片加载类,如果不需要可以在上面注释掉 ↓

/** * Created by lic on 2016/9/22. */public class LruBitmapCache extends LruCache<String, Bitmap> implements        ImageLoader.ImageCache {    public static int getDefaultLruCacheSize() {        final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);        final int cacheSize = maxMemory / 8;        return cacheSize;    }    public LruBitmapCache() {        this(getDefaultLruCacheSize());    }    public LruBitmapCache(int sizeInKiloBytes) {        super(sizeInKiloBytes);    }    @Override    protected int sizeOf(String key, Bitmap value) {        return value.getRowBytes() * value.getHeight() / 1024;    }    @Override    public Bitmap getBitmap(String url) {        return get(url);    }    @Override    public void putBitmap(String url, Bitmap bitmap) {        put(url, bitmap);    }}

MainActivity

SpinnAsync 异步加载Spinner内容 ↓

public class SpinnAsync extends AsyncTask {        private Context context;        SpinnAsync(Context context) {            this.context = context;        }        @Override        protected Object doInBackground(Object[] params) {            try {                List<CityCode> result = new ArrayList<>();                InputStream in = context.getResources().getAssets().open("citycode.json");                int length = in.available();                byte[] buffer = new byte[length];                in.read(buffer);                String line = new String(buffer);                result = convertToBean(line);                return result;            } catch (Exception e) {                e.printStackTrace();            }            return null;        }        @Override        protected void onPostExecute(Object o) {            if (o == null) {                Toast("发生未知错误");                return;            }            List<CityCode>list = (List<CityCode>)o;            String[] cities=new String[list.size()];            for(int i=0;i<list.size();i++)                cities[i]=list.get(i).getCity();            cityCodeList = list;            ArrayAdapter adapter=new ArrayAdapter(context,android.R.layout.simple_spinner_item,cities);            adapter.setDropDownViewResource(android.R.layout.simple_list_item_single_choice);            spinner.setAdapter(adapter);            spinner.setSelection(getSpArg(),true);        }    }

其中convertToBean 方法

public List<CityCode> convertToBean(String json) {        List<CityCode> result=new ArrayList<>();        try {            JSONObject obj = new JSONObject(json);            JSONArray jsons = obj.getJSONArray("城市代码");            for (int n = 0; n < jsons.length(); n++) {                JSONObject sheng = jsons.getJSONObject(n);                JSONArray shi = sheng.getJSONArray("市");                for (int i = 0; i < shi.length(); i++) {                    JSONObject rss = shi.optJSONObject(i);                    CityCode m = new CityCode();                    m.setCode(rss.getString("编码"));                    m.setCity(rss.getString("市名"));                    result.add(m);                }            }        }catch (JSONException e) {            e.printStackTrace();        }        return result;    }

volley联网 分层解析json

public void startHttp(String code) {        // Tag used to cancel the request        String tag = "json_obj_weather";        String api = "http://wthrcdn.etouch.cn/weather_mini?citykey=%s";        String url = String.format(api, code);        final ProgressDialog pDialog = new ProgressDialog(this);        pDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);        pDialog.setMessage("加载中...");        pDialog.setCanceledOnTouchOutside(false);        pDialog.show();        JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,url,                new Response.Listener<JSONObject>() {                    @Override                    public void onResponse(JSONObject response) {                        Log.d(TAG, "Success--------------" + response.toString());                        String result = null;//得到返回状态码                        try {                            result = response.getString("desc");                            if (result != null && result.equalsIgnoreCase("ok")) {//ok表示成功返回数据                                JSONObject jsonObject = response.optJSONObject("data");                                Gson gson = new Gson();                                Weather weather = gson.fromJson(jsonObject.toString(), Weather.class);                                JSONArray jsonArray = jsonObject.optJSONArray("forecast");                                if (jsonArray == null) {                                    pDialog.dismiss();                                    return;                                }                                List<Forecast> fList = gson.fromJson(jsonArray.toString(),                                        new TypeToken<List<Forecast>>(){}.getType());                                setWeatherView(weather, fList);                            }                        } catch (JSONException e) {                            e.printStackTrace();                        }                        pDialog.dismiss();                    }                },                new Response.ErrorListener() {                    @Override                    public void onErrorResponse(VolleyError error) {                        Log.d(TAG, "Error--------------" + error.getMessage());                        // hide the progress dialog                        pDialog.dismiss();                    }                }        );        // Adding request to request queue        AppController.getInstance().addToRequestQueue(jsonObjReq, tag);    }

↑ 先创建一个ProgressDialog ,然后再用Volley直接
AppController.getInstance().addToRequestQueue(jsonObjReq, tag); 就可以了很方便,不用考虑context。

让我们看看json请求的数据

{    "desc":"OK",    "status":"1000",    "data":{        "wendu":"21",        "ganmao":"虽然温度适宜但风力较大,仍较易发生感冒,体质较弱的朋友请注意适当防护。",        "forecast":[            {                "fengxiang":"南风",                "fengli":"4-5级",                "high":"高温 24℃",                "type":"晴",                "low":"低温 18℃",                "date":"22日星期四"            },            {                "fengxiang":"南风",                "fengli":"4-5级",                "high":"高温 24℃",                "type":"多云",                "low":"低温 19℃",                "date":"23日星期五"            },            {                "fengxiang":"南风",                "fengli":"4-5级",                "high":"高温 25℃",                "type":"多云",                "low":"低温 18℃",                "date":"24日星期六"            },            {                "fengxiang":"南风",                "fengli":"4-5级",                "high":"高温 25℃",                "type":"晴",                "low":"低温 19℃",                "date":"25日星期天"            },            {                "fengxiang":"南风",                "fengli":"4-5级",                "high":"高温 24℃",                "type":"小雨",                "low":"低温 20℃",                "date":"26日星期一"            }        ],        "yesterday":{            "fl":"4-5级",            "fx":"南风",            "high":"高温 24℃",            "type":"晴",            "low":"低温 17℃",            "date":"21日星期三"        },        "aqi":"128",        "city":"大连"    }}

↑ 其中返回的response是三层json对象,
先判断第一层”desc” 是否为”ok”

第二层数据JSONObject解析”data”数据,然后再用Gson

JSONObject jsonObject = response.optJSONObject(“data”);
Weather weather = gson.fromJson(jsonObject.toString(), Weather.class);

即可正确解析,但是这里有个坑。本APP使用的api,yesterday 字段有的地区会为空。所以做好判断。forecast 字段为数组,需要再次解析。

第三层数据为数组。依然需要使用Gson

JSONArray jsonArray = jsonObject.optJSONArray("forecast");if (jsonArray == null) {    pDialog.dismiss();    return;}List<Forecast> fList = gson.fromJson(jsonArray.toString(),        new TypeToken<List<Forecast>>(){}.getType());

然后就是设置view数据了 setWeatherView(weather, fList);

private void setWeatherView(Weather w, List<Forecast> list) {        if (w == null && list.size()==0 ) {            return;        }        Forecast f = list.get(0);        tv_weather.setText(f.getType());        tv_tempera.setText(f.getHigh()+" ~ "+f.getLow());        tv_info.setText(w.getGanmao());        switch (f.getType()) {            case "晴":                rLayout.setBackgroundResource(R.drawable.bg_sunny_day);                img1.setImageResource(R.drawable.w0);                break;            case "多云":                rLayout.setBackgroundResource(R.drawable.bg_fog_and_haze);                img1.setImageResource(R.drawable.w2);                break;            //.......... other case            //省略不写了,详情查看源代码            default:                if (f.getType().contains("霾")){                    rLayout.setBackgroundResource(R.drawable.bg_fog_and_haze);                    img1.setImageResource(R.drawable.w20);                }                rLayout.setBackgroundResource(R.drawable.bg_na);                img1.setImageResource(R.drawable.w45);                break;        }    }

使用SharedPreferences 来存储城市信息,每次启动保持一致

    /** 获取Preference Arg值     *     */    private int getSpArg() {        sp = getSharedPreferences("city_data", MODE_PRIVATE);        return sp.getInt("arg", 0);    }    /** 获取Preference 城市代码值     *     */    private String getSpCode() {        sp = getSharedPreferences("city_data", MODE_PRIVATE);        return sp.getString("code", "101010100");    }    /**放置Preferences     *     */    private void pushPreferences(String code, int arg) {        sp = getSharedPreferences("city_data", MODE_PRIVATE);        SharedPreferences.Editor editor = sp.edit();        editor.putString("code", code);        editor.putInt("arg", arg);        editor.apply();    }

源代码下载:传送门

1 0