参考:《第一行代码:Android》第2版——郭霖html
注1:本文为原创,例子可参考郭前辈著做:《第一行代码:Android》第2版java
注2:本文不赘述android开发的基本理论,不介绍入门知识,不介绍Android Studio基本安装,开门见山,直接使用kotlin改写郭前辈的《第一行代码:Android》中的部分例子,有机会的话本身作一些新例子出来!android
注3:本文尝试用Google新官推语言kotlin改写《第一行代码:Android》中的案例,偶尔涉及java做为对比json
注4:开发基于Android Studio 3.0,而且新建项目时勾选“support kotlin”api
本次博文,我将尝试使用kotlin语言对郭前辈的《第一行代码》中的最后那个实战项目“酷欧天气”进行重写数组
原书:14.5显示天气信息(p509)服务器
上一章,咱们已经把省市县数据“爬”到了app中,接下来咱们要作的是“爬”天气预报信息,完成app剩下的功能app
先去注册一下郭神提供的weather api(经过他得到在线的天气信息)
http://console.heweather.com/registerasync
注册完成登录后取得key,并测试访问一下是否能得到天气的json信息
http://guolin.tech/api/weather?cityid=CN101190402&key=e970db87b1f24fb8a00555c6b361e8d4
(访问形式如上,参考原书:p522,地址中的参数cityid就是在上一章中County数据类里的weather_id)ide
得到数据:
这就说明已经能够成功获取最近的天气数据了!
不过这个json信息量有点大啊!==|||
上一章已经“吹”过了kotlin强大的data class(数据类)了,这是一种比java pojo类更加方便精简的类!
每个你创建的POJO类文件最后都转换为一行代码而已
原做中,做者对gson实体类进行了分析(原书p509),可使用他分析后建立的实体类(只须要转换成kotlin data class的写法)
不过对于这么复杂的json,我使用了在线json转POJO,将刚刚得到的天气json数据先转换为POJO类(这样使得实体类定义更加完整而且比本身一个个手写要块多了,工具是个好东西!)
json转POJO网址:http://www.bejson.com/json2javapojo/
注意从网站上获得的只是java的POJO类,不是kotlin类(反正我尚未找到json直接转kotlin数据类的工具==|||求推荐)
进入Android Studio 3.0,在项目中新建包:weatherapi->新建datas.kt
为何要新建一个包?
这个包是专门存放kotlin的天气数据类的,由于我发现郭前辈那个api得到天气json转换后的数据类与以前的个人City这个数据类有冲突(那个json里也有个City),故而将此次天气的数据类放到一个单独的包中,保证不会冲突,另外引入时须要注意,别引入了外面那个City类!
先新建一个City.java,这是一个POJO类文件,将json在线转换好的POJO类代码复制进来
这是那个在线json转换出来的City java POJO类:
package cn.cslg.weatherkotlin.weatherapi; public class City { private String aqi; private String pm10; private String pm25; private String qlty; public void setAqi(String aqi){ this.aqi = aqi; } public String getAqi(){ return this.aqi; } public void setPm10(String pm10){ this.pm10 = pm10; } public String getPm10(){ return this.pm10; } public void setPm25(String pm25){ this.pm25 = pm25; } public String getPm25(){ return this.pm25; } public void setQlty(String qlty){ this.qlty = qlty; } public String getQlty(){ return this.qlty; } }
使用IDE能够直接将java转换为kotlin代码,这是kotlin类库自带的功能,咱们来转这个java类为kotlin类
点击Android Studio 3.0上面的工具栏上的Code->Convert Java File to Kotlin File(在最后一个)
IDE转换结束后,很遗憾,这不是一个kotlin的数据类,自行修修补补,改为data class吧(求工具彻底转换!)
如下是我自行修改后:City的dataclass
data class City(val aqi: String, val pm10: String, val pm25: String, val qlty: String)
我的推荐一种办法:
最终的datas.kt:
package cn.cslg.weatherkotlin.weatherapi data class City(var aqi: String, var pm10: String, var pm25: String, var qlty: String) data class Aqi(var city: City) data class Update(var loc: String, var utc: String) data class Basic(var city: String, var cnty: String, var id: String, var lat: String, var lon: String, var update: Update) data class Now(var cond: Cond, var fl: String, var hum: String, var pcpn: String, var pres: String, var tmp: String, var vis: String, var wind: Wind) data class Air(var brf: String, var txt: String) data class Comf(var brf: String, var txt: String) data class Cw(var brf: String, var txt: String) data class Drsg(var brf: String, var txt: String) data class Flu(var brf: String, var txt: String) data class Sport(var brf: String, var txt: String) data class Trav(var brf: String, var txt: String) data class Uv(var brf: String, var txt: String) data class Suggestion(var air: Air, var comf: Comf, var cw: Cw, var drsg: Drsg, var flu: Flu, var sport: Sport, var trav: Trav, var uv: Uv) data class Astro(var mr: String, var ms: String, var sr: String, var ss: String) data class Tmp(var max: String, var min: String) data class Daily_forecast(var astro: Astro, var cond: DailyCond, var date: String, var hum: String, var pcpn: String, var pop: String, var pres: String, var tmp: Tmp, var uv: String, var vis: String, var wind: Wind) data class Cond(var code: String, var txt: String) data class DailyCond(var code_d:String,var code_n:String,var txt_d:String,var txt_n:String) data class Wind(var deg: String, var dir: String, var sc: String, var spd: String) data class Hourly_forecast(var cond: Cond, var date: String, var hum: String, var pop: String, var pres: String, var tmp: String, var wind: Wind) data class HeWeather(var aqi: Aqi, var basic: Basic, var daily_forecast: List<Daily_forecast>, var hourly_forecast: List<Hourly_forecast>, var now: Now, var status: String, var suggestion: Suggestion) data class Weather(var HeWeather:List<HeWeather>)
注意最后一个Weather类,这是我单独添加出来的,由于我注意到API返回的json开头就有一个HeWeathter对象而且对应的值是HeWeather数组,Gson映射的时候是以最外层{}开始转换为一个对象的,这个对象将会是这个Weather,而不是HeWeather!
另外注意到,那个工具网站生成的POJO类中有两个Cond!仔细查看json数据格式,确实有两个Cond,并且不同!因此我另开了一个DailyCond数据类做为daily_forecast下的cond的实体模型
能够树形查看json格式的网站:http://www.qqe2.com/
至此数据类已经创建好了,后面能够放心的用Gson映射为实体对象了!
原书:p520
接下来能够开始书写kt代码了,我将会把原书中的java翻译成为简单kotlin代码
原书中有handleWeatherResponse,针对json进行处理,这个咱们不须要,我使用Gson映射为数据类实体
WeatherActivity.kt:
package cn.cslg.weatherkotlin import android.support.v7.app.AppCompatActivity import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.widget.* import cn.cslg.weatherkotlin.weatherapi.* import com.google.gson.Gson import org.jetbrains.anko.custom.async import org.jetbrains.anko.find import org.jetbrains.anko.uiThread import java.net.URL class WeatherActivity : AppCompatActivity() { private var weatherLayout: ScrollView? = null private var titleCity: TextView? = null private var titleUpdateTime: TextView? = null private var degreeText: TextView? = null private var weatherInfoText: TextView? = null private var forecastLayout: LinearLayout? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_weather) weatherLayout = find<ScrollView>(R.id.weather_layout) titleCity = find<TextView>(R.id.title_city) titleUpdateTime = find<TextView>(R.id.title_update_time) degreeText = find<TextView>(R.id.degree_text) weatherInfoText = find<TextView>(R.id.weather_info_text) forecastLayout = find<LinearLayout>(R.id.forecast_layout) val weatherId = intent.getStringExtra("weather_id"); weatherLayout!!.visibility = View.INVISIBLE requestWeather(weatherId) } //从服务器加载天气信息 private fun requestWeather(wid:String){ val url="http://guolin.tech/api/weather?cityid="+wid+"&key=e970db87b1f24fb8a00555c6b361e8d4" async { val s = URL(url).readText() uiThread { val weather = Gson().fromJson(s,Weather::class.java) showWeatherInfo(weather.HeWeather[0]) } } } //显示出天气信息 private fun showWeatherInfo(w: HeWeather){ titleCity!!.text=w.basic.city titleUpdateTime!!.text= w.basic.update.loc degreeText!!.text=w.now.tmp+" ℃" weatherInfoText!!.text=w.now.cond.txt+" "+w.now.wind.dir+" "+w.now.wind.sc+"级" weatherLayout!!.visibility=View.VISIBLE forecastLayout!!.removeAllViews() for( d in w.daily_forecast){ val v = LayoutInflater.from(this).inflate(R.layout.forecast_item,forecastLayout,false) val dateText = v.find<TextView>(R.id.date_text) val infoText = v.find<TextView>(R.id.info_text) val maxText = v.find<TextView>(R.id.max_text) val minText = v.find<TextView>(R.id.min_text) dateText.text = d.date maxText.text = d.tmp.max minText.text = d.tmp.min if(d.cond.code_d == d.cond.code_n){ infoText.text = d.cond.txt_d }else{ infoText.text = d.cond.txt_d+"->"+d.cond.txt_n } forecastLayout!!.addView(v) } } }
overwrite的onCreate方法很少解释,主要是获取R中的布局转成控件,隐藏了还没有加载的地方,还从intent中得到了一个参数,用于选择查询的城市
requestWeather方法使用了async请求API的数据,传入城市的weather_id
注意到,这里使用Gson转换的时候并无上一章的TypeToken,由于这一次得到json数据最外层不是数组,也就不须要List映射,因此直接传入一个对象的类,kotlin使用Object::class.java便可!
showWeatherInfo方法将获取的数据初始化到界面上,其中用到了kotlin的for( in )遍历结构,很是简单!
ChooseAreaFragment.kt:
class ChooseAreaFragment : Fragment() { ...... override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) //列表点击监听事件 listView!!.setOnItemClickListener { LEVEL_COUNTY -> { selectedCounty = countyList[position] val intent = Intent(activity,WeatherActivity::class.java) intent.putExtra("weather_id", selectedCounty!!.weather_id) startActivity(intent) activity.finish() ....... }
往里面添加了:点击县跳转到WeatherActivity的Intent
activity_weather.xml:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimary"> <ScrollView android:id="@+id/weather_layout" android:scrollbars="none" android:overScrollMode="never" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <include layout="@layout/title"/> <include layout="@layout/now"/> <include layout="@layout/forecast"/> </LinearLayout> </ScrollView> </FrameLayout>
forecast.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:background="#8000" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:paddingTop="10sp" android:paddingBottom="10sp" android:text="三天预报" android:textColor="#fff" android:textSize="20sp" /> <LinearLayout android:id="@+id/forecast_layout" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> </LinearLayout> </LinearLayout>
forecast_item.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="15dp" android:orientation="horizontal"> <TextView android:id="@+id/date_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="2" android:layout_gravity="center_vertical" android:textColor="#fff" /> <TextView android:id="@+id/info_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="center_vertical" android:gravity="center" android:textColor="#fff" /> <TextView android:id="@+id/max_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center" android:textColor="#fff" /> <TextView android:id="@+id/min_text" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_weight="1" android:gravity="right" android:textColor="#fff" /> </LinearLayout>
now.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_margin="15dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/degree_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end" android:textColor="#fff" android:textSize="60sp" /> <TextView android:id="@+id/weather_info_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end" android:textColor="#fff" android:textSize="20sp" /> </LinearLayout>
title.xml:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" > <TextView android:id="@+id/title_city" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="#fff" android:textSize="20sp" /> <TextView android:id="@+id/title_update_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10sp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:textColor="#fff" android:textSize="16sp" /> </RelativeLayout>
app的大致功能和样式已经实现了,接下来须要对他作更多的美化和完善!
转载请注明出自:http://www.cnblogs.com/devilyouwei/p/6889804.html