【问题标题】:Eclipse, Android, Scala made easy but still does not workEclipse、Android、Scala 变得简单但仍然无法正常工作
【发布时间】:2012-03-29 10:58:23
【问题描述】:

我最近遵循了一种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 类,将 Scala 构建器移到了 Android Package Installer 之前,一切都构建得很完美,但是当我在 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
    }

你认为我应该怎么做才能完成这项工作?感觉离目标很近了。

【问题讨论】:

  • 也许你的ComputeSum 类被ProGuard 剥离了,你不能粘贴你的构建日志吗?
  • 在这种方法中,没有 proGuard 步骤。不错的尝试:)
  • 尝试smali验证你的apk,检查ComputeSum类是否存在
  • 好工具!我不知道。在未编译的文件中,有一个 ComputeSum.smali ,这是否意味着存在 ComputeSum 类?
  • 我想知道我是否要为此开始赏金。如果它有效,那就太棒了。

标签: android eclipse scala


【解决方案1】:

这是解决方案,将 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

你已经完成了。


缩放安卓代码

现在好事发生了。 首先,您可以对任何活动进行 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 &gt; Build Päth &gt; Order and Export 并检查Android Private Libraries。这将允许在库项目和主项目中导出 scala 库,即使主项目未分配 Scala。

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

【讨论】:

  • "其次,您可以将整个项目设置为库项目,无需任何额外的努力,只需右键单击项目,属性,Android,并检查isLibrary,您就可以拥有很多衍生项目你想要的。使用那个 scala 项目的项目不需要具有 scala 特性或 AndroidProguardScala 特性。 - 请您详细说明一下。准确告诉我如何包含其他项目
  • 完成,我重新编写并添加了说明。
  • 另外,该插件的文档(和代码)位于github.com/banshee/AndroidProguardScala(我是作者)
  • @MikaëlMayer 只有日食? IntellijIdea 可以采用这种方法吗?
  • 我不知道 IntellijIdea。该插件仅适用于 Eclipse。也许您可能想尝试另一个命令行插件github.com/jberkel/android-plugin
猜你喜欢
  • 2013-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多