当前位置: 首页 > 工具软件 > Scala Android > 使用案例 >

使用Scala编写Android程序

鱼意远
2023-12-01

环境搭建:

  • 安装JDK和Scala(本人使用2.1)
  • 下载Android SDK,最新版本里面已经包含了Eclipse和 ADT插件
  • 根据Eclipse版本和Scala版本下载对应的Scala IDE插件。http://download.scala-ide.org/
  • 安装AndroidProguardScala,地址https://androidproguardscala.s3.amazonaws.com/UpdateSiteForAndroidProguardScala,安装过程可能会升级Ecplise版本,自动的。
  • 创建Android Project
  • 增加Scala特性,在工程的右键菜单,Scala菜单项下点击Add Scala Nature按钮
  • Add AndroidProguardScala Nature,
    在android项目上点右键,Add AndroidProguardScala Nature

开始Android Scala之旅:

  1. 使用Scala Class重写 MainActivity。
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风格来编写代码。




 

 类似资料: