advanced
Java
Build a store locator for Android
Prerequisite
Familiarity with Android Studio and Java.

This guide will walk you through how to use our Android Store Locator starter kit to create a custom store locator map that can be integrated into any Android application. You’ll be able to browse several store locations, select a specific store to view more information, and retrieve an estimated travel distance and route from a user’s location to any of the store locations. You can start with one of five different themes and customize everything from store location data to marker icons and individual store cards.

simulation of user interaction with a store locator application


Getting started

Here’s what you’ll need to start building a store locator for Android:

  • Starter kit files. Download or clone the Android Store Locator starter kit from GitHub. This includes all the necessary files for a functional Android Studio project.
  • Android Studio 3.0 Beta. You will need to use Android Studio 3.0 Beta with the starter kit files. If you try to run your application and receive an Error running android: Gradle project sync failed. Please fix your project and try again, verify that you’re using Android Studio 3.0 Beta.
  • Mapbox access token. The access token is used to associate a map with your account and can be found on your Account page.
  • An Android device (physical or virtual). You will need either a physical Android device or an emulated Android device to preview the store locator. Note: the device’s Android SDK version number must be 16 (“Jelly Bean”) or higher.
  • Optional: Android Drawable Importer. If you plan to add custom images to your application (for example, custom icons for markers at store locations), install the Android Drawable Importer plugin to add images to your project.
  • Optional: SVG editing tool. If you’d like to create custom layouts or icons, you can use a program like Sketch, Figma, or Adobe Illustrator.

Set up the starter kit

After you’ve downloaded the Android Store Locator starter kit from GitHub, open the project in Android Studio 3.0 Beta. In the project, you’ll find all of the source files for the entire app, including:

  • Five UI theme variations.
  • Sample GeoJSON data with store locations.
  • Code for retrieving directions with the Mapbox Directions API and displaying a navigation route line on the map.

Access token

Before running the application, you will need to add your Mapbox access token to the strings.xml file. You can find this file in app > src > main > res > values.

strings.xml
<!-- Add your Mapbox access token in between >< in the line below. Your token can
be retrieved at https://www.mapbox.com/account/
-->
<string name="access_token" translatable="false">REPLACE_WITH_MAPBOX_ACCESS_TOKEN</string>

MapActivity

The MapActivity.java file is the primary place you’ll adjust code. This activity can be found by navigating to app > src > main > java > com > mapbox > storelocator > activity. This is the file where you’ll customize your app by:

  • Selecting a theme to start with.
  • Setting the map’s style URL.
  • Choosing the marker icons.
  • Customizing other UI elements and colors as needed.

Choose a theme

Once you have the starter kit set up, start by picking a theme. Unless adjusted, the theme picker activity will be the first thing you see when the the app is launched. Choose a theme by clicking on the preview image for one of five themes made by our mobile designers.

screenshot of the theme picker screen of the store locator starter kit application

Once you’ve selected your theme, remove this activity before adding the MapActivity.java file to your final app:

  • Delete the file — ThemePickerActivity.java is in the same directory as the MapActivity.java file (app > src > main > java > com > mapbox > storelocator > activity).
  • Remove the ThemePickerActivity from the app’s manifest file and move the launcher intent filter to the MapActivity (or any other activity you’d like to first open when the app is launched):
Manifest.xml
<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
  • Adjust the MapActivity.java file so it no longer initializes the chosenTheme object via getIntent().getIntExtra(*SELECTED_THEME*, R.style.*AppTheme_Blue*);. Instead, set it equal to whichever theme you chose:
MapActivity.java
chosenTheme = R.style.YOUR_CHOSEN_THEME; // Example of a theme: AppTheme_Blue

Once you’ve made these changes, run your app again. You should see the map using your chosen theme and some preloaded store location data. In the next step, you’ll add your own data with store locations.

screenshot of the android store locator application after the blue theme is chosen

Add your data

The starter kit contains a GeoJSON file called list_of_locations.geojson where you’ll find all the current store locations that are visible on the map. GeoJSON is a file format for geospatial data and a subset of the JSON format. In this section, you’ll update the sample data to reflect your actual store locations.

