Android Project Setup for the TomTom Maps SDK
Tags: android, beginners, tutorial, code
Published: 2020-06-09 16:36:39

The TomTom Maps SDK for Android is a great way to add TomTom API services to your Android app. In this article, we'll walk you through the project setup process, and we'll create a basic app that displays a map with the user’s current position marked.

This article will guide you through the process of setting up a basic Android project that integrates the TomTom Maps SDK for Android and TomTom API services. 

To illustrate the project setup process, we'll create a basic app that displays a map with the user’s current position marked. The app uses the TomTom Search API to let a user search for a point of interest by entering text and returns useful results even if the search includes spelling errors or inexact addresses. The results will be marked on the map for the user to browse. 

This example Android application provides a jumping off point for many potential location-aware apps using TomTom location services.

**GETTING STARTED**

The TomTom Maps SDK for Android is supported on devices running Android version 4.4 (KitKat) or later. I’m going to use Android Studio as my IDE and Java as the development language. Kotlin is also supported.

To use the TomTom SDK and API services, you need a free developer account. Sign up or log in at [https://developer.tomtom.com](https://developer.tomtom.com). This account will be used to manage the API keys for the application, and you’ll need an API key with what you build today.

In the TomTom developer portal, go to your dashboard. When you create a new application entry, you’ll be prompted for a name for the application and for the services the application needs. Enter any name you like. You can select any of the API services that apply to your application, but they must be selected to work with your application. 

For this example, select Maps API and Search API, as indicated in the screenshot. The Maps SDK contains classes that will handle making the web calls and rendering the map.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/htqhdm92hdm3kakqtpn1.jpg)

Click “Create App” to create the application entry. 

Once you’ve saved the application, the dashboard will show an entry for it, and if you click on the entry, you’ll see the “Consumer API Key.” You’ll need this value to authorize API access in your app. We'll show you how to use the key in your app in a moment.

**ANDROID PROJECT SETUP**

Create a new project in Android Studio. From the “Choose your Project” window, select “Empty Activity” and click “Next,” then enter a name for the project and modify any other project details as needed. 

Note that the API version must be no lower than 4.4 (KitKat). Click “Finish” to create the project.

We’ve created the project, but there’s still some configuration to do before diving into the code. 

We’ll need the API keys for the services we’re using. 

Find the application manifest in the left pane (AndroidManifest.xml). Within the <application/> node of the file, add <meta-data /> entries for the application keys. For the sample app we only need keys for the OnlineMaps.Key and OnlineSearch.Key, but I’ve included the names of other possible <meta-data /> elements you might use with other SDKs:

```javascript
<meta-data android:name="OnlineMaps.Key" android:value="YOUR_KEY_HERE" />
<meta-data android:name="OnlineSearch.Key" android:value=" YOUR_KEY_HERE " />
<!--
<meta-data android:name="OnlineTraffic.Key" android:value=" YOUR_KEY_HERE " />
<meta-data android:name="OnlineRouting.Key" android:value=" YOUR_KEY_HERE " />
<meta-data android:name="GeofencingApi.Key" android:value=" YOUR_KEY_HERE " />
-->
```

In the left pane in Android Studio, you’ll see two entries for build.gradle, one for Project and the other for Module. Double-click on the build.gradle file for the project, which contains a section for allprojects. Within allprojects you’ll see an entry for repositories, which already contains a couple of entries. We’ll add a third entry so the IDE can retrieve components of the SDK, as shown below in bold: 

```javascript
allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url 'https://maven.tomtom.com:8443/nexus/content/repositories/releases/'
        }
    }
}
```

Save and close the file. 

Now open the build.gradle file for the module. In the dependencies block, add entries referencing both the Maps and Search SDKs. We only need those two here, but I show other possible entries for other SDK components, commented out. 

