Eclipse,Android,Scala变得简单但仍然不起作用

时间:2012-03-29 10:58:23

标签: android eclipse scala

我最近采用了一种方式of programming for Android using Scala and Eclipse,它可以在不使用Proguard或Treeshake的情况下减少代码和编译时间。

在本文之后,我应该能够使用最后一个Eclipse构建(3.7),几乎是在模拟器版本10上更新的Scala(2.8.1)的最新版本,Eclipse中的版本2.8.3以及提供的插件英寸

提供的方法是提供特定的ramdisk映像版本,我们可以上传scala库,这会大大缩小上传到模拟器的代码大小。

我按照步骤,创建了一个hello world,添加了scala本质,添加了一个虚拟scala类,在Android Package Installer之前移动了Scala构建器,一切都构建完美,但是当我在Eclipse的模拟器上启动apk时,应用程序崩溃,我得到以下错误,看起来像 same as presented here(在文件末尾):

    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
    }

你认为我应该做些什么来完成这项工作?我觉得这个目标非常接近。

1 个答案:

答案 0 :(得分:56)

以下是使用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:
  

https://dl-ssl.google.com/android/eclipse/

  

http://download.scala-ide.org/sdk/e37/scala210/stable/site

  

https://androidproguardscala.s3.amazonaws.com/UpdateSiteForAndroidProguardScala

现在,要创建一个scala项目,

  1. 照常创建一个Android项目
  2. 右键点击项目ConfigureAdd Scala nature
  3. 右键点击项目Add AndroidProguardScala nature
  4. 你已经完成了。


    Scalafying android code

    现在好事发生了。 首先,您可以对任何活动进行scalafy,并且您将可以访问scala的独特功能,例如:

    • 延迟评估以定义类主体内的视图
    • 隐式转换功能,用于自定义视图与代码的交互
    • 没有分号和scala的所有语法糖。
    • 使用actors for activities 区分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

    其次,要将scala项目设置为库项目,要使用它作为具有不同资源的应用程序的基础,请遵循regular way of setting up a library project。右键单击要作为基础库项目的scala项目PropertiesAndroid,然后选中isLibrary
    要使用此库创建派生项目并为其生成APK,请创建一个新的android项目,而不添加任何scala或androidproguardscala性质,只需右键单击PropertiesAndroid,然后添加以前的scala项目作为库。

    更新使用新版Android插件,您应该转到Project Properties > Build Päth > Order and Export并检查Android Private Libraries。这将允许导出库项目和主项目中的scala库,即使主项目未分配Scala。

    测试使用插件Robolectric可以轻松测试Android scala项目。只需按照创建测试项目的步骤,添加Scala特性。您甚至可以使用新的scala调试器,通过添加scalatest库,您可以使用Scala和Scala的许多其他功能。