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

Mik*_*yer 38 eclipse android scala

我最近采用了一种使用Scala和Eclipse进行Android编程的方法,它可以在不使用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时,应用程序崩溃了我收到以下错误,看起来与此处提供相同(在文档末尾):

    03-29 10:29:38.505: E/AndroidRuntime(839): java.lang.NoClassDefFoundError: upg.TestSinceInstallation.ComputeSum
Run Code Online (Sandbox Code Playgroud)

如果我删除活动文件中的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);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是ComputeSum.scala文件

    package upg.TestSinceInstallation

    class ComputeSum(a: Int, b: Int) {
      def getResut() : Int = a + b
    }
Run Code Online (Sandbox Code Playgroud)

您认为我应该怎么做才能使这项工作成功?我感觉如此接近目标.

Mik*_*yer 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. 右键单击项目Configure,Add Scala nature
  3. 右键单击项目, Add AndroidProguardScala nature

你完成了.


Scalafying安卓代码

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

  • 延迟评估以定义类主体内的视图
  • 隐式转换函数用于自定义视图与代码的交互
  • 没有分号和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))
}
Run Code Online (Sandbox Code Playgroud)

现在,在所有以前的样板之后,编写简洁的活动非常有用.请注意我们如何直接对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
  }
}
Run Code Online (Sandbox Code Playgroud)

确保scala文件的名称与其中包含的主要活动匹配,在这种情况下应该是MyActivity.scala.

其次,要将scala项目设置为库项目,使用它作为具有不同资源的应用程序的基础,遵循常规方式设置库项目.在要作为一个基础库项目,斯卡拉项目上右键单击Properties,Android并检查isLibrary.
若要使用这个库项目的推导,以及您可以生成APK,创建一个新的Android项目,并且不添加任何阶或androidproguardscala性质,只需右键点击,Properties,Android,并添加以前的斯卡拉项目作为库.

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

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

  • 此外,该插件的doc(和代码)位于https://github.com/banshee/AndroidProguardScala(我是作者) (5认同)