Eclipse,Android,Scala变得简单,但仍然无法正常工作
我最近遵循了使用Scala和Eclipse进行Android编程的方法,这样可以在不使用Proguard或Treeshake的情况下减less代码和编译时间。
在本文后面,我应该能够使用最后一个Eclipse版本(3.7),几乎是最新版本的Scala(2.8.1)在模拟器版本10上更新,在Eclipse中使用提供的插件版本2.8.3。
提出的方法是提供一个特定的ramdisk映像版本,我们可以上传scala库,这大大缩小了代码上传到仿真器的大小。
我遵循这些步骤,创build了一个hello world,添加了scala自然,添加了一个scala类,在Android Package Installer之前移动了Scala构build器,一切都很完美,但是当我从Eclipse的模拟器上启动apk时,应用程序崩溃我得到以下错误,看起来像这里 (在文档的末尾)相同:
03-29 10:29:38.505: E/AndroidRuntime(839): java.lang.NoClassDefFoundError: upg.TestSinceInstallation.ComputeSum
如果我删除活动文件中的scala引用,它运行良好。
这里是TestSinceInstallation.java文件:
package upg.TestSinceInstallation; import android.app.Activity; import android.os.Bundle; import upg.TestSinceInstallation.ComputeSum; public class TestSinceInstallationActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); int a = 1; int b = 5; ComputeSum cs = new ComputeSum(a, b); if(cs.getResut() == 6) { setContentView(R.layout.main); } } }
这里是ComputeSum.scala文件
package upg.TestSinceInstallation class ComputeSum(a: Int, b: Int) { def getResut() : Int = a + b }
你认为我应该怎么做才能做到这一点? 我觉得如此接近目标。
下面是解决scheme,使用Android的Eclipse 3.7和Scala 3.0.0没有任何问题。
- 安装Eclipse 3.7 (适用于我3.7.2)和Android SDK – 如果您的系统中尚未安装Java SDK 7v22 。 注意:特殊的Android ADT Bundle不允许安装scala(截至2013年6月,linux站) 。
- 通过将Eclipse指向此网站来安装适用于Eclipse的Android ADT插件版本22:
- 通过将Eclipse指向此网站来安装Scala IDE 3.0.0版 :
- 将Eclipse指向此网站来安装AndroidProguardScala插件v47:
https://androidproguardscala.s3.amazonaws.com/UpdateSiteForAndroidProguardScala
现在,要创build一个scala项目,
- 照常创build一个Android项目
- 右键单击该项目,
Configure
,Add Scala nature
- 右键单击该项目,
Add AndroidProguardScala nature
你完成了。
Scalafying android代码
现在好事发生了。 首先,你可以scalafy任何活动,你会得到访问scala独特的function,如:
- 懒惰的评估来定义类体内的视图
- 隐式转换函数来定制视图与代码的交互
- 没有分号和scala的所有语法糖。
- 使用actor来区分UI线程和处理线程。
这是其中一些例子。
package com.example.testing; import android.app.Activity import android.os.Bundle import scala.collection.mutable.Map import android.view.View import android.widget.SeekBar import android.widget.ImageButton import android.graphics.drawable.Drawable import android.widget.TextView trait ActivityUtil extends Activity { implicit def func2OnClickListener(func: (View) => Unit):View.OnClickListener = { new View.OnClickListener() { override def onClick(v: View) = func(v) } } implicit def func2OnClickListener(code: () => Unit):View.OnClickListener = { new View.OnClickListener() { override def onClick(v: View) = code() } } private var customOnPause: () => Unit = null override def onPause() = { super.onPause() if(customOnPause != null) customOnPause() } def onPause(f: =>Unit) = { customOnPause = {() => f} } private var customOnCreate: Bundle => Unit = null override def onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) if(customOnCreate != null) customOnCreate(savedInstanceState) } def onCreate(f: Bundle => Unit) = { customOnCreate = f } // Keep references alive when fetched for the first time. private implicit val vMap = Map[Int, View]() private implicit val ibMap = Map[Int, ImageButton]() private implicit val sbMap = Map[Int, SeekBar]() private implicit val tvMap = Map[Int, TextView]() private implicit val dMap = Map[Int, Drawable]() def findView[A <: View](id: Int)(implicit v: Map[Int, A]): A = v.getOrElseUpdate(id, findViewById(id).asInstanceOf[A]) def findDrawable[A <: Drawable](id: Int)(implicit v: Map[Int, A]): A = v.getOrElseUpdate(id, getResources().getDrawable(id).asInstanceOf[A]) implicit class RichView(b: View) { // Scala 2.10 ! def onClicked(f: =>Unit) = b.setOnClickListener{ () => f } } // Implicit functions to operate directly on integers generated by android. implicit def findViewImageButton(id: Int): ImageButton = findView[ImageButton](id) implicit def findViewSeekBar(id: Int): SeekBar = findView[SeekBar](id) implicit def findViewTextView(id: Int): TextView = findView[TextView](id) implicit def findDrawable(id: Int): Drawable = findDrawable[Drawable](id) implicit def findRichView(id: Int): RichView = toRichView(findView[View](id)) }
现在所有以前的样板,编写简洁的活动是非常有用的。 请注意我们如何直接操作ID,就好像它们是视图一样。 如果可以从各种结构推断方法,则需要消除歧义作为(view: TextView).requestFocus()
。
// Now after all the boilerplate, it is very useful to write consise activities class MyActivity extends Activity with ActivityUtil { import R.id._ // Contains R.id.button, R.id.button2, R.id.button3, R.id.mytextview lazy val my_button: ImageButton = button //In reality, R.id.button lazy val his_button: ImageButton = button2 onCreate { savedInstanceState => // The type is automatically inferred. setContentView(R.layout.main) my_button.setOnClickListener(myCustomReactClick _) his_button.setOnClickListener { () => //.... Scala code called after clicking his_button } button3.onClicked { // Awesome way of setting a method. Thanks Scala. } mytextview.setText("My text") // Whoaaa ! setText on an integer. (mytextview: TextView).requestFocus() // Disambiguation because the method is ambiguous // Note that because of the use of maps, the textview is not recomputed. } def myCustomReactClick(v: View) = { // .... Scala code called after clicking my_button } onPause{ // ... Custom code for onPause } }
确保scala文件的名称与其中包含的主要活动相匹配,在这种情况下,它应该是MyActivity.scala
。
其次,为了build立一个scala项目作为一个图书馆项目,使用是作为一个资源不同的应用程序的基础,遵循build立一个图书馆项目的常规方式 。 右键单击想要作为基础库项目的Properties
, Android
的scala项目,然后检查isLibrary
。
要使用这个库创build衍生项目,并为此生成一个APK,创build一个新的android项目,并且不添加任何scala或androidproguardscala本质,只需右键单击Properties
, Android
,然后将以前的scala项目添加为库。
更新使用新版本的Android插件,您应该转到Project Properties > Build Päth > Order and Export
然后检查Android Private Libraries
。 这将允许在库项目和主项目中导出scala库,即使主项目没有分配Scala。
testing使用插件Robolectric可以轻松testing您的android scala项目。 只需按照创buildtesting项目的步骤,向其中添加Scala自然。 你甚至可以使用新的Scaladebugging器,并通过添加Scalatest库,你可以使用应该匹配器和许多其他functionScala。