Android项目实践(三)——天气预报APP

本文详细介绍了如何开发一个Android天气预报应用,包括查询天气、添加关注功能、区域选择功能的设计,以及界面布局和数据库操作。应用使用了高德API获取数据,通过Gson解析JSON,使用SQLite存储用户关注的城市信息。同时,文章提供了网络请求的实现和权限配置,以及整体框架的参考来源和GitHub链接。
摘要由CSDN通过智能技术生成

关于Android制作天气预报APP的几点建议

1.功能实现和界面展示

1.查询天气功能:通过输入地区的adcode码(后续有机会做一下通过输入地区)查询天气情况;
2.添加关注功能:对于某个县级行政区域,可以在其天气界面点击关注,之后在“我的关注”里可以进行查看;
3.区域选择功能:省、市、县三级行政区域可以分层点击,在县级行政区域点击之后,跳转到此地区的天气情况界面。
4.界面展示:
(1)主界面:
在这里插入图片描述
(2)“我的关注”界面:
在这里插入图片描述
(3)天气情况界面:
在这里插入图片描述

2.界面分布

1.对于天气预报APP,首先需要思考清楚需要几个Activity或者碎片:
(1)主页面(MainActivity):在主页面需要放置搜索输入框、搜索按钮,以及三级行政区域,而三级行政区域是靠碎片来实现的;
(2)碎片(ChooseAreaFragment):碎片定义包含了三级行政区域列表,上一级行政区域点击会进入到下一级,最后一级行政区域点击会跳转到此地的天气情况界面;
(3)天气情况界面(WeatherActivity):通过查询或者三级列表点击,进入到天气情况界面,包含温度、湿度、当前时间等信息,以及“关注”按钮、“取消关注”按钮、“返回主页面”按钮、“刷新”按钮;
(4)关注列表界面(MyConcernList):这个界面是所关注的城市,通过点击列表的城市,进入到所对应的天气情况界面。

3.关注城市的存储

在某个城市的天气显示情况界面,点击关注之后,需要如何对信息进行存储,以及如何在关注列表点击此城市后跳转到对应的天气界面呢?
1.对于关注的城市,信息存储包含两个内容:城市的名称(用于在关注界面进行显示)和城市的adcode(用于点击之后跳转到天气情况界面),清楚需要存储的信息之后,建立对应的数据库和表(新建一个java类,继承SQLiteOpenHelper):

public class MyDBhelper extends SQLiteOpenHelper {
    public static final String DB_NAME="Concern3.db";
    public static final int VERSION=1;
    public static final String TABLE_NAME="Concern";
    //对数据库进行创建
    public static final String CREATE_CONCERN = "create table Concern("
            + "city_code String primary key not null,"
            + "city_name String not null)";
            
    private Context mContext;

    public MyDBhelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version){
        super(context,name,factory,version);
        mContext = context;
    }
    @Override
    public void onCreate(SQLiteDatabase db){
        db.execSQL(CREATE_CONCERN);
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
    }
}

2.有了数据库和表,接下来便是如何在点击“关注”时将城市名称和idcode收集、存储到数据库中。需要在天气情况界面添加一个“关注”按钮,而这个按钮的点击响应事件为:

concern.setOnClickListener(new View.OnClickListener() {
	@Override
    public void onClick(View v) {
    MyDBhelper dbHelper = new MyDBhelper(WeatherActivity.this, DB_NAME, null, 1);
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put("city_code", countyCode);
    values.put("city_name", countyName);
    db.insert(TABLE_NAME, null, values);
    Toast.makeText(WeatherActivity.this, "关注成功!", Toast.LENGTH_LONG).show();
    }
});

可以看到,关注的点击响应事件会将countyCode和countyName这两个参数传递并存储到数据库,而对应“关注”按钮应该也有“取消关注”按钮,这个按钮的点击响应事件为:

concealConcern.setOnClickListener(new View.OnClickListener() {
	@Override
	public void onClick(View v) {
    MyDBhelper dbHelper = new MyDBhelper(WeatherActivity.this, DB_NAME, null, 1);
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    db.delete(TABLE_NAME,"city_code=?",new String[]{String.valueOf(countyCode)});
    Toast.makeText(WeatherActivity.this, "取消关注成功!", Toast.LENGTH_LONG).show();
    }
});

在存储完成后,需要一个新的Activity(MyConcernList)来显示所有的关注城市,MyConcernList中包含了所有关注城市的名称并显示出来,在此给出从数据库填装数据的代码:

private void InitConcern() {       //进行数据填装
	MyDBhelper dbHelper = new MyDBhelper(this,DB_NAME,null,1);
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    Cursor cursor  = db.rawQuery("select * from Concern",null);
    while(cursor.moveToNext()){
    	String city_code = cursor.getString(cursor.getColumnIndex("city_code"));
        String city_name = cursor.getString(cursor.getColumnIndex("city_name"));
        city_codeList.add(city_code);
        city_nameList.add(city_name);
    }
}

4.天气请求和gson数据解析

1.有了adcode码,便可以通过高德的API来进行地区天气情况的查询。高德的API需要去申请,高德API申请的地址如下:
高德API
注意:选择注册的为Web服务,天气查询和行政区域查询都可以用这个key值。
有了API之后,访问天气的链接为:

