Java Question MapView a non-starter?

warwound

Expert
Licensed User
Longtime User
Hi.

I completed the Android SDK Hello, MapView tutorial and have a working (but basic!) native app that displays a map with a single marker on it.

The code is minimal and looked at first to be simple enough to transplant to a B4A library:

B4X:
package com.martin.pearman.hellogooglemaps;


import android.graphics.drawable.Drawable;
import android.os.Bundle;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import java.util.List;

public class MultiResultsMap extends MapActivity {
   List<Overlay> mapOverlays;
   Drawable drawable;
   GeographOverlay geographOverlay;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        MapView mapView=(MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);
        mapOverlays=mapView.getOverlays();
        drawable=this.getResources().getDrawable(R.drawable.geograph_icon);
        geographOverlay=new GeographOverlay(drawable);
        GeoPoint point=new GeoPoint(19240000, -99120000);
        OverlayItem overlayItem=new OverlayItem(point, "", "");
        geographOverlay.addOverlay(overlayItem);
        mapOverlays.add(geographOverlay);
    }

    @Override
    protected boolean isRouteDisplayed(){
       return false;
    }
}

and

B4X:
package com.martin.pearman.hellogooglemaps;

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

public class GeographOverlay extends ItemizedOverlay<OverlayItem> {
   private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>();

   public GeographOverlay(Drawable defaultMarker) {
      super(boundCenterBottom(defaultMarker));
   }

   public void addOverlay(OverlayItem overlay) {
      mOverlays.add(overlay);
      populate();
   }

   @Override
   protected OverlayItem createItem(int index) {
      return mOverlays.get(index);
   }

   @Override
   public int size() {
      return mOverlays.size();
   }

}

I started a new library aiming first to just add a MapView to a B4A app and straightaway found it a non-starter.

A MapView can only be added to an activity that extends the MapActivity class - you cannot add one to an activity that extends the Activity class.

Here's the library code:

B4X:
package uk.co.martinpearman.geographmap;

import com.google.android.maps.MapView;

import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ActivityObject;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Hide;
import anywheresoftware.b4a.BA.Version;
import anywheresoftware.b4a.objects.ViewWrapper;

@ActivityObject
@Author("Martin Pearman")
@Hide
@ShortName("GeographMap")
@Version((float) 1.0)
public class GeographMap extends ViewWrapper<MapView> {
   @Hide
   public void innerInitialize(BA ba, String eventName, boolean keepOldObject) {
      if (!keepOldObject) {
         setObject(new MapView(ba.context, "0k1SIJwKfCiZTK7UT7nWbsF2jwt9BgsyP5H5SLQ"));
         super.innerInitialize(ba, eventName, true);
      }
   }
}

The library compiles but when i try to use it there is no GeographMap type available in the code completion list.

I'm assuming that this is because the B4A activity extends Activity and NOT MapActivity..?

Looking at the compiled B4A source for any B4A project i see the activity extends Activity (as expected) and implements B4AActivity.

What seemed like a simple task now looks to be unworkable or impossible.

Even if i could develop a B4AMapActivity there would be no way to integrate it into the B4A IDE - we have activity, code and service modules and i'm assuming this is where a 'map module' would also be available as a new module option?

So B4A does not support MapActivity and there's no way to add it - is that correct?

A solution for my app might be to compile a native MapView activity that contains all the functionality i require and then when my app requires the map simply use an INTENT to start my native sdk MapView app - hopefully i could pass values to the MapView app from my B4A app so the MapView app knows where to create map markers.

Trouble is i want the map to display in a tab in a tabhost which i cannot do with B4A.

Another idea was to import my compiled B4A app into Eclipse and look at modifying it - adding native SDK code and then re-compiling it.
Is that possible - to take a working compiled B4A project and add native SDK code to it and then re-compile?

Thanks.

Martin.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
It is possible to create a MapView library however it is not simple.
It seems to me that MapView is a bit cumbersome and the WebView solution is much simpler. What are the main advantages of MapView over showing the map with WebView?

