当前位置: 代码迷 >> Android >> 施用Scala编写Android程序
  详细解决方案

施用Scala编写Android程序

热度:53   发布时间:2016-05-01 10:55:38.0
使用Scala编写Android程序

环境搭建:

  • 安装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.Buttonimport android.view.Viewimport android.app.Activityclass 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.Activityimport android.os.Bundleimport android.widget.Buttonimport RichButton._import android.widget.EditTextimport 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风格来编写代码。




 

  相关解决方案