FATAL EXCEPTION in LayerManager with a copy of the sample code

679 views
Skip to first unread message

Chris Dewhurst

unread,
Jun 27, 2018, 9:02:16 AM6/27/18
to mapsforge-dev
I am writing an app that started with Google Maps, but I've decided to make the transition to MapForge because it suits my needs better.

I started with the sample applications from https://github.com/mapsforge/mapsforge and using Android Studio, I can get these samples working without any problem.

In my own app (also under Android Studio), I tried to start building from the ground-up to re-factor to use MapsForge code. However, whatever I try, I end up with the same FATAL EXCEPTION that I can't get past. What's most intriguing is that the code I'm using is a straight copy of the sample app code from the file SimplestMapViewer.java (https://github.com/mapsforge/mapsforge/blob/master/mapsforge-samples-android/src/main/java/org/mapsforge/samples/android/SimplestMapViewer.java)

Whatever I have tried, I get this bug when the application starts:

D/EGL_emulation: eglMakeCurrent: 0xebc058a0: ver 3 1 (tinfo 0xebc03ad0)

                 --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: LayerManager
                  Process: com.fermovian.mytfl1, PID: 27834
                  java.lang.IllegalArgumentException: Invalid Region.Op - only INTERSECT and DIFFERENCE are allowed
                      at android.graphics.Canvas.checkValidClipOp(Canvas.java:779)
                      at android.graphics.Canvas.clipRect(Canvas.java:918)
                      at org.mapsforge.map.android.graphics.AndroidCanvas.resetClip(AndroidCanvas.java:216)
                      at org.mapsforge.map.layer.TileLayer.draw(TileLayer.java:78)
                      at org.mapsforge.map.layer.LayerManager.doWork(LayerManager.java:94)
                      at org.mapsforge.map.util.PausableThread.run(PausableThread.java:147)

The only difference I have is that I have a splash-screen. I've also tried eliminating, but to no avail, so I'm not focussing on that. I've tried launching directly into the map activity, and got exactly the same result. The splash-screen simply shows an image and then transfers control to the main screen, but I have initialised the AndroidGraphicFactory within this, as below...

public class SplashActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

AndroidGraphicFactory.createInstance(getApplication());

Intent intent = new Intent(this, MapActivity.class);
startActivity(intent);
finish();
}
}

Here is my MapActivity class, but apart from the name, it's identical to the SimplestMapViewer class from the samples, as indicated before. Indeed, to try to track down the problem, even the comments are the same:

/**
* The simplest form of creating a map viewer based on the MapViewerTemplate.
* It also demonstrates the use simplified cleanup operation at activity exit.
*/
public class MapActivity extends MapViewerTemplate {

/**
* This MapViewer uses the built-in Osmarender theme.
*
* @return the render theme to use
*/
@Override
protected XmlRenderTheme getRenderTheme() {
return InternalRenderTheme.OSMARENDER;
}

/**
* This MapViewer uses the standard xml layout in the Samples app.
*/
@Override
protected int getLayoutId() {
return R.layout.activity_map;
}

/**
* The id of the mapview inside the layout.
*
* @return the id of the MapView inside the layout.
*/
@Override
protected int getMapViewId() {
return R.id.map;
}

/**
* The name of the map file.
*
* @return map file name
*/
@Override
protected String getMapFileName() {
return "germany.map";
}

/**
* Creates a simple tile renderer layer with the AndroidUtil helper.
*/
@Override
protected void createLayers() {
TileRendererLayer tileRendererLayer = AndroidUtil.createTileRendererLayer(this.tileCaches.get(0),
this.mapView.getModel().mapViewPosition, getMapFile(), getRenderTheme(), false, true, false);
this.mapView.getLayerManager().getLayers().add(tileRendererLayer);
}

@Override
protected void createMapViews() {
super.createMapViews();
}

/**
* Creates the tile cache with the AndroidUtil helper
*/
@Override
protected void createTileCaches() {
this.tileCaches.add(AndroidUtil.createTileCache(this, getPersistableId(),
this.mapView.getModel().displayModel.getTileSize(), this.getScreenRatio(),
this.mapView.getModel().frameBufferModel.getOverdrawFactor()));
}

@Override
protected MapPosition getInitialPosition() {
int tileSize = this.mapView.getModel().displayModel.getTileSize();
byte zoomLevel = LatLongUtils.zoomForBounds(new Dimension(tileSize * 4, tileSize * 4), getMapFile().boundingBox(), tileSize);
return new MapPosition(getMapFile().boundingBox().getCenterPoint(), zoomLevel);
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle(getClass().getSimpleName());
}
}

Here are my Android Manifest and gradle files.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fermovian.mytfl1">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:testOnly="false"
android:theme="@style/SplashTheme"
android:usesCleartextTraffic="true">

<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />

<activity android:name=".MapActivity">
</activity>

<!--<activity-->
<!--android:name=".MapsActivity"-->
<!--android:label="@string/title_activity_maps"></activity>-->

<activity android:name=".SplashActivity">
android:name=".SplashActivity"
android:theme="@style/SplashTheme">

<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
applicationId "com.fermovian.mytfl1"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}


dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0-alpha3'
implementation 'com.android.support:support-v4:28.0.0-alpha3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

def room_version = "1.1.0" // or, for latest rc, use "1.1.1-rc1"

implementation "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version"

// RxJava support for Room
implementation "android.arch.persistence.room:rxjava2:$room_version"
implementation 'com.google.android.gms:play-services-ads:15.0.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'

def mapsforge_version = "0.9.1"

implementation "org.mapsforge:mapsforge-core:$mapsforge_version"
implementation "org.mapsforge:mapsforge-map:$mapsforge_version"
implementation "org.mapsforge:mapsforge-map-reader:$mapsforge_version"
implementation "org.mapsforge:mapsforge-themes:$mapsforge_version"

implementation "org.mapsforge:mapsforge-map-android:$mapsforge_version"
implementation "org.mapsforge:mapsforge-poi-android:$mapsforge_version"
}

Any clues would be greatly appreciated, as I've now spent nearly a week at this and cannot find my way past this issue.


Chris Dewhurst

unread,
Jun 27, 2018, 11:39:04 AM6/27/18
to mapsforge-dev
This appears to be something to do with the version of the code that I was using.

I've imported the JARs from the Samples Application into my application and that *initially* appears to be working. Is there a standard location I should be pulling the latest and best JARs from though?

Sorry - I come from a Python, C#, C and C++ background. I know what JARs are, but I'm none-too-familiar with exactly how to use them, so any help would be good - especially setting up my gradle script, etc. Java is only a tiny part of what I do and I don't often have to focus on it.

Emux

unread,
Jun 27, 2018, 1:02:54 PM6/27/18
to mapsfo...@googlegroups.com
There is a GettingStarted sample which is the simplest example to get started with Mapsforge.

How does it run on your device?
You can start building around that.

Regarding how to integrate Mapsforge in your project, the recommended way is using a build automation system, like Gradle or Maven.

Can check the integration guide for more details per case.
And if you need jars, it mentions their release and snapshot locations too.

--
Emux

Emux

unread,
Jun 27, 2018, 1:08:42 PM6/27/18
to mapsfo...@googlegroups.com
BTW if you set "targetSdkVersion 28" must use the latest SNAPSHOT which contains the needed improvements for running properly on Android 9.

--
Emux
Reply all
Reply to author
Forward
0 new messages