About the library. You can add an activity in the same way that PreferenceActivity library does it. The user will need to add the activity declaration to the manifest file.
You will still need to communicate with this activity using intents. This is standard way to do it in Android.
 

warwound

Expert
Licensed User
Longtime User
It seems to me that MapView is a bit cumbersome and the WebView solution is much simpler. What are the main advantages of MapView over showing the map with WebView?

The main advantages to MapView over a WebView with a Google Maps API map are (to me):

1) The speed at which the view is created and becomes useable.
A WebView with a Google Maps API map is far from fast to load, the more features enabled on the map the slower the map is to load and use.
On device orientation change this is proving to be a major problem in an app i'm creating.

2) Restoring map state with a WebView based map is just as painful - maybe more so!

Let's say i create a map with a user location marker and say 15 nearby points of interest markers.
When the map first loads i set a default map type (roadmap, satellite etc) and then the map automatically pans and zooms itself to fully display all markers on the screen.

The user can change the map center, zoom level and map type.
So each time map center, zoom level or map type are changed, the map needs to send the latest map state to B4A so it can be restored on orientation change.
(JSInterface is used here).

Now imagine a device orientation change - we have the unavoidable delay as the WebView re-requests the Google Maps API library from Google's servers.
The delay as the WebView parses the HTML page and all javascript contained in that page.
Then the WebView can re-build the map.
Finally - we have to wait for the API to finish building the map before we can restore map center, zoom level and map type from before the orientation change.

Lots of network re-requests, lots of time-consuming HTML DOM manipulation in the map javascript and no small amount of processing required from the device CPU.

3) Pinch to zoom!
We all like pinch to zoom i think - it's so useable.
A Google Maps API map in a WebView has no pinch to zoom function - the MapView pinch to zoom works a treat.

So performance on orientation change is my biggest dislike of using the Google Maps API in a WebView.
Pinch to zoom is the icing on the cake.

About the library. You can add an activity in the same way that PreferenceActivity library does it. The user will need to add the activity declaration to the manifest file.
You will still need to communicate with this activity using intents. This is standard way to do it in Android.

If i understand, then this is a way that i can add a native sdk (or indeed any) activity to my B4A project?
For the project i'm working on i really want a MapView in a TabHost tab - is this possible?

And finally - is it possible to open a compiled B4A project in Eclipse and make any modifications?

Thanks.

Martin.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You might consider disabling orientation at all, if it is suitable for your application.

If i understand, then this is a way that i can add a native sdk (or indeed any) activity to my B4A project?
Yes. Interacting with this activity is not simple. You will need to use a service for that.
For the project i'm working on i really want a MapView in a TabHost tab - is this possible?
MapView cannot be added to a TabHost as it is a complete Activity (don't ask me why Google implement it in such way).

And finally - is it possible to open a compiled B4A project in Eclipse and make any modifications?
Theoretically it is possible. Though I don't recommend you to. It will be easier to create a complete activity in Java and add it to your B4A project.
 

miataman

Member
Licensed User
Hi everybody,
have a you a news for API mapview in the Basic4Android, tips or externe library but (without WebView please) ?
many thanks, stef
 

warwound

Expert
Licensed User
Longtime User
Hi.

I'm trying yet again to add a MapView to an application and have made some progress BUT have run into problems...

Here's my Eclipse project code:

B4X:
package uk.co.martinpearman.b4amapactivity;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

import android.content.Intent;
import android.os.Bundle;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ActivityObject;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.DependsOn;
import anywheresoftware.b4a.BA.Permissions;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;

@ActivityObject
@Author("Martin Pearman")
@ShortName("MapActivity")
@Version(1F)
@DependsOn(values={"maps"})
@Permissions(values={"android.permission.INTERNET"})


public class B4AMapActivity extends MapActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        MapView mapView = new MapView(this, "0k1SIJwKfCiZzLeQxv6UEHoTeHXJzmX7uYlDXUg");
        setContentView(mapView);   
    }
   @Override
   protected boolean isRouteDisplayed() {
      return false;
   }
   public Intent CreateIntent(){
      Intent intent=new Intent();
      intent.setClass(BA.applicationContext, B4AMapActivity.class);
      return intent;
   }
}

