怎么定义一个类
如果你想定义一个类,你只需要使用class
关键字。
class MainActivity{
}
它有一个默认唯一的构造器。我们会在以后的课程中学习在特殊的情况下创建其它额外的构造器,但是请记住大部分情况下你只需要这个默认的构造器。你只需要在类名后面写上它的参数。如果这个类没有任何内容可以省略大括号:
class Person(name: String, surname: String)
那么构造函数的函数体在哪呢?你可以写在init
块中:
class Person(name: String, surname: String) {
init{
...
}
}
类继承
默认任何类都是基础继承自Any
(与java中的Object
类似),但是我们可以继承其它类。所有的类默认都是不可继承的(final),所以我们只能继承那些明确声明open
或者abstract
的类:
open class Animal(name: String)
class Person(name: String, surname: String) : Animal(name)
当我们只有单个构造器时,我们需要在从父类继承下来的构造器中指定需要的参数。这是用来替换Java中的super
调用的。
函数
函数(我们Java中的方法)可以使用fun
关键字就可以定义:
fun onCreate(savedInstanceState: Bundle?) {
}
如果你没有指定它的返回值,它就会返回Unit
,与Java中的void
类似,但是Unit
是一个真正的对象。你当然也可以指定任何其它的返回类型:
fun add(x: Int, y: Int) : Int {
return x + y
}
小提示:分号不是必须的
就像你在上面的例子中看到的那样,我在每句的最后没有使用分号。当然你也可以使用分号,分号不是必须的,而且不使用分号是一个不错的实践。当你这么做了,你会发现这节约了你很多时间。
然而如果返回的结果可以使用一个表达式计算出来,你可以不使用括号而是使用等号:
fun add(x: Int,y: Int) : Int = x + y
构造方法和函数参数
Kotlin中的参数与Java中有些不同。如你所见,我们先写参数的名字再写它的类型:
fun add(x: Int, y: Int) : Int {
return x + y
}
我们可以给参数指定一个默认值使得它们变得可选,这是非常有帮助的。这里有一个例子,在Activity中创建了一个函数用来toast一段信息:
fun toast(message: String, length: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, length).show()
}
如你所见,第二个参数(length)指定了一个默认值。这意味着你调用的时候可以传入第二个值或者不传,这样可以避免你需要的重载函数:
toast("Hello")
toast("Hello", Toast.LENGTH_LONG)
这个与下面的Java代码是一样的:
void toast(String message){
}
void toast(String message, int length){
Toast.makeText(this, message, length).show();
}
这跟你想象的一样复杂。再看看这个例子:
fun niceToast(message: String,
tag: String = javaClass<MainActivity>().getSimpleName(),
length: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, "[$className] $message", length).show()
}
我增加了第三个默认值是类名的tag参数。如果在Java中总数开销会以几何增长。现在可以通过以下方式调用:
toast("Hello")
toast("Hello", "MyTag")
toast("Hello", "MyTag", Toast.LENGTH_SHORT)
而且甚至还有其它选择,因为你可以使用参数名字来调用,这表示你可以通过在值前写明参数名来传入你希望的参数:
toast(message = "Hello", length = Toast.LENGTH_SHORT)
小提示:String模版
你可以在String中直接使用模版表达式。它可以帮助你很简单地在静态值和变量的基础上编写复杂的String。在上面的例子中,我使用了"[$className] $message"。
如你所见,任何时候你使用一个
$
符号就可以插入一个表达式。如果这个表达式有一点复杂,你就需要使用一对大括号括起来:"Your name is ${user.name}"。
编写你的第一个类
我们已经有了MainActivity.kt
类。这个Activity会展示下周一系列的天气预报,所有它的layout需要有些改变。
创建一个layout
显示天气预报的列表我们使用RecyclerView
,所以你需要在build.gradle
中增加一个新的依赖:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile "com.android.support:appcompat-v7:$support_version"
compile "com.android.support:recyclerview-v7:$support_version" ...
}
然后,activity_main.xml
如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/forecast_list"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
在Mainactivity.kt
中删除掉之前用来测试的能正常运行的所有代码(现在应该会提示错误)。暂且我们使用老的findViewByid()
的方式:
val forecastList = findViewById(R.id.forecast_list) as RecyclerView
forecastList.layoutManager = LinearLayoutManager(this)
如你所见,我们定义类一个变量并转型为RecyclerView
。这里与Java有点不同,我们会在下一章分析这些不同之处。LayoutManager
会通过属性的方式被设置,而不是通过setter,这个layout已经足够显示一个列表了。
对象实例化
对象实例化也是与Java中有些不同。如你所见,我们去掉了
new
关键字。这时构造函数仍然会被调用,但是我们省略了宝贵的四个字符。LinearLayoutManager(this)
创建了一个对象的实例。
The Recycler Adapter
我们同样需要一个RecyclerView
的Adapter。之前我在我博客中讨论过RecyclerView
,如果你以前没有使用过,它可能会有所帮助。
RecyclerView
中所使用到的布局现在只需要一个TextView
,我会手动去创建这个简单的文本列表。增加一个名为ForecastListAdapter.kt
的Kotlin文件,包括如下代码:
class ForecastListAdapter(val items: List<String>) :
RecyclerView.Adapter<ForecastListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(TextView(parent.context))
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.textView.text = items.[position]
}
override fun getItemCount(): Int = items.size
class ViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
}
又是如此,我们可以像访问属性一样访问context和text。你可以保持以往那样操作(使用getters和setters),但是你会得到一个编译器的警告。如果你还是倾向于Java中的使用方式,这个检查可以被关闭。但是一旦你使用上了这种属性调用的方式你就会爱上它,而且它也节省了额外的字符总量。
回到MainActivity
,现在简单地创建一系列的String放入List中,然后使用创建分配Adapter实例。
private val items = listOf(
"Mon 6/23 - Sunny - 31/17",
"Tue 6/24 - Foggy - 21/8",
"Wed 6/25 - Cloudy - 22/17",
"Thurs 6/26 - Rainy - 18/11",
"Fri 6/27 - Foggy - 21/10",
"Sat 6/28 - TRAPPED IN WEATHERSTATION - 23/18",
"Sun 6/29 - Sunny - 20/7"
)
override fun onCreate(savedInstanceState: Bundle?) {
...
val forecastList = findViewById(R.id.forecast_list) as RecyclerView
forecastList.layoutManager = LinearLayoutManager(this)
forecastList.adapter = ForecastListAdapter(items)
}
List的创建
尽管我会在本书后面来对Collection进行讲解,但是我现在仅仅简单地解释你可以通过使用一个函数
listOf
创建一个常量的List(很快我们就会讲到的immutable
)。它接收一个任何类型的vararg
(可变长的参数),它会自动推断出结果的类型。还有很多其它的函数可以选择,比如
setOf
,arrayListOf
或者hashSetOf
。
为了优化项目的结构,我也移动了一些类到新的包里面。
我们在上面很简短的代码中看到了很多新的东西,所以我会在下一章讲到它们。我们现在必须要学习一些比如基本类型,变量,属性等比较重要的概念才能继续下去。
后续的文章可以去我的博客里面看。