Android趣味课程:简易天气预报功能

在某些应用程序中,经常有天气预报的功能,通过当地天气情况给予用户合适的建议。比如团购网站根据定位,天气推送用户需要的信息等。本篇博客会使用公共api当中天气预报接口信息,编写一个简易天气预报的界面。

获取天气信息接口如下:

http://api.map.baidu.com/telematics/v3/weather?location=九江&output=json&ak=FkPhtMBK0HTIQNh7gG4cNUttSTyr0nzo

可替换location对应的地址,比如改变location=九江为location=北京,及可以获取北京的天气情况与指数建议。

最终显示界面如下:

Android趣味课程:简易天气预报功能_第1张图片       Android趣味课程:简易天气预报功能_第2张图片

这里我针对已有接口中提供的信息,简易布局内容,查看上图,包括控件有:Toolbar,ListView,Spinner以及一些简单组件。接下来,我们就根据这个布局完成相关功能:

首先完成activity对应的布局界面编写:activity_forecast.xml



    
    
    
    
    
    
    

观察发现,这里涉及到listview和spinner,所以需要编写每一个item的布局,我先编写listview对应的布局:item_forecast_lv.xml



    
    
    
    

接下来编写spinner下拉列表对应的item的布局内容,在下拉列表的item中主要用于显示温度,风向等信息。item_forecast_sp.xml内容为:



    
    
    
    
    
        
        
        
        

    
    

至此,界面对应的所有布局都完成了。在开始编写代码前,我们需要首先明确需要用到哪些包或者依赖,倒入到当前app的build.gradle文件当中。此处我在libs文件夹中添加了gson用于解析数据,picasso用于加载网络图片,当然也可通过compile直接倒入,我在build.gradle用添加了这两个包对应的添加文件信息:

Android趣味课程:简易天气预报功能_第3张图片

然后我们就开始正式分析需求,编写逻辑代码了:

1.获取接口内容,分析json数据格式,编写对应的java bean类,用于方便存储和获取其对应的信息。

2.编写listview和spinner对应的适配器信息,将布局加载为view对象,显示在每一个item格式当中。继承BaseAdapter类。

3.在主页面中为复杂视图设置起对应的适配器。并且进行网络加载,将获取并解析后的数据显示在适配器视图中。

根据以上布局进行编写,相信功能就能很快完成了~我们试一下!

分析接口数据,并生成bean类。

Android趣味课程:简易天气预报功能_第4张图片

整体看为一个对象,包括4个属性,其中需要重点为results对应的数组容器,在向下分析,这个容器中只有一个对象,而这个对象中有包括4个属性,我们需要重点注意的包括数据index为天气指数信息,weather_data为每天的天气情况信息,currentcity为当前查询城市,pm25为空气质量情况。故生成bean类如下:

import java.util.List;
public class ForecastBean {
    private int error;
    private String status;
    private String date;
    private List results;
    public int getError() {
        return error;
    }
    public void setError(int error) {
        this.error = error;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    public String getDate() {
        return date;
    }
    public void setDate(String date) {
        this.date = date;
    }
    public List getResults() {
        return results;
    }
    public void setResults(List results) {
        this.results = results;
    }
    public static class ResultsBean {
        /**
         * currentCity : 九江
         * pm25 : 105
         * index : [{"des":"天气炎热,建议着短衫、短裙、短裤、薄型T恤衫等清凉夏季服装。","zs":"炎热","tipt":"穿衣指数","title":"穿衣"},{"des":"较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。","zs":"较适宜","tipt":"洗车指数","title":"洗车"},{"des":"各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。","zs":"少发","tipt":"感冒指数","title":"感冒"},{"des":"天气较好,户外运动请注意防晒,推荐您在室内进行低强度运动。","zs":"较适宜","tipt":"运动指数","title":"运动"},{"des":"紫外线辐射极强,建议涂擦SPF20以上、PA++的防晒护肤品,尽量避免暴露于日光下。","zs":"很强","tipt":"紫外线强度指数","title":"紫外线强度"}]
         * weather_data : [{"date":"周一 06月11日 (实时:32℃)","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/qing.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/qing.png","weather":"晴","wind":"南风微风","temperature":"32 ~ 21℃"},{"date":"周二","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多云","wind":"南风微风","temperature":"29 ~ 21℃"},{"date":"周三","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多云","wind":"南风微风","temperature":"29 ~ 21℃"},{"date":"周四","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/qing.png","weather":"多云转晴","wind":"东北风微风","temperature":"30 ~ 21℃"}]
         */
        private String currentCity;
        private String pm25;
        private List index;
        private List weather_data;
        public String getCurrentCity() {
            return currentCity;
        }
        public void setCurrentCity(String currentCity) {
            this.currentCity = currentCity;
        }
        public String getPm25() {
            return pm25;
        }
        public void setPm25(String pm25) {
            this.pm25 = pm25;
        }
        public List getIndex() {
            return index;
        }
        public void setIndex(List index) {
            this.index = index;
        }
        public List getWeather_data() {
            return weather_data;
        }
        public void setWeather_data(List weather_data) {
            this.weather_data = weather_data;
        }
        public static class IndexBean {
            /**
             * des : 天气炎热,建议着短衫、短裙、短裤、薄型T恤衫等清凉夏季服装。
             * zs : 炎热
             * tipt : 穿衣指数
             * title : 穿衣
             */

            private String des;
            private String zs;
            private String tipt;
            private String title;
            public String getDes() {
                return des;
            }
            public void setDes(String des) {
                this.des = des;
            }
            public String getZs() {
                return zs;
            }
            public void setZs(String zs) {
                this.zs = zs;
            }
            public String getTipt() {
                return tipt;
            }
            public void setTipt(String tipt) {
                this.tipt = tipt;
            }
            public String getTitle() {
                return title;
            }
            public void setTitle(String title) {
                this.title = title;
            }
        }
        public static class WeatherDataBean {
            /**
             * date : 周一 06月11日 (实时:32℃)
             * dayPictureUrl : http://api.map.baidu.com/images/weather/day/qing.png
             * nightPictureUrl : http://api.map.baidu.com/images/weather/night/qing.png
             * weather : 晴
             * wind : 南风微风
             * temperature : 32 ~ 21℃
             */
            private String date;
            private String dayPictureUrl;
            private String nightPictureUrl;
            private String weather;
            private String wind;
            private String temperature;
            public String getDate() {
                return date;
            }
            public void setDate(String date) {
                this.date = date;
            }
            public String getDayPictureUrl() {
                return dayPictureUrl;
            }
            public void setDayPictureUrl(String dayPictureUrl) {
                this.dayPictureUrl = dayPictureUrl;
            }
            public String getNightPictureUrl() {
                return nightPictureUrl;
            }
            public void setNightPictureUrl(String nightPictureUrl) {
                this.nightPictureUrl = nightPictureUrl;
            }
            public String getWeather() {
                return weather;
            }
            public void setWeather(String weather) {
                this.weather = weather;
            }
            public String getWind() {
                return wind;
            }
            public void setWind(String wind) {
                this.wind = wind;
            }
            public String getTemperature() {
                return temperature;
            }
            public void setTemperature(String temperature) {
                this.temperature = temperature;
            }
        }
    }
}

继续根据需求可知,我们需要在ListView的每一个item当中展示指数信息,即bean类当中的result集合的对象包括的index集合的信息,了解了数据源类型,我们就可以非常容易完成适配器部分:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
import com.animee.testinfo.R;
/**
 * 这是ListView的适配器
 */
public class IndexAdapter extends BaseAdapter{
    Context context;
//    listView的数据源
    List mDatas;
    public IndexAdapter(Context context, List mDatas) {
        this.context = context;
        this.mDatas = mDatas;
    }
    @Override
    public int getCount() {
        return mDatas.size();
    }
    @Override
    public Object getItem(int i) {
        return mDatas.get(i);
    }
    @Override
    public long getItemId(int i) {
        return i;
    }
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        IndexViewHolder holder = null;
        if (view==null) {
            view = LayoutInflater.from(context).inflate(R.layout.item_forecast_lv,null);
            holder = new IndexViewHolder();
            holder.titleTv = (TextView) view.findViewById(R.id.item_lv_tv_title);
            holder.zsTv = (TextView) view.findViewById(R.id.item_lv_tv_zs);
            holder.tiptTv = (TextView) view.findViewById(R.id.item_lv_tv_tipt);
            holder.desTv = (TextView) view.findViewById(R.id.item_lv_tv_des);
            view.setTag(holder);
        }else{
            holder = (IndexViewHolder) view.getTag();
        }
        ForecastBean.ResultsBean.IndexBean indexBean = mDatas.get(i);
        holder.titleTv.setText(indexBean.getTitle());
        holder.zsTv.setText(indexBean.getZs());
        holder.desTv.setText(indexBean.getDes());
        holder.tiptTv.setText(indexBean.getTipt());
        return view;
    }
    class IndexViewHolder{
        TextView titleTv,zsTv,tiptTv,desTv;
    }
}

同理,我们可知需要在spinner的每一个item当中展示指数信息,即bean类当中的result集合的对象包括的weather_data集合的信息,了解了数据源类型,我们同样可以非常容易完成适配器部分:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.animee.testinfo.R;
import com.squareup.picasso.Picasso;
import java.util.List;
public class WeatherAdapter extends BaseAdapter{
    Context context;
//    Spinner的数据源
    List mDatas;