And my B4A code:

B4X:
Sub Process_Globals
End Sub

Sub Globals
   Dim Button1 As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Button1.Initialize("Button1")
   Button1.Text="Start MapActivity"
   Activity.AddView(Button1, 0, 10dip, 100%x, 10%y)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
   Log("Start MapActivity")
   
   Dim MyMap As MapActivity
   
   StartActivity(MyMap.CreateIntent)
End Sub

The javadoc compilation fails with these errors:

Loading source file N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java...
Constructing Javadoc information...
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:3: package com.google.android.maps does not exist
import com.google.android.maps.MapActivity;
^
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:4: package com.google.android.maps does not exist
import com.google.android.maps.MapView;
^
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:6: package android.content does not exist
import android.content.Intent;
^
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:7: package android.os does not exist
import android.os.Bundle;
^
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:24: cannot find symbol
symbol: class MapActivity
public class B4AMapActivity extends MapActivity {
^
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:26: cannot find symbol
symbol : class Bundle
location: class uk.co.martinpearman.b4amapactivity.B4AMapActivity
public void onCreate(Bundle savedInstanceState) {
^
N:\Basic4Android\MapViewActivity\eclipse\src\uk\co\martinpearman\b4amapactivity\B4AMapActivity.java:36: cannot find symbol
symbol : class Intent
location: class uk.co.martinpearman.b4amapactivity.B4AMapActivity
public Intent CreateIntent(){
^
[-doclet, BADoclet]
[-docletpath, N:\Basic4Android\Doclet]
[-sourcepath, N:\Basic4Android\MapViewActivity\eclipse\gen;N:\Basic4Android\MapViewActivity\eclipse\src]
[-classpath, C:\Program Files (x86)\Anywhere Software\Basic4android\Libraries\B4AShared.jar]
[-public]
[-b4atarget, N:\Basic4Android\libraries\MapActivity.xml]
starting....
Working with class: uk.co.martinpearman.b4amapactivity.B4AMapActivity
finish: N:\Basic4Android\libraries\MapActivity.xml
7 warnings

The B4A project fails to compile with error:

Compiling code. 0.01
Generating R file. 0.00
Compiling generated Java code. Error
B4A line: 31
Dim MyMap As MapActivity
javac 1.6.0_24
src\uk\co\martinpearman\b4a\mapactivityexample\main.java:276: cannot access com.google.android.maps.MapActivity
class file for com.google.android.maps.MapActivity not found
_mymap = new uk.co.martinpearman.b4amapactivity.B4AMapActivity();Debug.locals.put("MyMap", _mymap);
^
1 error

I manually copied the Google 'map.jar' file from the SDK folder to my B4A additional libraries folder and the B4A project now compiles BUT a click on Button1 causes an error:

Start MapActivity


main_button1_click (B4A line: 31)


Dim MyMap As MapActivity



java.lang.RuntimeException: stub
at com.google.android.maps.MapActivity.<init>(Unknown Source)
at uk.co.martinpearman.b4amapactivity.B4AMapActivity.<init>(B4AMapActivity.java:24)
at uk.co.martinpearman.b4a.mapactivityexample.main._button1_click(main.java:276)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:113)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:101)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:97)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:49)
at android.view.View.performClick(View.java:2408)
at android.view.View$PerformClick.run(View.java:8816)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
java.lang.RuntimeException: stub

Dimming MyMap in Globals instead of the Button1_Click Sub causes the activity to fail with the same exception as soon as it loads.
So B4A is not able to create an instance of my 'MapActivity'.

I have the latest version of the B4A Doclet and wonder what value to use in DependsOn so that the maps.jar file is automatically made available to the B4A compiler.
Must i manually copy it to the B4A additional libraries folder?

Why is the javadoc creation failing - is this related to any of the other errors?