Locate the list_of_locations.geojson file in app > src > main > assets. Take a look at how the data is formatted. Notice that each store location is a separate GeoJSON feature in the file. Each feature has four properties describing a few characteristics about the store location and geometry specifying that the feature is a single point and where that point is located in the world.

You can replace the preloaded data with your own store data. If you have store location data available in GeoJSON form, you can delete the current data and replace it with your own. Note: If your data contains different properties than the default data, you will need to modify the related code in both the MapActivity.java file and the LocationRecyclerViewAdapter class. We recommend using geojson.io to quickly validate and visualize your GeoJSON.

If you don’t have your store data in GeoJSON format, you can create a new GeoJSON file using the Mapbox Studio dataset editor. In this example, you’ll create a dataset with store locations for Jeni’s Splendid Ice Cream locations in the Columbus, Ohio area using the Mapbox Studio dataset editor, export a GeoJSON file, replace the GeoJSON data in the list_of_locations.geojson, adjust the bounding box and mock user location, and run your app to see the new store locations.

Create a dataset

If you already have a GeoJSON file of store locations, you can skip ahead to the Replace data section.

There are several ways to create a new GeoJSON file. In this guide you’ll use the Mapbox Studio dataset editor, a convenient in-browser application for creating and editing Mapbox datasets. In this guide, you’ll use known addresses for Jeni’s locations to search and add store locations to your dataset.

First, create a new dataset:

  1. Log into Mapbox Studio and navigate to the Datasets page.
  2. Click the New dataset button.
  3. A new window will open. You’ll use the Blank dataset option in the upper right corner.
  4. Name your dataset “ice-cream” and click Create.
  5. The dataset editor will automatically open.

Next, you’ll begin adding stores. You can use the geocoder in the dataset editor to search for a place and the draw tools to add a new point to your dataset. You can modify the geometry, placement, and properties of existing features with the dataset editor’s draw tools.

  1. Click inside the Search places field and type 3998 Gramercy St, Columbus, Ohio.
  2. Click the address that best matches your search in the search results.
  3. Click the Add to dataset button to add that address to your dataset.
  4. Click on the new feature and use the properties list on the left hand side to:
    • Change the place_name field to description.
    • Add the field name name and give it the value Easton.
    • Add the field name hours and give it the value 11 a.m. to 11 p.m..
    • Add the field name phone and give it the value 614-476-5364.

You could go through this process for each known store address. After you’ve added each store location, you can Save, return to the Datasets page, click the button next to the name of your “ice-cream” dataset, and click Download GeoJSON.

In the interest of time, for this guide, we’ve provided the complete GeoJSON below for you to use in the next step:

list_of_locations.geojson
{
  "features": [
    {
      "type": "Feature",
      "properties": {
        "description": "3998 Gramercy St, Columbus, Ohio 43219, United States",
        "name": "Easton",
        "hours": "11 a.m. to 11 p.m.",
        "phone": "614-476-5364"
      },
      "geometry": {
        "coordinates": [
          -82.917665,
          40.051791
        ],
        "type": "Point"
      },
      "id": "address.11780104298749790"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "714 N High St, Columbus, Ohio 43215, United States",
        "name": "North Market",
        "hours": "10 a.m. to 5 p.m.",
        "phone": "614-228-9960"
      },
      "geometry": {
        "coordinates": [
          -83.00418,
          39.971888
        ],
        "type": "Point"
      },
      "id": "address.1504101080777130"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "900 Mohawk St, Columbus, Ohio 43206, United States",
        "name": "German Village",
        "hours": "Noon to 10 p.m.",
        "phone": "614-445-6513"
      },
      "geometry": {
        "coordinates": [
          -82.992495,
          39.944236
        ],
        "type": "Point"
      },
      "id": "address.18662160207305960"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "1 W Bridge St, Dublin, Ohio 43017, United States",
        "name": "Dublin",
        "hours": "11 a.m. to 11 p.m.",
        "phone": "614-792-5364"
      },
      "geometry": {
        "coordinates": [
          -83.114164,
          40.099224
        ],
        "type": "Point"
      },
      "id": "address.3847501076015100"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "2156 E Main St, Columbus, Ohio 43209, United States",
        "name": "Bexley",
        "hours": "11 a.m. to 11 p.m.",
        "phone": "614-231-5364"
      },
      "geometry": {
        "coordinates": [
          -82.941956,
          39.957461
        ],
        "type": "Point"
      },
      "id": "address.5795414383633980"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "714 N High St, Columbus, Ohio 43215, United States",
        "name": "Short North",
        "hours": "11 a.m. to 11 p.m.",
        "phone": "614-294-5364"
      },
      "geometry": {
        "coordinates": [
          -83.003353,
          39.976965
        ],
        "type": "Point"
      },
      "id": "address.748502797349860"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "160 S High St, Columbus, Ohio 43215, United States",
        "name": "The Commons",
        "hours": "11 a.m. to 8 p.m.",
        "phone": "614-867-5512"
      },
      "geometry": {
        "coordinates": [
          -82.999991,
          39.958812
        ],
        "type": "Point"
      },
      "id": "address.7894313840035430"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "1281 Grandview Ave, Columbus, Ohio 43212, United States",
        "name": "Grandview Heights",
        "hours": "11 a.m. to 11 p.m.",
        "phone": "614-488-2680"
      },
      "geometry": {
        "coordinates": [
          -83.045003,
          39.983947
        ],
        "type": "Point"
      },
      "id": "address.8328248295013750"
    },
    {
      "type": "Feature",
      "properties": {
        "description": "8 N Liberty St, Powell, Ohio 43065, United States",
        "name": "Powell",
        "hours": "11 a.m. to 11 p.m.",
        "phone": "614-846-1060"
      },
      "geometry": {
        "coordinates": [
          -83.074985,
          40.158137
        ],
        "type": "Point"
      },
      "id": "address.8508074803994320"
    }
  ],
  "type": "FeatureCollection"
}

Replace data

Open the list_of_locations.geojson file. Delete the current contents and add the GeoJSON data from the previous step. The data that’s provided in the sample code and in this example contain four properties for each store location:

  • name
  • description
  • hours
  • phone

Since all the feature properties are identical to the four that were used in the initial GeoJSON data, your map will be fully functional immediately. If you have different information you would like to display as properties, you will need to modify the related code in both the MapActivity.java file and the LocationRecyclerViewAdapter class.

Update bounding box and location

Currently, the MapActivity.java file specifies that the map be centered on New York when the app is initialized. Replace the current code with the following code snippets to update the location to Columbus, Ohio.

First, change the target latitude and longitude when the app is initialized to center on Columbus in the app > res > layout > activity_map.xml file.

activity_map.xml
mapbox:mapbox_cameraTargetLat="39.95"
mapbox:mapbox_cameraTargetLng="-83"

Then, change the bounding box so the map opens displaying the Columbus area in the MapActivity.java file.

MapActivity.java
private static final LatLngBounds LOCKED_MAP_CAMERA_BOUNDS = new LatLngBounds.Builder()
    .include(new LatLng(40.1746, -83.1426))
    .include(new LatLng(39.9278, -82.8814))
    .build();

Finally, change the simulated user location to be near Columbus in the MapActivity.java file.

MapActivity.java
private static final LatLng MOCK_DEVICE_LOCATION_LAT_LNG = new LatLng(40, -83);

Run the application, and you will see the map focused on Columbus, Ohio.

screenshot of the android store locator application after store location data is updated

Display distances and routes

The starter kit includes the use of the Mapbox Directions API to display estimated travel distances and routes. Once you’ve updated the GeoJSON data for store locations and the mock location, the Mapbox Directions API will automatically read your GeoJSON file to retrieve the distances and routes to each of your locations. The code that specifies how the Directions API is used can be found in the MapActivity.java file.

Add custom markers

You can use any image as a marker — you can use an emoji (like in the starter kit files), create your own icon, use your company’s logo, or use an icon from several open source resources. Here are some recommended resources for finding marker icons:

In this guide, you’ll use an icon from the open source project, Flat Icon. This icon, made by Eucalyp from www.flaticon.com, is licensed by CC 3.0 BY. You can download an image this icon on a white marker or download another icon from Flat Icon. When using icons from Flat Icon, be sure to credit the author appropriately.

Download the icon on a white marker

As mentioned in the getting started section, we recommend installing and using the Android Drawable Importer plugin to add images to your project. This plugin automatically scales and adds the image to a drawable folder for each screen size (mdpi, xhdpi, xxhdpi, etc).

Add a new image to your project

After installing the Android Drawable Importer plugin and downloading the icon that you would like to use for the store location markers, add the image to the app > res > drawable folder. Right-click on the drawable folder, hover over the New menu item, in the sub menu choose Batch Drawable Importer. Note: This option will only be available after installing the Android Drawable Importer.

screenshot of the menu and submenu you will need to navigate to add an image using the Batch Drawable Importer

In the window that opens, click the + and choose your file. Another window will open. In this window, take note of the Target-name that is assigned to the image. For the guide, use the name new_ice_cream_icon and click Ok. In the first window, you can also click Ok.

Notice that a new folder has been added to the drawable folder. It is named new_ice_cream_icon, the Target-name from the importer process, and contains several files — your new image optimized for various screens.

screenshot of the folder for your new image and the files it contains

Use the new image as a marker

Now that you’ve successfully imported a new image, modify the code that specifies what image should be used in the markers for each store location. The code that specifies which image to use for store markers lives in the MapActivity.java file. To change the image to the new_ice_cream_image:

  1. Open MapActivity.java.
  2. Find private void initializeTheme() { }.
  3. Within that method, find case R.style.AppTheme_Blue:. This is the code that specifies the styles for markers, routes, and mock user location.
  4. For both unselectedMarkerIcon and selectedMarkerIcon change R.drawable.ice_cream_icon to R.drawable.new_ice_cream_icon.

Run the application again, and you should see new ice cream icon markers at all store locations.

screenshot of Store Locator application with the new ice cream icon as markers

Customize card icons

In addition to customizing the look of the map, you can also customize the style of the cards for each store. Next you’ll change the icon shown on the scrolling cards. This example swaps out the ice cream icon for a photo of a child enjoying an ice cream cone from the incredible open source project, Unsplash. The original image has been cropped and modified to an image size of 105px x 105px.

Download the image

Import the image

Following the same process described in the section above, add the new scrolling card image to your project using the Android Drawable Importer plugin. Use the Target-name ice_cream_kid.

Use the new image on the scrolling card

Now that you’ve successfully imported a new image, modify the code that specifies what image should be used in the scrolling cards. The code for the cards lives in the single_location_map_view_rv_card.xml layout. In this file you can adjust the style (including the spacing, location, and size) of different elements on the cards. This single card layout is given to the ReyclerView.java adapter, and this adapter eventually creates the scrollable list of cards at the bottom of your device’s screen.

To change the image used in the scrolling cards you’ll need to pass through your desired drawable when the emojiForCircle object is initialized in the onBindViewHolder() method of the LocationRecyclerViewAdapter class:

  1. Open the ReyclerView.java file in app > java > adapter.
  2. Find switch (selectedTheme) { }.
  3. Within that method, find case R.style.AppTheme_Blue:. This is the code that specifies the styles for the information shown on the scrolling cards.
  4. Set emojiForCircle equal to ResourcesCompat.getDrawable(context.getResources(), R.drawable.ice_cream_kid, null);
  5. Delete backgroundCircle = ResourcesCompat.getDrawable(context.getResources(), R.drawable.blue_circle, null);.

Run the application again, and you should see the new image on the scrolling cards.

screenshot of store locator application with custom scrolling card image

Final product

Great work! You’ve learned how the Android Store Locator starter kit works and modified a few of the key customizable elements of a store locator.

simulating user interaction with the final customized store locator

Next steps

Take a look at the Mapbox Maps SDK for Android documentation and examples to learn more about customizing your application or adding additional functionality. If you’re interested in creating your own custom map style to replace the designer themes provided in the Store Locator starter kit, check out our Create a custom style tutorial to use Mapbox Studio to build a style that fits your brand.