Eclipse, Android, Scala Made Easy But Still Does Not Work

Eclipse, Android, Scala made easy but still does not work

Here is the solution, to use Android with Eclipse 3.7 and with Scala 3.0.0 without any problems.

  • Install Eclipse 3.7 (for me 3.7.2) and the Android SDK - plus the Java SDK 7v22 if not already in your system. Caution: The special Android ADT Bundle does not allow to install scala (as of June 2013, linux station).
  • Install Android ADT plug-in version 22 for Eclipse by pointing Eclipse to this website :

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

  • Install Scala IDE version 3.0.0 by pointing Eclipse to this website :

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

  • Install the AndroidProguardScala plug-in v47 by pointing Eclipse to this website :

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

Now, to create a scala project,

  1. Create an Android project as usual
  2. Right-click on the project, Configure, Add Scala nature
  3. Right-click on the project, Add AndroidProguardScala nature

You're done.


Scalafying android code

Now good things happen.
First, you can scalafy any activity, and you will get access to scala unique features, such as:

  • Lazy evaluations to define views inside the class body
  • Implicit conversion functions to customize the interaction of view with your code
  • No semicolons and all the syntactic sugar of scala.
  • Use of actors for activities to distinguish the UI thread from the processing thread.

Here is an example of some of them.

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

Now after all the previous boilerplate, it is very useful to write concise activities. Note how we can directly operate on ids as if they were views. Disambiguation is needed as (view: TextView).requestFocus() if the methods can be inferred from various structures.

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

Make sure that the name of the scala file matches the main activity contained in it, in this case it should be MyActivity.scala.

Second, to set up a scala project as a library project, to use is as a base for applications having different resources, follow the regular way of setting up a library project. Right-click on the scala project that you want as a base library project, Properties, Android, and check isLibrary.

To create derivated project using this library and for which you can generate an APK, create a new android project, and without adding any scala or androidproguardscala nature, just right-click, Properties, Android, and add the previous scala project as a library.

UPDATE With the new version of the Android Plug-in, you should go to Project Properties > Build Päth > Order and Export and check Android Private Libraries. This will allow to export the scala library, both in the library project and the main project, even if the main project is not assigned Scala.

TESTING Using the plug-in Robolectric makes it easy to test your android scala project. Just follow the steps for creating a test project, add Scala nature to it. You can even use the new scala debugger, and by adding the scalatest library, you can use should matchers and many other features Scala has.

Android library project with Scala works but not scalable

The solution is to start all over without treeshaker but with the AndroidProguardScala plug-in instead :

https://stackoverflow.com/a/11084146/1287856

Scala, Android and Eclipse

We are using Scala heavily to test our Android code - you can read a writeup of how we're doing so here. We use Ant or SBT to compile - there's an excellent SBT plugin for Android development.

Having said all of that, I'm not sure that I would recommend Scala for production Android development. In particular Scala 2.9.x is basically unusable as there is no good way to get the libraries to work on Android. You can read about the issue here.

It's a real pity, as Android development would benefit considerably from Scala if we could get it working properly.

Class not being built using Scala Eclipse plug-in

I followed Kipton Barros' suggestion from the comments, and installed the 2.0.0 beta of the Scala IDE plug-in for Eclipse. While I find it slightly strange that switching from a final release to a beta release resolved the issue, resolve the issue it did.

(Too bad I can't accept a comment as the answer.)

Scala+Android: Is anybody successfully building and debugging in Eclipse?

In general debugging Scala code running on Android using Eclipse works well and behaves more or less like debugging Scala on regular (non-Android) applications.

I use sbt with sbt-android and android:start-emulator or android:start-device.

Depending on whether I need to debug the application startup, I set the option to wait for the debugger in the developer settings on the device or emulator. To do this, run "DevTools" / "Development Settings". Select your application and check "Wait for Debugger".

Then you have to select the process to debug in DDMS. Make sure the debug port is shown, and then connect with the Eclipse debugger.

A potential cause for the debugger not installing the breakpoints is that the source code line has no direct equivalent in byte code. For comprehensions come to mind.

Android doesn't recognizes Scala activity

The page you're looking at is pretty old. I'd recommend using AndroidPlugin, which is built on top of SBT (https://github.com/jberkel/android-plugin). It handles building, testing, deploying to the emulator/device, etc.

I've got this building my android app, and the only java file I have is the autogenerated R.java.

With SBT you can also generate IDEA and Eclipse configurations, so you should be good to go.



Related Topics



Leave a reply



Submit