The number at the end of these strings is the SDK version. I’m using 2.4.37. Note that when you’re using more than one component, the SDK versions must be the same for all components. We also need to enable [multidex](https://developer.android.com/studio/build/multidex) in the implementation to avoid a limitation about including libraries that we’d otherwise encounter. 

```javascript
implementation 'com.android.support:multidex:1.0.3'
implementation("com.tomtom.online:sdk-maps:2.4327")
implementation("com.tomtom.online:sdk-search:2.4327")
// These entries could be used for other TomTom services
//implementation("com.tomtom.online:sdk-routing:2.4327")
//implementation("com.tomtom.online:sdk-traffic:2.4327")
//implementation("com.tomtom.online:sdk-geofencing:2.4327")
//implementation("com.tomtom.online:sdk-maps-ui-extensions:2.4327")
//implementation("com.tomtom.online:sdk-maps-rx-extensions:2.4327")  
//implementation("com.tomtom.online:sdk-maps-ktx-extensions:2.4327")
//implementation("com.tomtom.online:sdk-maps-static-image:2.4327")
//implementation("com.tomtom.online:sdk-maps-driving-extensions:2.4327")
```

Next, we’ll add a section called compileOptions to the android section of the file, to set sourceCompatibility and targetCompatibility for Java Version 1.8. We also need to set the multidex setting to true. The additions are shown in bold:

```javascript
android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.tomtommapstestapp"
        minSdkVersion 19
        targetSdkVersion 29
        multiDexEnabled true
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}
```

With this done, the configuration is complete. You can compile the application. Just take an extra look to make sure you don’t encounter any errors resulting from mistyping. 

Now that we’ve completed the setup, let’s write more of the actual code.

**BUILDING THE UI**

The application already has a layout file named activity_main.xml. This is where we’ll define the application UI. Remove the “Hello World” text element and add a <fragment /> element for the map view instead:

```javascript
<fragment
    android:id="@+id/map_fragment"
    android:name="com.tomtom.online.sdk.map.MapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:layout="@layout/map_view" />
```

If you run the application now, you’ll see a map of the earth in which you can zoom and scroll. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/icguku85gvq5abn1ajxb.jpg)

The UI will need additional elements for text entry for the search and to show the results as a list. I added an EditText element for the text entry and a ListView to show the list of search results.

In the MainActivity.java, we need a few variables to hold references to the map object, the search service, the search results, and the adapter for the list view:

```javascript
TomtomMap tomtomMap;
SearchService tomtomSearch;
ImmutableList<FuzzySearchResult> lastSearchResult;
ResultListAdapter adapter;
```

After the activity’s content view is initialized, in onCreate we use a reference to the map fragment to request a map object. When the map is ready, our callback is called and given a reference to the map. We save the reference since we’ll need it for other calls to the map. Notice a pattern throughout this code: requests being asynchronous and being notified of their completion with results in callbacks.

```javascript
MapFragment mapFragment = (MapFragment)getSupportFragmentManager().findFragmentById(R.id.map_fragment);
Log.d(TAG, "Request map from map fragment");
mapFragment.getAsyncMap(new OnMapReadyCallback() {
    @Override
    public void onMapReady(@NonNull TomtomMap map) {
        Log.d(TAG, "Map retrieved");
        tomtomMap = map;
        tomtomMap.setMyLocationEnabled(true);
        //Set the map view somewhere near San Jose
        tomtomMap.centerOn(37, -121, 8);
    }
});
```

We use the SearchServiceManager class to create our SearchService object. As with the map object, we use a callback to get the SearchService object:

```javascript
Log.d(TAG, "Requesting search service");
ServiceConnection serviceConnection = SearchServiceManager.createAndBind(getBaseContext(),
        new SearchServiceConnectionCallback() {
            @Override
            public void onBindSearchService(SearchService searchService) {
                Log.d(TAG,"Search service retrieved");
                tomtomSearch = searchService;
            }
        });
```

We want the search results to be based on the part of the map the user is viewing. When the user presses the search button, the coordinates for the map center can be found by calling getCenterOfMap() on the map object. 

