Anko
- Anko Commons:一个轻量级的库,里面包含了intents,对话框,日志等帮助类
- Anko Layouts:用于编写动态Android布局的快速且类型安全的方法
- Anko SQLite:查询适用于Android SQLite的DSL和分析器集合
- Anko Coroutines:基于kotlinx.coroutines库的实用程序
- 简化获取RecyclerView
1
val forecastList: RecyclerView = find(R.id.recyclerView)
扩展函数
扩展函数数是指在一个类上增加一种新的行为,甚至我们没有这个类代码的访问权
限。这是一个在缺少有用函数的类上扩展的方法。在Java中,通常会实现很多带有
static方法的工具类。Kotlin中扩展函数的一个优势是我们不需要在调用方法的时候
把整个对象当作参数传入。扩展函数表现得就像是属于这个类的一样,而且我们可
以使用 this 关键字和调用所有public方法1
2
3fun Context.toastF(message: CharSequence,duration: Int=Toast.LENGTH_SHORT){
Toast.makeText(this, "$message", duration).show()
}
Anko已经扩展toast函数,提供了CharSequence,(resource id)Int的函数
1
2toast(R.string.app_name)
longToast("longToast")扩展函数并不是真正地修改了原来的类,它是以静态导入的方式来实现的。扩展函数可以被声明在任何文件中,通用的实践是把一系列有关的函数放在一个新建的文件里
1
2
3var TextView.text: CharSequence
get() = getText()
set(v) = setText(v)
网络请求
网络请求类
1
2
3
4
5
6
7public class Request(var url: String) {
public fun run() {
//这个方法不推荐
val forcastJson = URL(url).readText()
Log.e(javaClass.simpleName, forcastJson)
}
}执行异步请求,async用于其他线程执行请求,uiThread回到主线程,UIThread 是可以依赖于调用者如果它是被一个Activity 调用的,那么如果 activity.isFinishing() 返回true,则 uiThread 不会执行,在Activity销毁的时候避免程序崩溃
1
2
3
4
5
6doAsync {
val url="http://samples.openweathermap.org/data/2.5/weather?id=2172797&appid=b6907d289e10d714a6e88b30761fae22"
Request(url).run()
uiThread { longToast("Request Performed") }
}数据类,属性访问,以及其他函数
- equals(): 它可以比较两个对象的属性来确保他们是相同的
- hashCode(): 我们可以得到一个hash值,也是从属性中计算出来的
- copy(): 你可以拷贝一个对象,可以根据你的需要去修改里面的属性
- 一系列可以映射对象到变量中的函数
1
2data class Forecast(val date: Date, val temperature: Float, val
details: String)
复制一个数据类,修改某个属性
1
2
3
4
5
6
7val f1 = Forecast(Date(), 23f, "Sunny")
Log.e(tag, f1.toString())
val f2 = f1.copy(temperature = 30f)
Log.e(tag, f2.toString())
E/MainActivity: Forecast(date=Fri Mar 23 00:22:42 EDT 2018, temperature=23.0, details=Sunny)
E/MainActivity: Forecast(date=Fri Mar 23 00:22:42 EDT 2018, temperature=30.0, details=Sunny)映射对象到变量中
1
2
3
4
5
6
7
8
9
10
11
12
13//映射对象到变量中,多声明
val (date, temp, details) = f1
Log.e(tag, "date " + date.toString())
Log.e(tag, "temp " + temp.toString())
Log.e(tag, "details $details")
// 上面的多声明会编译成下面的代码
// val date = f1.component1()
// val temperature = f1.component2()
// val details = f1.component3()
E/MainActivity: date Fri Mar 23 00:33:41 EDT 2018
E/MainActivity: temp 23.0
E/MainActivity: details SunnyMap 类含有一些扩展函数的实现,允许它在迭代时使用key和value
1
2
3
4
5
6
7val map = mutableListOf(f1,f2)
for ((key, value) in map) {
Log.d("map", "key:$key, value:$value")
}
E/map: key:Fri Mar 23 00:41:25 EDT 2018, value:23.0
E/map: key:Fri Mar 23 00:41:25 EDT 2018, value:30.0转换josn到数据类,这里有个插件JsonToKotlinClass,转换json to kotlin data class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
data class ForecastResult(
val city: City,
val cod: String,
val message: Double,
val cnt: Int,
val list: List<Item8>
)
data class City(
val id: Int,
val name: String,
val coord: Coord,
val country: String,
val population: Int
)
data class Coord(
val lon: Double,
val lat: Double
)
data class Item8(
val dt: Int,
val temp: Temp,
val pressure: Double,
val humidity: Int,
val weather: List<Weather>,
val speed: Double,
val deg: Int,
val clouds: Int
)
data class Temp(
val day: Double,
val min: Double,
val max: Double,
val night: Double,
val eve: Double,
val morn: Double
)
data class Weather(
val id: Int,
val main: String,
val description: String,
val icon: String
)Companion objects (伴随对象)Kotlin允许我们去定义一些行为与静态对象一样的对象。尽管这些对象可以用众所周知的模式来实现,比如容易实现的单例模式。我们需要一个类里面有一些静态的属性、常量或者函数,我们可以使用 companion objecvt 。这个对象被这个类的所有对象所共享,就像Java中的静态属性或者方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class Request(var zipCode: String) {
companion object {
private val APP_ID = "15646a06818f61f7b8d7823ca833e1ce"
private val URL = "http://api.openweathermap.org/data/2.5/forecast/daily?mode=json&units=metric&cnt=7"
private val COMPLETE_URL = "$URL&APPID=$APP_ID&zip="
}
public fun execute(): ForecastResult {
//这个方法不推荐
val forecastJson = URL(COMPLETE_URL + zipCode).readText()
Log.e(javaClass.simpleName, forecastJson)
return Gson().fromJson(forecastJson, ForecastResult::class.java)
}
}
val result = Request(94040).execute()
Log.e(tag, "result " + result.toString())
构建domain层
定义一个commnad,执行一个任务,返回泛型,一起Kotlin函数都有返回值,没有指定默认返回Unit,所以不返回数据可以指定类型会Unit
1
2
3public interface Command<T> {
fun execute(): T
}command需要去请求天气预报接口然后转换结果为domain类
1
2
3
4
5
6
7public interface Command<T> {
data class ForecastList(val city: String, val country: String,
val dailyForecast: List<Forecast>)
data class Forecast(val date: String, val description: String,
val high: Int, val low: Int)
}数据映射到Domain,创建DataMapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class ForecastDataMapper {
fun convertFromDataModel(forecast: ForecastResult): Forecast
List {
return ForecastList(forecast.city.name, forecast.city.co
untry,
convertForecastListToDomain(forecast.list))
private fun convertForecastListToDomain(list: List<Forecast>)
:
List<ModelForecast> {
return list.map { convertForecastItemToDomain(it) }
}
private fun convertForecastItemToDomain(forecast: Forecast):
ModelForecast {
return ModelForecast(convertDate(forecast.dt),
forecast.weather[0].description, forecast.temp.m
ax.toInt(),
forecast.temp.min.toInt())
}
private fun convertDate(date: Long): String {
val df = DateFormat.getDateInstance(DateFormat.MEDIUM, L
ocale.getDefault())
return df.format(date * 1000)
}
}当我们使用了两个相同名字的类,我们可以给其中一个指定一个别名,这样我们就不需要写完整的包名了:
import com.willkernel.app.kotlindemo.model.Forecast as ModelForecast
,从一个forecast list中转换为domain modelreturn list.map { convertForecastItemToDomain(it) }
循环这个集合并且返回一个转换后的新的ListForecastMapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class ForecastDataMapper {
fun convertFromDataModel(forecast: ForecastResult): ForecastList {
return ForecastList(forecast.city.name, forecast.city.country,
convertForecastListToDomain(forecast.list))
}
private fun convertForecastListToDomain(list: List<Forecast>)
: List<ModelForecast> {
return list.map { convertForecastItemToDomain(it) }
}
private fun convertForecastItemToDomain(forecast: Forecast):
ModelForecast {
return ModelForecast(convertDate(forecast.dt),
forecast.weather[0].description, forecast.temp.max.toInt(),
forecast.temp.min.toInt())
}
private fun convertDate(date: Long): String {
val df = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault())
return df.format(date * 1000)
}
}编写网络请求命令
1
2
3
4
5
6class RequestForecastCommand(val zipCode: String) : Command<ForecastList> {
override fun execute(): ForecastList {
val forecastRequest = ForecastRequest(zipCode)
return ForecastDataMapper().convertFromDataModel(forecastRequest.execute())
}
}
修改Adapter,设置数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class ForecastListAdapter(val items: ForecastList) : RecyclerView.Adapter<ForecastListAdapter.VH>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
return VH(TextView(parent.context))
}
override fun getItemCount(): Int = items.size
override fun onBindViewHolder(holder: VH, position: Int) {
with(items.dailyForecast[position]) {
holder.textView.text = "$date - $description - $high - $low"
}
}
class VH(val textView: TextView) : RecyclerView.ViewHolder(textView)
}
doAsync {
val result = RequestForecastCommand("94043").execute()
Log.e(tag, "result " + result.toString())
uiThread { recyclerView.adapter = ForecastListAdapter(result)
}
}
with
函数with是一个非常有用的函数,它包含在Kotlin的标准库中。它接收一个对象
和一个扩展函数作为它的参数,然后使这个对象扩展这个函数。这表示所
有我们在括号中编写的代码都是作为对象(第一个参数)的一个扩展函
数,我们可以就像作为this一样使用所有它的public方法和属性。当我们针
对同一个对象做很多操作的时候这个非常有利于简化代码