In Eclipse i have referenced B4AShared.jar and Core.jar in 'Referenced Libraries'.
android.jar and maps.jar are both referenced under Google APIs.

Can anyone offer some answers?

I can upload any of the project source if need be.

Thanks.

Martin.


PS I wonder if i should or could simply compile my working Eclipse activity and add that to a B4A project (as an APK is that possible?).
That way B4A wouldn't be compiling my MapActivity but my B4A application would simply start it when required.
 

warwound

Expert
Licensed User
Longtime User
Hi.

I tried adding the contents of maps.jar to android.jar but still had much the same problems.

Then i realised i was making a mistake - i hadn't started with a B4A library project in Eclipse but was simply trying to export a working native Android app to a library :signOops:

So i've started yet again.

I have my Eclipse library project:

B4X:
package uk.co.martinpearman.b4a.mapactivity;

import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;

import android.content.Intent;
import android.os.Bundle;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.ActivityObject;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.DependsOn;
import anywheresoftware.b4a.BA.Permissions;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;

@ActivityObject
@Author("Martin Pearman")
@ShortName("MapActivity")
@Version(1F)
@DependsOn(values={"maps"})
@Permissions(values={"android.permission.INTERNET"})

public class B4AMapActivity extends MapActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        MapView mapView = new MapView(this, "0k1SIJwKfCiZzLeQxv6UEHoTeHXJzmX7uYlDXUg");
        setContentView(mapView);   
    }
   @Override
   protected boolean isRouteDisplayed() {
      return false;
   }
   public Intent CreateIntent(){
      Intent intent=new Intent();
      intent.setClass(BA.applicationContext, B4AMapActivity.class);
      return intent;
   }
}

My B4A test application:

B4X:
'Activity module
Sub Process_Globals

End Sub

Sub Globals
   Dim MyMap As MapActivity
   Dim Button1 As Button
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Button1.Initialize("Button1")
   Button1.Text="Start MapActivity"
   Activity.AddView(Button1, 0, 10dip, 100%x, 10%y)
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Button1_Click
   Log("Start MapActivity")
   
   Dim MyMap As MapActivity
   StartActivity(MyMap.CreateIntent)
End Sub

And my modified manifest file:

B4X:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="8" />
<supports-screens android:largeScreens="true" 
    android:normalScreens="true" 
    android:smallScreens="true" 
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.
AddApplicationText(<activity android:name="uk.co.martinpearman.b4a.mapactivity"/>)
AddApplicationText(<uses-library android:name="com.google.android.maps" />)

The library never compiles with maps.jar included but i have temporarily copied maps.jar to my additional libraries folder so i can at least make some progress.

The javadoc xml file now compiles with no errors so that's a step forward.

But the app force closes as soon as it tries to Dim an instance of my MapActivity library.
The unfiltered log shows this:

Displayed activity uk.co.martinpearman.b4a.mapactivitydemo/.main: 1877 ms (total 1877 ms)
Class resolved by unexpected DEX: Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity;(0x45f3e5a8):0x12d808 ref [Lcom/google/android/maps/MapActivity;] Lcom/google/android/maps/MapActivity;(0x45f3e5a8):0x123f78
(Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity; had used a different Lcom/google/android/maps/MapActivity; during pre-verification)
Unable to resolve superclass of Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity; (307)
Link of class 'Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity;' failed
Shutting down VM
threadid=1: thread exiting with uncaught exception (group=0x4001d800)
FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.mapactivity.B4AMapActivity
at uk.co.martinpearman.b4a.mapactivitydemo.main._globals(main.java:316)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:113)
at uk.co.martinpearman.b4a.mapactivitydemo.main.initializeGlobals(main.java:201)
at uk.co.martinpearman.b4a.mapactivitydemo.main.afterFirstLayout(main.java:81)
at uk.co.martinpearman.b4a.mapactivitydemo.main.access$100(main.java:16)
at uk.co.martinpearman.b4a.mapactivitydemo.main$WaitForLayout.run(main.java:72)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)


