开始Android Scala之旅:
class MainActivity extends Activity
{
override def onCreate( bundle :Bundle)
{
super.onCreate(bundle)
setContentView(R.layout.activity_main)
val btn = findViewById(R.id.button1).asInstanceOf[Button]
val txt = findViewById(R.id.editText1).asInstanceOf[EditText]
btn.setOnClickListener( new View.OnClickListener(){
def onClick( v : View)
{
txt.setText("Main Activity Using Scala.")
}
})
}
}
实例代码,模仿Java的风格,用Scala的代码重写了MainActivity类。这是使用Scala编写Android的最基本的方式,但是Scala的特性无法得到应有的发挥,这种方式编写android和使用Java几乎是一样的。下面我使用Scala的风格来重写MainActivity方法。
最简单的Scala风格,上面的实例代码中,使用的是接口来处理事件,在Scala中,一般使用函数,而不是接口。
让我在MainActivity类中增加一个隐士转换方法,后的代码。
class MainActivity extends Activity{
/*隐士转换方法*/
implicit def fun2ClickHandler( fun : View=>Unit) = new View.OnClickListener()
{
def onClick(v : View) = fun(v)
}
override def onCreate( bundle : Bundle)
{
super.onCreate(bundle);
this.setContentView(R.layout.activity_main);
val btn = findViewById(R.id.button1).asInstanceOf[Button]
val txt = findViewById(R.id.editText1).asInstanceOf[EditText]
btn.setOnClickListener( (v :View)=>{
txt.setText("使用Scala隐士转换1")
})
}
}
上面的代码,发现,在处理Click方法时,一般都不需要使用到View参数,因此试着把该参数给去掉。后的效果
class MainActivity extends Activity{
implicit def fun2ClickHandler( fun : ()=>Unit) = new View.OnClickListener()
{
def onClick(v : View) = fun()
}
override def onCreate( bundle : Bundle)
{
super.onCreate(bundle);
this.setContentView(R.layout.activity_main);
val btn = findViewById(R.id.button1).asInstanceOf[Button]
val txt = findViewById(R.id.editText1).asInstanceOf[EditText]
btn.setOnClickListener( ()=>{
txt.setText("使用Scala隐士转换1")
})
}
}
不过还有一点别扭,就是在设置btn.btn.setOnClickListener方法的时候多了 ()=>,如果能把这个去掉该多好,这里需要使用到Scala的传名方法,当把lambal当做函数参数时,并且该lambal函数没有接收任何参数时,可以把()给省略。进一步修改后的代码如下:
class MainActivity extends Activity{
implicit def fun2ClickHandler( fun : =>Unit) = new View.OnClickListener()
{
def onClick(v : View) = fun
}
override def onCreate( bundle : Bundle)
{
super.onCreate(bundle);
this.setContentView(R.layout.activity_main);
val btn = findViewById(R.id.button1).asInstanceOf[Button]
val txt = findViewById(R.id.editText1).asInstanceOf[EditText]
btn.setOnClickListener( {
txt.setText("使用Scala隐士转换1")
})
}
}
btn.setOnClickListener( { txt.setText("使用Scala隐士转换1") }) 代码开起来还是有点奇怪,如果可以把()去掉,只留{...}就更完美了,还记得Scala中,如果方法只有一个参数,可以使用{}替代(),因此上面的代码btn.setOnClickListener( { txt.setText("使用Scala隐士转换1") })完全可以修改为btn.setOnClickListener { txt.setText("使用Scala隐士转换1") },自己测试吧。
重构,以便复用。在上面的所有代码中,隐士方法(implicit)是在MainActivity中定义的,到了其它地方就不能使用了,因此很有必要封装一个可以复用的。
可以定义一个RichButton类和其伴生类。
import android.widget.Button
import android.view.View
import android.app.Activity
class RichButton(val button : Button)
{
def onClick( handler : =>Unit)
{
button.setOnClickListener( new View.OnClickListener(){
def onClick(arg0 : View) {
handler
}
})
}
}
object RichButton
{
implicit def button2RichButton(button: Button)= new RichButton(button)
}
让后在MainActivity中,导入该类即可。
import android.app.Activity
import android.os.Bundle
import android.widget.Button
import RichButton._
import android.widget.EditText
import android.view.View
class MainActivity extends Activity{
override def onCreate( bundle : Bundle)
{
super.onCreate(bundle);
this.setContentView(R.layout.activity_main);
val btn = findViewById(R.id.button1).asInstanceOf[Button]
val txt = findViewById(R.id.editText1).asInstanceOf[EditText]
btn onClick {
txt setText "button click,Using Scala By ID!!!"
}
}
}
上面的代码,应该说是非常Scala的风格了,大部分情况下,按钮都是用来设置一个事件处理方法,如果可以像
R.id.button1 onClick {
txt setText "button click,Using Scala By ID!!!"
}
这样注册事件处理方法就更完美了。想法完全可以,不过需要额外的Scala特性的支持,那就是implicit参数。
首先需要在RichButton的伴生类中增加如下方法:
implicit def button2RichButton(id : Int)(implicit cur_activity : Activity)=
{
new RichButton(cur_activity.findViewById(id).asInstanceOf[Button])
}
上面的方法定义了一个implicit参数,调用该方法的地方有一个叫cur_activity的参数。这既是个隐士方法,同时还需要用户提供隐士参数。太多隐士(implicit)了,头不要被弄晕了。
让后在Mainactivity类中,新增一个隐士变量(又来一个隐士)。
class MainActivity extends Activity{
implicit var cur_activity :Activity = null
override def onCreate( bundle : Bundle)
{
cur_activity = this
super.onCreate(bundle);
this.setContentView(R.layout.activity_main);
// val btn = findViewById(R.id.button1).asInstanceOf[Button]
val txt = findViewById(R.id.editText1).asInstanceOf[EditText]
R.id.button1 onClick {
txt setText "button click,Using Scala By ID!!!"
}
}
}
上面代码,定义了一个隐士变量implicit var cur_activity :Activity = null,并且在onCreate中对齐进行了初始化。
至此,已经使用了非常Scala的风格来编写android代码了。当然,很小的程序,写起来比Java的代码还多,但是随着工程的变大,使用Scala的代码量是相当少的,至于少多少,用过了就知道了。30%~50%那是很正常的。10%,说明,你还在使用Java风格来编写代码。