Eclipse, Android, Scala легко, но все равно не работает

Недавно я проследил путь программирования для Android с помощью Scala и Eclipse, который сокращает время кода и время компиляции без использования Proguard или Treeshake.

Следуя этой статье, я должен использовать последнюю сборку Eclipse (3.7), почти последнюю версию Scala (2.8.1), обновленную на эмуляторе версии 10, версии 2.8.3 в Eclipse с предоставленным плагин.

Представленный способ - предоставить конкретную версию образа ramdisk, где мы можем загрузить библиотеки Scala, которые резко сокращают размер кода для загрузки в эмулятор.

Я последовал за шагами, создал мир приветствия, добавил Scala nature, добавил фиктивный класс Scala, переместил конструктор Scala перед установщиком пакетов Android, все прекрасно работает, но когда я запускаю apk on эмулятор от Eclipse, приложение выходит из строя, и я получаю следующую ошибку, которая выглядит как как показано здесь (в конце документа):

    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

Вот решение, чтобы использовать Android с Eclipse 3.7 и Scala 3.0.0 без проблем.

  • Установите Eclipse 3.7 (для меня 3.7.2) и Android SDK - плюс Java SDK 7v22, если это еще не в вашей системе. Внимание: специальный пакет Android ADT Bundle не позволяет установить Scala (по состоянию на июнь 2013 года, Linux-станция).
  • Установите плагин Android ADT версии 22 для Eclipse, указав Eclipse на этот сайт:

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

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

  • Установите плагин AndroidProguardScala v47, указав Eclipse на этот сайт:

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

Теперь, чтобы создать проект Scala,

  • Создайте проект Android как обычно
  • Щелкните правой кнопкой мыши проект, Configure, Add Scala nature
  • Щелкните правой кнопкой мыши проект, Add AndroidProguardScala nature

Вы закончили.


Scalafying android code

Теперь хорошие вещи случаются. Во-первых, вы можете масштабировать любую активность, и вы получите доступ к Scala уникальным функциям, таким как:

  • ленивые оценки для определения представлений внутри тела класса
  • Неявные функции преобразования, чтобы настроить взаимодействие представления с вашим кодом.
  • Точка с запятой и весь синтаксический сахар scala.
  • Использование участников для действий, чтобы отличить поток пользовательского интерфейса от потока обработки.

Вот пример некоторых из них.

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))
}

Теперь, после всего предыдущего шаблона, очень полезно написать краткие действия. Обратите внимание, как мы можем напрямую работать с идентификаторами, как если бы они были представлениями. Несознание необходимо как (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 в качестве проекта библиотеки, использовать его в качестве базы для приложений, имеющих разные ресурсы, следуйте регулярному способу создания проекта библиотеки. Щелкните правой кнопкой мыши проект Scala, который вы хотите в качестве проекта базовой библиотеки, Properties, Android и отметьте isLibrary.
Чтобы создать деривационный проект с использованием этой библиотеки и для которого вы можете создать APK, создайте новый проект для Android и не добавляя никакой природы Scala или orroidproguardscala, просто щелкните правой кнопкой мыши, Properties, Android и добавьте предыдущий Scala проект как библиотека.

ОБНОВЛЕНИЕ. В новой версии Android-модуля вы должны перейти на Project Properties > Build Päth > Order and Export и проверить Android Private Libraries. Это позволит экспортировать библиотеку Scala как в проект библиотеки, так и в главный проект, даже если главный проект не назначен scala.

ТЕСТИРОВАНИЕ Использование плагина Robolectric позволяет легко протестировать ваш проект Android w60. Просто выполните шаги для создания тестового проекта, добавьте к нему внешний вид Scala. Вы даже можете использовать новый отладчик Scala, и, добавив библиотеку scalatest, вы можете использовать символы соответствия и многие другие функции Scala.