String weatherUrl = "https://restapi.amap.com/v3/weather/weatherInfo?city=" + adCode + "&key=c1894e9fcaf35e9fceabe9afaf40d45f";

其中key值为申请所得,前面的格式是固定的。访问行政区域的链接为:

String address = "https://restapi.amap.com/v3/config/district?keywords="+provinceName+"&subdistrict=1&key=c1894e9fcaf35e9fceabe9afaf40d45f";

其中key值同上边的key值,在链接中的“subdistrict=1”表示的含义为返回下一级行政区域,如果“subdistrict=2”则返回下两级行政区域。
2.不论天气还是行政区域查询,返回的都是json数据,要想得到最后的显示:天气情况或者行政区域,都需要对json数据进行解析,json数据解析参考下面这篇文章:
使用Gson解析常见字符串
需要注意的是,只有用[ ]方括号括起来的数据,才可以看作是一个数组,在数组外的字符串解析同整个数组是同级的,而[ ]方括号内的数据是同级的(低一级别),在此列出天气和行政区域的json数据解析。
(1)天气查询返回的json数据解析:

public static Weather handleWeatherResponse(String response) {
	try {
    	JSONObject jsonObject = new JSONObject(response);
        JSONArray jsonArray = jsonObject.getJSONArray("lives");
        for(int i=0; i<jsonArray.length(); i++){
        	JSONObject x = jsonArray.getJSONObject(i);
            String weatherContent = x.toString();
            return new Gson().fromJson(weatherContent, Weather.class);
        } }catch (Exception e) {
            e.printStackTrace();
        }
    return null;
}

(2)行政区域查询返回的json数据解析(此处返回的仅含下一级行政区域):
a.省级数据解析:

public static boolean handleProvinceResponse(String response){
	if (!TextUtils.isEmpty(response)) {
    	try {
        	JSONObject jsonObject = new JSONObject(response);
            JSONArray countryAll = jsonObject.getJSONArray("districts");
            for (int i = 0; i < countryAll.length(); i++) {
            	JSONObject countryLeve0 = countryAll.getJSONObject(i);
                    //插入省
                JSONArray provinceAll = countryLeve0.getJSONArray("districts");
                for (int j = 0; j < provinceAll.length(); j++) {
                	JSONObject province1 = provinceAll.getJSONObject(j);
                    String adcode1 = province1.getString("adcode");
                    String name1 = province1.getString("name");
                    Province provinceN = new Province();
                    provinceN.setProvinceCode(adcode1);
                    provinceN.setProvinceName(name1);
                    provinceN.save();
                }
                return true;
            }
        }
        catch(JSONException e){
            e.printStackTrace();
        }
    }
    return false;
}

b.市级数据解析:

public static boolean handleCityResponse(String response, String provinceCode){
	if (!TextUtils.isEmpty(response)) {
    	try {
        	JSONObject jsonObject = new JSONObject(response);
            JSONArray provinceAll = jsonObject.getJSONArray("districts");
            for (int i = 0; i < provinceAll.length(); i++) {
            	JSONObject province1 = provinceAll.getJSONObject(i);
                    //插入市
                JSONArray cityAll = province1.getJSONArray("districts");
                for (int j = 0; j < cityAll.length(); j++) {
                	JSONObject city2 = cityAll.getJSONObject(j);
                    String adcode2 = city2.getString("adcode");
                    String name2 = city2.getString("name");
                    City cityN = new City();
                    cityN.setCityCode(adcode2);
                    cityN.setCityName(name2);
                    cityN.setProvinceCode(provinceCode);
                    cityN.save();
                }
                 return true;
            }
        }
        catch(JSONException e){
            e.printStackTrace();
        }
    }
    return false;
}

c.县级数据解析:

public static boolean handleCountyResponse(String response, String cityCode){
	if (!TextUtils.isEmpty(response)) {
    	try {
        	JSONObject jsonObject = new JSONObject(response);
            JSONArray cityAll = jsonObject.getJSONArray("districts");
            for (int i = 0; i < cityAll.length(); i++) {
            	JSONObject city2 = cityAll.getJSONObject(i);
                    //插入市
                JSONArray countyAll = city2.getJSONArray("districts");
                for (int j = 0; j < countyAll.length(); j++) {
                	JSONObject county3 = countyAll.getJSONObject(j);
                    String adcode3 = county3.getString("adcode");
                    String name3 = county3.getString("name");
                    County countyN = new County();
                    countyN.setCountyCode(adcode3);
                    countyN.setCountyName(name3);
                    countyN.setCityCode(cityCode);
                    countyN.save();
                }
                 return true;
            }
		}
        catch(JSONException e){
        	e.printStackTrace();
        }
    }
    return false;
}

5.网络连接

天气预报APP需要进行网络请求,需要进行联网。此处用到的是okHttp,新建一个java类,命名为HttpUtil,代码如下:

import okhttp3.OkHttpClient;
import okhttp3.Request;

public class HttpUtil {
    public static void sendOkHttpRequest(final String address, okhttp3.Callback callback){
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(address).get().build();
        client.newCall(request).enqueue(callback);
    }
}

在AndroidManifest.xml中进行权限获取:

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

6.下载链接

天气预报APP的整体框架是郭霖《第一行代码》的第十四章"酷派天气",感兴趣可以去具体看一下。最后,附上天气预报APP的github地址,代码仍不完善,欢迎指正。
Weather

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值