at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
at dalvik.system.DexFile.defineClass(Native Method)
at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:209)
at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:203)
at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
at java.lang.ClassLoader.loadClass(ClassLoader.java:532)
... 17 more
Force finishing activity uk.co.martinpearman.b4a.mapactivitydemo/.main
Activity pause timeout for HistoryRecord{46114030 uk.co.martinpearman.b4a.mapactivitydemo/.main}
-- loadPreferences()
Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@45ffd980
Sending signal. PID: 300 SIG: 9
WIN DEATH: Window{460307a0 uk.co.martinpearman.b4a.mapactivitydemo/uk.co.martinpearman.b4a.mapactivitydemo.main paused=false}
Process uk.co.martinpearman.b4a.mapactivitydemo (pid 300) has died.
WIN DEATH: Window{46083418 uk.co.martinpearman.b4a.mapactivitydemo/uk.co.martinpearman.b4a.mapactivitydemo.main paused=false}
GC_EXPLICIT freed 2102 objects / 147248 bytes in 88ms
Activity destroy timeout for HistoryRecord{46114030 uk.co.martinpearman.b4a.mapactivitydemo/.main}

The relevant parts seem to be:

Class resolved by unexpected DEX: Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity;(0x45f3e5a8):0x12d808 ref [Lcom/google/android/maps/MapActivity;] Lcom/google/android/maps/MapActivity;(0x45f3e5a8):0x123f78
(Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity; had used a different Lcom/google/android/maps/MapActivity; during pre-verification)
Unable to resolve superclass of Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity; (307)
Link of class 'Luk/co/martinpearman/b4a/mapactivity/B4AMapActivity;' failed

and:

FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: uk.co.martinpearman.b4a.mapactivity.B4AMapActivity

Any ideas?

Martin.
 

warwound

Expert
Licensed User
Longtime User
I had a Google for some info on this these errors and the first three results all relate to the SDK MapActivity not being found:

Class resolved by unexpected DEX Unable to resolve superclass of - Google Search

The common mistake seems to be manually adding the maps.jar archive to a project rather than letting Eclipse do it automatically.

This result: android - Force Down error in MapView - Stack Overflow states:

Somehow, your device or emulator has a different implementation of com.google.android.maps.MapActivity than what your compiler used. That should not be possible under normal circumstances. It suggests that you have seriously messed up your build process, such as manually adding the Maps add-on JAR to your build path rather than just setting a Maps-enabled target.

The other results all indicate that the error arises when the build path is not correctly configured.
That is the build path for a native Android SDK project not a B4A project.

There must be something going on 'behind the scenes' when i create a native Android project and select the Google APIs (v8) as the target build.

Anyway i'm getting past my java/android skill level here so will have to do some research and try to find a way forward.

I'll keep this thread updated with any progress i make.

Martin.
 

warwound

Expert
Licensed User
Longtime User
MapView - a work in progress!!

At last i have made some progress and have a working MapView!!

I had given up on ever developing a MapView for B4A as there just seemed to be no way to create an activity that extends the MapActivity class within B4A.
However on my internet travels i came across OSMDroid.

osmdroid provides Tools / Views to interact with OpenStreetMap-Data.

The OpenStreetMapView is a (almost) full/free replacement for Androids MapView class.

OSMDroid can be used in a 'normal' Android Activity - it does not require that the activity extends the MapActivity class.

So after a couple of days i have a working, but very basic, MapView library.
What i shall be doing next is to learn more about the OSMDroid API so i can add more features to the library and then i'll start a new thread.
Until then i'll release this working prototype so those that are interested can have a look.

The library has just a few methods/properties:

Center() As Double

Returns the current map center as an array of two Double types.
The array elements are Latitude, Longitude.
This property is read-only.

GetTileSources As List

Returns a List of Strings which are the names of all the available TileSources which can be selected.
Values that i have found to work are "CycleMap", "Mapnik", "MapquestAerial", "MapquestOSM" and "OSMPublicTransport".
The List will contain other TileSources BUT these seem to require an API key or a licence to access those tiles.
The default TileSource is "Mapnik".

