Android实战(天气查询+网络通讯)

我的MOOC课基本结束了,学校要求做的最后一讲是做一个天气查询软件。

完整项目代码地址:

https://github.com/AbitGo/mybatis_csdn/tree/master/workspace_as_mooc25

1.软件思路

  1. 使用提供的API,并实现HTTP通讯
  2. 可以通过省、市区(包括直辖市)查询
  3. 可以通过spinner实现下拉选择

2.实验现象

3.实验步骤

3.1API选择

在本文中使用的是中国天气网的API,以下是网址

https://m.weather.com.cn/d/town/index?lat=31.29834&lon=120.58319&areaid=101190401

 3.2获得省/直辖市API

http://www.weather.com.cn/data/city3jdata/china.html

3.3获得市API

http://www.weather.com.cn/data/city3jdata/provshi/10109.html

 3.3获得天气API

在这里说明:本问要求使用市作为最小单位,例如常州市、苏州市而非江阴、溧阳等。

 

非直辖市
需要进行上面的省ID+市区ID+01获得

直辖市则与直辖市不一样,因为直辖市在获取省的时候只有一个返回参数00:

http://www.weather.com.cn/data/sk/101010100.html

使用获取天气APi需要区别直辖与非直辖

这是北京

这是江苏南京

从中看出两者区别在于cityid的位置摆放不一致。

3.4应用网络通讯权限

在AndroidManifest.xml中添加以下代码。

<uses-permission android:name="android.permission.INTERNET" />

3.5外部库

在gradle的dependencies中添加

implementation 'com.squareup.okhttp3:okhttp:3.14.2'
implementation 'com.alibaba:fastjson:1.1.71.android'

3.6HTTP调用

 详细代码可以看最后

实验注意点

  1. 调用外部类需要导入gradle
  2. 不可以再HTTP通讯代码中写改变UI的代码
  3. 调用API需要注意直辖市与非直辖市的区别

 

所有源码

MainActivity.java

