android天气预报开发
本教程将介绍如何开发android应用程序 。 在本教程中,我们将探讨创建Android应用程序所需的内容以及可用于创建应用程序的积木。 例如,我们将创建一个天气应用程序。 几个月前我们谈到了它 ,我们将开发具有天气状况和天气预报的天气应用程序。 要开发一个android应用程序,我们至少需要:
- 一个活动
- 布局
这些是我们可以使用的基本组件。 当然,我们想创建一些更复杂的东西,因为我们必须从远程服务器(在本例中为openweathermap)中检索信息,并且必须解析结果数据。 因此,我们需要添加以下基本组件:
- HTTP连接
- AsyncTask(没有ANR问题)
- JSON解析
- 数据模型(包含JSON数据)
最后,我们将获得:
应用布局
第一步是创建布局。 从下面的图像中可以看到,我们的布局分为两部分:一个保存当前的天气状况,另一个保存天气预报。 在天气预报中,我们必须在不同的日期之间移动,以便可以使用ViewPager.
在这种情况下,我们可以使用LinearLayout:
现在我们有了布局,我们可以开始每个部分的工作了。 在第一部分(当前天气)中,我们可以使用RelativeLayout将每个小部件放置在正确的位置:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity"
android:layout_weight="1" >
<TextView
android:id="@+id/cityText"
style="?android:attr/textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true">
</TextView>
<TextView
android:id="@+id/temp"
style="@style/tempStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/cityText"
android:layout_centerHorizontal="true">
</TextView>
<TextView
android:id="@+id/unittemp"
android:layout_width="wrap_content"
style="?android:attr/textAppearanceMedium"
android:layout_height="wrap_content"
android:layout_below="@id/cityText"
android:layout_toRightOf="@id/temp"
android:layout_alignBaseline="@id/temp">
</TextView>
<TextView
android:id="@+id/skydesc"
android:layout_width="wrap_content"
style="?android:attr/textAppearanceMedium"
android:layout_height="wrap_content"
android:layout_below="@id/temp"
android:layout_alignStart="@id/temp"
android:layout_toRightOf="@id/temp">
</TextView>
<!-- Image weather condition -->
<ImageView android:id="@+id/condIcon"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignTop="@id/temp"
android:layout_toRightOf="@id/temp"/>
</RelativeLayout>
正如我们所说的,在第二部分中,我们必须显示几天的预测。 在这种情况下,我们可以使用ViewPager来帮助我们在页面之间滑动,因此我们具有:
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="6" >
<android.support.v4.view.PagerTitleStrip
android:id="@+id/pager_title_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#E6E6E6"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
这是我们的布局。 现在我们要填写天气数据。
HTTP,AsyncTask和json数据解析
下一步是使用HTTP连接和asynctask来检索数据,以避免ANR问题。 有了数据后,我们将使用JSON解析器对其进行解析。 让我们使用以下链接询问我们的浏览器天气预报:
http://api.openweathermap.org/data/2.5/forecast/daily?q=Rome,IT&mode=json&units=metric&cnt=3
其中,cnt是我们要具有天气状况的天数。 结果如下所示:
{
"cod": "200",
"message": 0.0192,
"city": {
"id": "3169070",
"name": "Rome",
"coord": {
"lon": 12.4958,
"lat": 41.903
},
"country": "Italy",
"population": 0
},
"cnt": 7,
"list": [
{
"dt": 1377774000,
"temp": {
"day": 26.83,
"min": 16.41,
"max": 29.12,
"night": 16.41,
"eve": 24.81,
"morn": 26.83
},
"pressure": 1007.2,
"humidity": 72,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "sky is clear",
"icon": "01d"
}
],
"speed": 0.71,
"deg": 146,
"clouds": 0
},
{
"dt": 1377860400,
"temp": {
"day": 29.84,
"min": 16.8,
"max": 29.84,
"night": 16.8,
"eve": 24.81,
"morn": 17.93
},
"pressure": 1006.68,
"humidity": 50,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "sky is clear",
"icon": "02d"
}
],
"speed": 2.2,
"deg": 235,
"clouds": 8
},
{
"dt": 1377946800,
"temp": {
"day": 29.14,
"min": 14.11,
"max": 29.14,
"night": 14.11,
"eve": 24.08,
"morn": 18.32
},
"pressure": 1005.17,
"humidity": 45,
"weather": [
{
"id": 801,
"main": "Clouds",
"description": "few clouds",
"icon": "02d"
}
],
"speed": 1.56,
"deg": 320,
"clouds": 20
},
{
"dt": 1378033200,
"temp": {
"day": 28.43,
"min": 12.11,
"max": 28.95,
"night": 14.28,
"eve": 23.89,
"morn": 12.11
},
"pressure": 1005.23,
"humidity": 39,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "sky is clear",
"icon": "01d"
}
],
"speed": 1.55,
"deg": 289,
"clouds": 0
},
{
"dt": 1378119600,
"temp": {
"day": 29.83,
"min": 16.02,
"max": 29.83,
"night": 18.86,
"eve": 25.35,
"morn": 16.02
},
"pressure": 1006.57,
"humidity": 32,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "sky is clear",
"icon": "01d"
}
],
"speed": 3.3,
"deg": 292,
"clouds": 0
},
{
"dt": 1378206000,
"temp": {
"day": 27.76,
"min": 19.68,
"max": 27.76,
"night": 19.68,
"eve": 25,
"morn": 20.25
},
"pressure": 1014.89,
"humidity": 0,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "sky is clear",
"icon": "01d"
}
],
"speed": 4.05,
"deg": 298,
"clouds": 0
},
{
"dt": 1378292400,
"temp": {
"day": 27.85,
"min": 19.91,
"max": 27.85,
"night": 19.91,
"eve": 24.78,
"morn": 20.13
},
"pressure": 1017.2,
"humidity": 0,
"weather": [
{
"id": 800,
"main": "Clear",
"description": "sky is clear",
"icon": "01d"
}
],
"speed": 1.91,
"deg": 252,
"clouds": 0
}
]
}
分析结果,我们发现我们正在寻找的信息在list标记内,这是一个数组。 为了保存此信息,我们可以在两个保存每日预测的类上创建另一个,保存另一个每日预测类:
public class DayForecast {
private static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
public Weather weather = new Weather();
public ForecastTemp forecastTemp = new ForecastTemp();
public long timestamp;
public class ForecastTemp {
public float day;
public float min;
public float max;
public float night;
public float eve;
public float morning;
}
public String getStringDate() {
return sdf.format(new Date(timestamp));
}
}
另一个:
public class WeatherForecast {
private List<DayForecast> daysForecast = new ArrayList<DayForecast>();
public void addForecast(DayForecast forecast) {
daysForecast.add(forecast);
System.out.println("Add forecast ["+forecast+"]");
}
public DayForecast getForecast(int dayNum) {
return daysForecast.get(dayNum);
}
}
现在我们有了数据模型,并且使用简单的类(如上一篇文章(JSONWeatherParser)中使用的类)简单地解析了JSON数据。
public static WeatherForecast getForecastWeather(String data) throws JSONException {
WeatherForecast forecast = new WeatherForecast();
// We create out JSONObject from the data
JSONObject jObj = new JSONObject(data);
JSONArray jArr = jObj.getJSONArray("list"); // Here we have the forecast for every day
// We traverse all the array and parse the data
for (int i=0; i < jArr.length(); i++) {
JSONObject jDayForecast = jArr.getJSONObject(i);
// Now we have the json object so we can extract the data
DayForecast df = new DayForecast();
// We retrieve the timestamp (dt)
df.timestamp = jDayForecast.getLong("dt");
// Temp is an object
JSONObject jTempObj = jDayForecast.getJSONObject("temp");
df.forecastTemp.day = (float) jTempObj.getDouble("day");
df.forecastTemp.min = (float) jTempObj.getDouble("min");
df.forecastTemp.max = (float) jTempObj.getDouble("max");
df.forecastTemp.night = (float) jTempObj.getDouble("night");
df.forecastTemp.eve = (float) jTempObj.getDouble("eve");
df.forecastTemp.morning = (float) jTempObj.getDouble("morn");
// Pressure & Humidity
df.weather.currentCondition.setPressure((float) jDayForecast.getDouble("pressure"));
df.weather.currentCondition.setHumidity((float) jDayForecast.getDouble("humidity"));
// ...and now the weather
JSONArray jWeatherArr = jDayForecast.getJSONArray("weather");
JSONObject jWeatherObj = jWeatherArr.getJSONObject(0);
df.weather.currentCondition.setWeatherId(getInt("id", jWeatherObj));
df.weather.currentCondition.setDescr(getString("description", jWeatherObj));
df.weather.currentCondition.setCondition(getString("main", jWeatherObj));
df.weather.currentCondition.setIcon(getString("icon", jWeatherObj));
forecast.addForecast(df);
}
return forecast;
}
做得好! 我们还需要什么呢?……我们必须处理ViewPager并创建适配器来保存每天的天气预报。
ViewPager,片段和适配器
首先,我们必须创建我们的适配器,以处理显示每日天气详细信息的每个片段。 在这种情况下,要创建我们的适配器,我们必须扩展FragmentPagerAdapter:
public class DailyForecastPageAdapter extends FragmentPagerAdapter {
private int numDays;
private FragmentManager fm;
private WeatherForecast forecast;
private final static SimpleDateFormat sdf = new SimpleDateFormat("E, dd-MM");
public DailyForecastPageAdapter(int numDays, FragmentManager fm, WeatherForecast forecast) {
super(fm);
this.numDays = numDays;
this.fm = fm;
this.forecast = forecast;
}
// Page title
@Override
public CharSequence getPageTitle(int position) {
// We calculate the next days adding position to the current date
Date d = new Date();
Calendar gc = new GregorianCalendar();
gc.setTime(d);
gc.add(GregorianCalendar.DAY_OF_MONTH, position);
return sdf.format(gc.getTime());
}
@Override
public Fragment getItem(int num) {
DayForecast dayForecast = (DayForecast) forecast.getForecast(num);
DayForecastFragment f = new DayForecastFragment();
f.setForecast(dayForecast);
return f;
}
/*
* Number of the days we have the forecast
*/
@Override
public int getCount() {
return numDays;
}
两种方法很重要:一种“创建”片段,另一种“创建”页面标题。 第一个实例化一个片段,该片段显示通过dayForecast数据传递的每日预测,另一个则使用GregorianCalendar创建页面图块。
最后一步是对片段进行编码:
public class DayForecastFragment extends Fragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.dayforecast_fragment, container, false);
TextView tempView = (TextView) v.findViewById(R.id.tempForecast);
TextView descView = (TextView) v.findViewById(R.id.skydescForecast);
tempView.setText( (int) (dayForecast.forecastTemp.min - 275.15) + "-" + (int) (dayForecast.forecastTemp.max - 275.15) );
descView.setText(dayForecast.weather.currentCondition.getDescr());
iconWeather = (ImageView) v.findViewById(R.id.forCondIcon);
// Now we retrieve the weather icon
JSONIconWeatherTask task = new JSONIconWeatherTask();
task.execute(new String[]{dayForecast.weather.currentCondition.getIcon()});
return v;
}
...
}
在onCreateView中,我们增加布局并使用(AsyncTask)检索天气图标。
源代码可用@ github
翻译自: https://www.javacodegeeks.com/2013/09/android-app-developmentweather-app-with-forecast.html
android天气预报开发