The center coordinates and the text the user enters in the search box are both added to a FuzzySearchQuery object, and the fuzzy search service will look for relevant results. The query object is passed to the Search object that was created earlier. 

Search is performed asynchronously. When it completes, the code receives a callback with the search response.

```javascript
EditText searchEditText = findViewById(R.id.searchText);
searchEditText.setOnEditorActionListener((v, actionId, event) -> {
    LatLng mapCenter = tomtomMap.getCenterOfMap();

    FuzzySearchQuery searchQuery = FuzzySearchQueryBuilder.create(v.getText().toString())
        .withPosition(mapCenter)
        .build();
    tomtomSearch.search(searchQuery, new FuzzySearchResultListener() {
        @Override
        public void onSearchResult(FuzzySearchResponse fuzzySearchResponse) {
            ImmutableList<FuzzySearchResult> results = fuzzySearchResponse.getResults();
            showSearchResults(results);
        }
        @Override
        public void onSearchError(SearchError searchError) {
        }
    });
```

For a successful search, we’ll display a list of the results on the screen using ListView functionality. We only need to let the adapter for the ListView know that the data to display has been updated. If there is an unsuccessful search we get back an empty result set. If this happens we show a brief notification to let the user know. 

We also want markers for the search results to be placed on the map, so we’ll use the Maps SDK’s MarkerBuilder class to create an object that represents a marker on the map. Once the object is built, we can show it on the map by calling addMarker on our map object. 

```javascript
void showSearchResults(ImmutableList<FuzzySearchResult> resultList)
{
    Log.i(TAG, resultList.toString());
    this.lastSearchResult = resultList;
    adapter.notifyDataSetChanged();

    tomtomMap.clear();
    if(this.lastSearchResult.size() == 0)
    {
        Toast.makeText(getBaseContext(), "No locations found", 
            Toast.LENGTH_SHORT).show();
        return;
    }

    for(int i=0;i<lastSearchResult.size();++i)
    {
        LatLng geoposition = lastSearchResult.get(i).getPosition();
        Poi poi = lastSearchResult.get(i).getPoi();
        MarkerBuilder markerBuilder = new MarkerBuilder(geoposition)
            .icon(Icon.Factory.fromResources(getBaseContext(), 
                R.drawable.ic_favourites))
            .markerBalloon(new SimpleMarkerBalloon(poi.getName()))
            .tag(lastSearchResult.get(i).getAddress())
            .iconAnchor(MarkerAnchor.Bottom)
            .decal(true);
        tomtomMap.addMarker(markerBuilder);
    }
}
```

If someone clicks on an item on the ListView, the map needs to re-center on that item. The centerOn method was used at map initialization to center the map on San Jose, and we can use it again to center the map on the item the user selected:

```javascript
searchResultList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        FuzzySearchResult result = 
            (FuzzySearchResult)searchResultList.getItemAtPosition(position);
        LatLng geoposition = result.getPosition();
        tomtomMap.centerOn(geoposition);
    }
});
```

Deploy the application and try searching for a category, such as “airports” or “hospitals.” You should see several results listed, and be able to click on any of them to have the map focus on it. If you see this, you’ve successfully created and configured an application that uses the TomTom Maps SDK and services. 

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dfsak3v82y7q3gox1vxl.jpg)

**NEXT STEPS**

We created a basic Android project that’s configured to use the TomTom Maps SDK and its Search API. Using the SDK, you can build a variety of applications, from ones with customized maps, to ones for tracking assets, for querying traffic information, and for searching an area for points of interest. 

Using the same steps, you could create an application that uses TomTom’s other services. 

For more information on the TomTom Maps SDK for Android, visit [https://developer.tomtom.com/maps-sdk-android](https://developer.tomtom.com/maps-sdk-android).

*This article was originally published on [https://developer.tomtom.com/blog](https://developer.tomtom.com/blog). The original author is Joel Johnson.*