package com.example.mooc25hw;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {
    private Spinner spinner_prov,spinner_city;
    private TextView textView;
    private LinearLayout linearLayout;
    private OkHttpUtils okHttpUtils;

    //作为省的初始ID
    private String provinceId = "10101";
    private String cityID = "01";

    //作为省名字的数组
    private Map<String,String> provinceMap= new HashMap<>();
    private ArrayList<String> provinceArray=new ArrayList<>();

    //作为市区名字的数组
    private Map<String,String> cityMap = new HashMap<>();
    private ArrayList<String> cityArray = new ArrayList<>();

    //获取省的HTTP请求链接
    final String searchPorvURI = "http://www.weather.com.cn/data/city3jdata/china.html";
    //获取市区的HTTP请求
    //需要使用 searchCityURI+provionceID+searchCityURI_suffix进行请求
    final String searchCityURI = "http://www.weather.com.cn/data/city3jdata/provshi/";
    final String searchCityURI_suffix = ".html";

    final String searchWeatherURI = "http://www.weather.com.cn/data/sk/";
    final String searchWeatherURI_suffix = ".html";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        initView();
        //进行省的HTTP即可
        getHTTPLink(searchPorvURI,0);
    }

    /**
     * 名称:获取HTTP连接
     * 参数:URI获取JSON的链接、operateId为操作码
     * 返回值:无
     */
    public void getHTTPLink(String URI,int operateId){
        //获得初始化之后的Https连接
        okHttpUtils = OkHttpUtils.getInstance();
        okHttpUtils.getRequest(URI, new Callback() {
            //无操作
            @Override
            public void onFailure(Call call, IOException e) {}

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String json = response.body().string();
                switch (operateId){
                    case 0:
                        //讲数据传输至省数据更新函数
                        UpdateProvinceData(json);
                        break;
                    case 1:
                        UpdateCityData(json);
                        break;
                    case 2:
                        UpdateWeatherData(json);
                        break;
                }
            }
        });
    }
    /***
     * 名称:更新所在市区的天气
     * 参数:HTTP传回的JSON数据
     * 返回值:无
     * 功能说明:通过解析JSON更新市区天气数据
     * @param JsonData
     * "weatherinfo": {
     *         "city": "上海",
     *         "cityid": "101020100",
     *         "temp": "23.5",
     *         "WD": "东北风",
     *         "WS": "小于3级",
     *         "SD": "80%",
     *         "AP": "1006.4hPa",
     *         "njd": "2903",
     *         "WSE": "<3",
     *         "time": "17:00",
     *         "sm": "1.1",
     *         "isRadar": "1",
     *         "Radar": "JC_RADAR_AZ9210_JB"
     *     }
     */
    public void UpdateWeatherData(String JsonData){
        runOnUiThread(() -> {
            try {
                //进行JSON数据的反序列化
                JSONObject param1 = JSONObject.parseObject(JsonData);
                JSONObject param2 =JSONObject.parseObject(param1.get("weatherinfo").toString());
                String result = "城市:"+param2.getString("city")+"\n"
                        +"温度:"+param2.getString("temp")+"\n"
                        +"湿度:"+param2.getString("SD")+"\n"
                        +"气压:"+param2.getString("AP")+"\n"
                        +"天气:"+param2.getString("WD")+"\n";
                textView.setText(result);

            } catch (JSONException e) {
                Toast.makeText(MainActivity.this,"JSON解析失败",Toast.LENGTH_SHORT).show();
            }
        });
    }


    /***
     * 名称:更新市区信息
     * 参数:HTTP传回的JSON数据
     * 返回值:无
     * 功能说明:通过解析JSON更新市区数据
     * @param JsonData {"01": "南京","02": "无锡"}
     */
    public void UpdateCityData(String JsonData){
        runOnUiThread(() -> {
            try {
                //进行JSON数据的反序列化
                JSONObject param = JSONObject.parseObject(JsonData);
                //将CityID编号提取出来
                Set<String> cityKey = param.keySet();
                Toast.makeText(MainActivity.this,"JSON市区信息获取成功",Toast.LENGTH_SHORT).show();
                //数据更新,防止省的市区进行叠加
                cityArray.clear();
                cityMap.clear();
                for(String key:cityKey){
                    //将数据以key:provinceName存储至provinceList
                    String cityName = param.getString(key);
                    cityMap.put(cityName,key);
                    cityArray.add(cityName);
                }
                //进行适配器的操作
                ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_dropdown_item_1line, cityArray);
                spinner_city.setAdapter(arrayAdapter);
            } catch (JSONException e) {
                Toast.makeText(MainActivity.this,"JSON解析失败",Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * 名称:更新省信息
     * 参数:HTTP传回的JSON数据
     * 返回值:无
     * 功能说明:通过解析JSON信息更逊省信息
     * @param JsonData JSON数据 {"10101": "北京","10102": "上海"}
     */
    public void UpdateProvinceData(String JsonData){
        runOnUiThread(() -> {
            try {
                //进行JSON数据的反序列化
                JSONObject param = JSONObject.parseObject(JsonData);
                //将ProvinceID编号提取出来
                Set<String> provinceKey = param.keySet();
                Toast.makeText(MainActivity.this,"JSON省信息获取成功",Toast.LENGTH_SHORT).show();

                for(String key:provinceKey){
                    //将数据以key:provinceName存储至provinceList
                    String provinceName = param.getString(key);
                    provinceMap.put(provinceName,key);
                    provinceArray.add(provinceName);
                }
                //进行适配器的操作
                ArrayAdapter arrayAdapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_dropdown_item_1line, provinceArray);
                spinner_prov.setAdapter(arrayAdapter);
            } catch (JSONException e) {
                Toast.makeText(MainActivity.this,"JSON解析失败",Toast.LENGTH_SHORT).show();
            }
        });
    }



    /**
     * 名称:组件初始化函数
     * 参数:无
     * 返回值:无
     */
    public void initView(){
        spinner_city = findViewById(R.id.spiner1_city);
        spinner_prov = findViewById(R.id.spiner1_province);
        textView = findViewById(R.id.tv_weather);
        linearLayout = findViewById(R.id.bg_control);

        //设定spinner_prov的点击事件
        spinner_prov.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                //获取比如    "北京"的省名称,并获得于此对应的ProvinceID
                provinceId = provinceMap.get(parent.getItemAtPosition(position).toString());
                getHTTPLink(searchCityURI+provinceId+searchCityURI_suffix,1);
            }

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

        spinner_city.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                //获取比如    "北京"的市区名称,并获得于此对应的CityID
                String cityName = parent.getItemAtPosition(position).toString();
                //直辖市以及非直辖市的获取区别需要重视
                cityID = cityMap.get(cityName);
                //通过拼接的方式进行所在市区的天气查询
                //直辖市=searchWeatherURI+"01"+cityID+searchWeatherURI_suffix
                //非直辖市=searchWeatherURI+cityID+"01"+searchWeatherURI_suffix
                String link = "";
                if(cityName.equals("北京")||cityName.equals("上海")||cityName.equals("重庆")||cityName.equals("天津")){
                    link = searchWeatherURI+provinceId+"01"+cityID+searchWeatherURI_suffix;
                    getHTTPLink(link,2);
                }else{
                    link=searchWeatherURI+provinceId+cityID+"01"+searchWeatherURI_suffix;
                    getHTTPLink(link,2);
                }
                Toast.makeText(MainActivity.this,link,Toast.LENGTH_SHORT).show();

            }

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


}

工具类:

package com.example.mooc25hw;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * create by zy on 08/25/19
 */
public class FastJsonUtil {
    //take json format data to java bean
    public static <T> T toBean(String jsonData, Class<T> tClass) {
        return JSON.parseObject(jsonData, tClass);
    }
    //take arbitrary object to json format data
    public static String ToJson(Object obj) {
        return JSON.toJSONString(obj);
    }
    //get json string one of single values
    public static Object getSingleValue(String jsonData, String key) {
        JSONObject jsonObject = JSONObject.parseObject(jsonData);
        return jsonObject.get(key);
    }
    //get multiple values in the json string
    public static List<String> getValue(String jsonData, String...key){
        List<String> jsonList = new ArrayList<>();
        JSONObject jsonObject = JSONObject.parseObject(jsonData);
        for (int i = 0; i < key.length; i ++){
            jsonList.add(String.valueOf(jsonObject.get(key[i])));
        }
        return jsonList;
    }
    //take json string to Java List Array
    public static <T> List<T> toList(String jsonData, Class<T> tClass) {
        return JSON.parseArray(jsonData, tClass);
    }
    //take json string to Java Map Array
    public static Map<String, Object> toMap(String jsonData){
        return JSON.parseObject(jsonData,new TypeReference<Map<String, Object>>(){});
    }
    //take json string to List<Map<String,Object>> Array
    public static List<Map<String, Object>> toListMap(String jsonData){
        return JSON.parseObject(jsonData,new TypeReference<List<Map<String, Object>>>(){});
    }
}
package com.example.mooc25hw;

import android.util.Log;

import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;

/**
 * create by zy on 08/22/2019
 * consult zhy OkHttpUtils
 */
public class OkHttpUtils {

    private volatile static OkHttpUtils mInstance;

    private OkHttpClient mokHttpClient;

    public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    public OkHttpUtils(OkHttpClient okHttpClient) {
        if (okHttpClient == null) {
            mokHttpClient = new OkHttpClient();
        } else {
            mokHttpClient = okHttpClient;
        }
    }

    public static OkHttpUtils initClient(OkHttpClient okHttpClient) {
        if (mInstance == null) {
            synchronized (OkHttpUtils.class) {
                if (mInstance == null) {
                    mInstance = new OkHttpUtils(okHttpClient);
                }
            }
        }
        return mInstance;
    }

    public static OkHttpUtils getInstance() {
        return initClient(null);
    }

    /**
     * Get Request
     *
     * @param getUrl   request url(get)
     * @param callback callback interface by okHttp
     */
    public void getRequest(String getUrl, final Callback callback) {
        new Thread(() -> {
            Request request = new Request.Builder()
                    .url(getUrl)
                    .build();
            mokHttpClient.newCall(request).enqueue(callback);
        }).start();
    }

    /**
     * POST Request
     *
     * @param data     afferent json data we can be afferent Map List pojo...
     * @param postUrl  request url(post)
     * @param callback callback interface by okHttp
     */
    public void postRequest(final Object data, String postUrl, final Callback callback) {
        new Thread(() -> {
            String json = FastJsonUtil.ToJson(data);
            Log.d("Send Json -->",json);
            RequestBody body = RequestBody.create(JSON, json);
            Request request = new Request.Builder()
                    .url(postUrl)
                    .post(body)
                    .build();
            mokHttpClient.newCall(request).enqueue(callback);
        }).start();
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/bg_control"
    android:orientation="vertical"
    android:background="@color/sun"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:paddingTop="20dp"
        android:paddingLeft="20dp"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
        <Spinner
            android:paddingLeft="20dp"
            android:layout_weight="1"
            android:id="@+id/spiner1_province"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
        </Spinner>
        <Spinner
            android:layout_weight="1"
            android:paddingLeft="20dp"
            android:id="@+id/spiner1_city"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"></Spinner>
    </LinearLayout>
    <TextView
        android:paddingLeft="20dp"
        android:paddingTop="20dp"
        android:text="天气"
        android:textSize="30dp"
        android:id="@+id/tv_weather"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />


</LinearLayout>

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值