setCenter (Latitude As Double, Longitude As Double)

Set the map center.

setMultiTouchEnabled (MultiTouchEnabled As Boolean)

Enable or disable multi-touch zoom in the MapView.

setTileSource (TileSource As String)

Set the TileSource.
Valid Strings are those returned by the GetTileSources method.

setZoomEnabled (ZoomEnabled As Boolean)

Enable or disable the MapView zoom control.

Zoom As Int

Get or set the current map zoom level.
Maximum zoom level varies with the choice of TileSource.
Some TileSources have very limited zoom levels available such as "MapquestAerial"

There are no methods to add markers/overlays/polylines/polygons etc.

And here's my demo code:

B4X:
'Activity module
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
   Dim Latitude As Double
   Dim Longitude As Double
   Dim TileSource As String
   Dim ZoomLevel As Int
End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim MapView1 As MapView
   Dim TileSourceSpinner As Spinner
End Sub

Sub Activity_Create(FirstTime As Boolean)
   If FirstTime Then
      Latitude=52.75610
      Longitude=0.39748
      TileSource="Mapnik"
      ZoomLevel=12
   End If
   
   MapView1.Initialize("")
   TileSourceSpinner.Initialize("TileSourceSelect")
   
   Activity.AddView(MapView1, 0, 48dip, 100%x, 100%y-48dip)
   Activity.AddView(TileSourceSpinner, 0, 0, 100%x, 48dip)
   
   MapView1.MultiTouchEnabled=True
   MapView1.ZoomEnabled=True
   
   MapView1.Zoom=ZoomLevel
   MapView1.setCenter(Latitude, Longitude)
   
   TileSourceSpinner.AddAll(MapView1.GetTileSources)
   TileSourceSpinner.Prompt="Select a TileSource"
   TileSourceSpinner.SelectedIndex=TileSourceSpinner.IndexOf(TileSource)
   TileSourceSelect_ItemClick(TileSourceSpinner.SelectedIndex, TileSourceSpinner.SelectedItem)
   
   Log("Activity_Create Latitude="&Latitude&", Longitude="&Longitude&", TileSource="&TileSource&", ZoomLevel="&ZoomLevel)
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   If UserClosed=False Then
      Dim MapCenter() As Double
      MapCenter=MapView1.Center
      Latitude=MapCenter(0)
      Longitude=MapCenter(1)
      ZoomLevel=MapView1.Zoom
      Log("Activity_Pause Latitude="&Latitude&", Longitude="&Longitude&", TileSource="&TileSource&", ZoomLevel="&ZoomLevel)
   End If
End Sub

Sub TileSourceSelect_ItemClick (Position As Int, Value As Object)
   '   Valid values (tested so far) are "CycleMap", "Mapnik", "MapquestAerial", "MapquestOSM", "OSMPublicTransport"
   '   "Mapnik" is the default TileSource
   '   Some TileSources have very limited zoom levels available such as "MapquestAerial"
   '   Others seem unreliable and don't always display a tile
   '   It may be that an API key or license is required to use some TileSources
   '   Look at the unfiltered Log to see related error messages
   TileSource=Value
   MapView1.TileSource=TileSource
End Sub

Displays a default Mapnik map centered on sunny Norfolk, UK.
A spinner allows you to select TileSource and a few process globals enable the map zoom, center and TileSource to be restored on orientation change.

Demo code and library files are attached.
Note that as well as the two normal library files OSMDroid.jar and OSMDroid.xml, there are two additional files osmdroid-android-3.0.6.jar and slf4j-android-1.6.1-RC1.jar which need to be copied to your B4A Additional libraries folder.

I'm looking forward to learning the OSMDroid API and the first thing i'll do is add support for basic markers.
Documentation for the API seems rather brief so i have no idea how long it will take to go from this prototype to a more fully featured working library.

Oh and one last thing - OSMDroid has support for offline mode.
You can download the tiles for an area, transfer them to your device's SD card and browse the map without an internet connection.
See MobileAtlasCreator for more information.

Martin.
 
Last edited:
Top