    public WeatherAdapter(Context context, List mDatas) {
        this.context = context;
        this.mDatas = mDatas;
    }
    @Override
    public int getCount() {
        return mDatas.size();
    }
    @Override
    public Object getItem(int i) {
        return mDatas.get(i);
    }
    @Override
    public long getItemId(int i) {
        return i;
    }
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        WeatherViewHolder holder = null;
        if (view==null) {
            view = LayoutInflater.from(context).inflate(R.layout.item_forecast_sp,null);
            holder = new WeatherViewHolder();
            holder.dayIv = (ImageView) view.findViewById(R.id.item_sp_iv_day);
            holder.nightIv = (ImageView) view.findViewById(R.id.item_sp_iv_night);
            holder.dateTv = (TextView) view.findViewById(R.id.item_sp_tv_date);
            holder.tempTv = (TextView) view.findViewById(R.id.item_sp_tv_temp);
            holder.weatherTv = (TextView) view.findViewById(R.id.item_sp_tv_weather);
            holder.windTv = (TextView) view.findViewById(R.id.item_sp_tv_wind);
            view.setTag(holder);
        }else{
            holder = (WeatherViewHolder) view.getTag();
        }
        ForecastBean.ResultsBean.WeatherDataBean bean = mDatas.get(i);
        holder.dateTv.setText(bean.getDate());
        holder.tempTv.setText(bean.getTemperature());
        holder.windTv.setText(bean.getWind());
        holder.weatherTv.setText(bean.getWeather());
//      使用Picasso加载白天图片和夜晚图片
        Picasso.with(context).load(bean.getDayPictureUrl()).into(holder.dayIv);
        Picasso.with(context).load(bean.getNightPictureUrl()).into(holder.nightIv);
        return view;
    }
    class WeatherViewHolder{
        ImageView dayIv,nightIv;
        TextView dateTv,tempTv,weatherTv,windTv;
    }
}

前面的铺垫已经完毕,我们正式进入正题,开始编写activity对应代码,设置适配器视图的信息,以及获取网络数据,通知其更新信息。获取网络数据,这里我使用原生的HttpURLConnection,先封装一下工具类:

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class HttpUtils {
    public static String getJsonContent(String path){
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            InputStream is = conn.getInputStream();
            int hasRead = 0;
            byte[]buf = new byte[1024];
            while ((hasRead = is.read(buf))!=-1){
                baos.write(buf,0,hasRead);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return baos.toString();
    }
}

接下来就可以代入到使用当中:

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.WindowDecorActionBar;
import android.view.Window;
import android.widget.ListView;
import android.widget.Spinner;
import com.animee.testinfo.R;
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;
public class ForecastActivity extends AppCompatActivity {
    private Spinner spinner;
    private ListView listView;
//    ListView的数据源
    private List indexList = new ArrayList<>();
//    Spinner的数据源
    private List weather_dataList = new ArrayList<>();
    private IndexAdapter indexAdapter;
    private WeatherAdapter weatherAdapter;

    public String url = "http://api.map.baidu.com/telematics/v3/weather?location=九江&output=json&ak=FkPhtMBK0HTIQNh7gG4cNUttSTyr0nzo";
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what==1) {
                String s = (String) msg.obj;
//                使用Gson进行解析
                Gson gson = new Gson();
                ForecastBean forecastBean = gson.fromJson(s, ForecastBean.class);
                ForecastBean.ResultsBean resultsBean = forecastBean.getResults().get(0);
//              获取ListView的解析数据,然后添加到数据源当中,提示更新
                List index = resultsBean.getIndex();
                indexList.addAll(index);
                indexAdapter.notifyDataSetChanged();
//              获取Spinner解析后的数据,添加到数据源当中,提示更新
                List data = resultsBean.getWeather_data();
                weather_dataList.addAll(data);
                weatherAdapter.notifyDataSetChanged();
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_forecast);
//        查找控件
        spinner = (Spinner) findViewById(R.id.forecast_sp);
        listView = (ListView) findViewById(R.id.forecast_lv);
//        获取数据源
//        创建适配器对象
        indexAdapter = new IndexAdapter(this,indexList);
        listView.setAdapter(indexAdapter);

        weatherAdapter = new WeatherAdapter(this,weather_dataList);
        spinner.setAdapter(weatherAdapter);
//     联网获取数据
        loadData();
    }
    private void loadData() {
        new Thread(new Runnable() {
            @Override
            public void run() {
//                联网获取数据的步骤·
                String content = HttpUtils.getJsonContent(url);
                Message msg = new Message();
                msg.what = 1;
                msg.obj = content;
                handler.sendMessage(msg);
            }
        }).start();
    }
}

最后一定要记得在清单文件当中注册activity,并且添加网络权限哦!

Android趣味课程:简易天气预报功能_第5张图片

然后运行一下,就会发现简单天气预报功能实现了,当然你也可以更改地区信息,可让用户输入相关地区,或者使用定位功能,获取用户当前位置,然后查找对应天气情况,推送信息给使用者,大家可以尝试一下。感谢您的阅读!

你可能感兴趣的:(Android学习笔记)