用 Scala 寫 Android 上的 Google Maps API 程式。

話說這兩天想到一些 Android 加 Google Maps 的應用,於是試著想用 Scala 試著做做看,沒想到竟然遇到了一堆問題,以致於陷入了苦戰之中。

簡單的來講,造成這次的狀況的原因,有以下兩個

  • Scala 的編譯器有蟲,當某個 Java 函式庫參照到另一個 Java 函式庫的 static inner class 時,就會找不到而爆炸。這次爆炸的原因就是 MapView 裡面用了 ViewGroup.LayoutParams。
  • Scala 因為語意上的關係,沒有 static 這種東西,以致於無法存取 static protected 的方法,所以 ItemizedOverlay 又不能用了。

結論:兩個最重要的東西都不能用啊!

為了解決這個問題,我只好自己寫一個 Wrapper,並且把他包成函式庫的形式,方便以後使用,或者以防有人遇到和我一樣的狀況卻求助無門,程式碼和說明在 GitHub 上

總之,目前總算是把 Hello, MapView 的範例跑起來了,程式碼如下,看起來和原來 Java 的版本差不多,這樣的 Wrapper 應該算還可以吧?

package org.bone;

import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.ZoomControls;
import android.widget.LinearLayout;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.OverlayItem;
import com.google.android.maps.Overlay;

import org.maidroid.scalamap.SMapView

class HelloMap extends MapActivity
{
    private lazy val layout      = findViewById (R.id.zoomview).
                                   asInstanceOf[LinearLayout]
    private lazy val mapView     = new SMapView (findViewById(R.id.mapview))
    private lazy val mapOverlays = mapView.getOverlays
    private lazy val drawable    = getResources.
                                   getDrawable (R.drawable.androidmarker)
    private lazy val itemizedoverlay = new HelloItemizedOverlay (drawable)


    override def isRouteDisplayed = false
    override def onCreate(savedInstanceState: Bundle)
    {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.main)

        mapView.setBuiltInZoomControls (true)

        val point1 = new GeoPoint (19240000, -99120000)
        val point2 = new GeoPoint(35410000, 139460000)

        val overlayitem1 = new OverlayItem (point1, "", "")
        val overlayitem2 = new OverlayItem (point2, "", "")

        itemizedoverlay.addOverlay (overlayitem1)
        itemizedoverlay.addOverlay (overlayitem2)

        mapOverlays.add (itemizedoverlay)
    }
}
package org.bone

import android.graphics.drawable.Drawable
import com.google.android.maps.OverlayItem
import java.util.ArrayList

import org.maidroid.scalamap.SItemizedOverlay
import SItemizedOverlay.BOUND_CENTER_BOTTOM

class HelloItemizedOverlay (drawable: Drawable) extends 
      SItemizedOverlay[OverlayItem] (drawable, BOUND_CENTER_BOTTOM)
{
    private lazy val mOverlays = new ArrayList[OverlayItem]

    override def createItem (i: Int) = mOverlays.get(i)
    override def size () = mOverlays.size() 

    def addOverlay (overlay: OverlayItem)
    {
        mOverlays.add (overlay);
        populate ();
    }
}

回響