DEV Community

Cover image for How to achieve Place Search and Marker Clustering Implementation in Map App
Jackson for HMS Core

Posted on

How to achieve Place Search and Marker Clustering Implementation in Map App

Background

Lots of apps these days include an in-app map feature and the ability to mark places of interest on the map. HMS Core Map Kit enables you to implement such capabilities for your apps. With Map Kit, you can first draw a map and then add markers to the map, as well as configure the map to cluster markers depending on the level of zoom. This article will show you how to implement searching for nearby places using the keyword search capability of Site Kit and display the results on the map.

Application scenarios:

  1. A travel app that allows users to search for scenic spots and shows the results on a map. 2.A bicycle sharing app that can show users nearby bicycles on a map.

Key functions used in the project:

  • Location service: Use Location Kit to obtain the current longitude-latitude coordinates of a device.
  • Keyword search: Use Site Kit to search for places such as scenic spots, businesses, and schools in the specified geographical area based on the specified keyword.
  • Map display: Use Map Kit to draw a map. Marker clustering: Use Map Kit to add markers to the map and configure the map to cluster markers depending on the level of zoom.

Integration Preparations

1.Register as a developer and create a project in AppGallery Connect.
(1)Register as a developer
Registration URL
Register as a developer
(2)Create an app, add the SHA-256 signing certificate fingerprint, enable Map Kit and Site Kit, and download the agconnect-services.json file of the app.
Create an app

2.Integrate the Map SDK and Site SDK.
(1)Copy the agconnect-services.json file to the app's directory of your project.

  • Go to allprojects > repositories and configure the Maven repository address for the HMS Core SDK.
  • Go to buildscript > repositories and configure the Maven repository address for the HMS Core SDK.
  • If the agconnect-services.json file has been added to the app, go to buildscript > dependencies and add the AppGallery Connect plugin configuration.
buildscript {
    repositories {
        maven { url 'https://developer.huawei.com/repo/' }
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.2'
        classpath 'com.huawei.agconnect:agcp:1.3.1.300'
    }
}
allprojects {
    repositories {
        maven { url 'https://developer.huawei.com/repo/' }
        google()
        jcenter()
    }
}
Enter fullscreen mode Exit fullscreen mode

(2)Add build dependencies in the dependencies block.

dependencies {
    implementation 'com.huawei.hms:maps:{version}'
    implementation 'com.huawei.hms:site:{version}'
 implementation 'com.huawei.hms:location:{version}'
}
Enter fullscreen mode Exit fullscreen mode

(3)Add the following configuration to the file header:

apply plugin: 'com.huawei.agconnect'
Enter fullscreen mode Exit fullscreen mode

(4)Copy the signing certificate generated in Generating a Signing Certificate to the app directory of your project, and configure the signing certificate in android in the build.gradle file.

signingConfigs {
    release {
        // Signing certificate.
            storeFile file("**.**")
            // KeyStore password.
            storePassword "******"
            // Key alias.
            keyAlias "******"
            // Key password.
            keyPassword "******"
            v2SigningEnabled true
        v2SigningEnabled true
    }
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        debuggable true
    }
    debug {
        debuggable true
    }
}
Enter fullscreen mode Exit fullscreen mode

Main Code and Used Functions

1.Use Location Kit to obtain the device location.

private void getMyLoction() {

        fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
        SettingsClient settingsClient = LocationServices.getSettingsClient(this);
        LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
        mLocationRequest = new LocationRequest();
        builder.addLocationRequest(mLocationRequest);
        LocationSettingsRequest locationSettingsRequest = builder.build();
//Check the device location settings.
        settingsClient.checkLocationSettings(locationSettingsRequest)
                .addOnSuccessListener(new OnSuccessListener<LocationSettingsResponse>() {
                    @Override
                    public void onSuccess(LocationSettingsResponse locationSettingsResponse) {
                        //Initiate location requests when the location settings meet the requirements.
                        fusedLocationProviderClient
                                .requestLocationUpdates(mLocationRequest, mLocationCallback, Looper.getMainLooper())
                                .addOnSuccessListener(new OnSuccessListener<Void>() {
                                    @Override
                                    public void onSuccess(Void aVoid) {
                                        // Processing when the API call is successful.
                                        Log.d(TAG, "onSuccess: " + aVoid);
                                    }
                                });
                    }
                })
Enter fullscreen mode Exit fullscreen mode

2.Implement the text search function using Site Kit to search for nearby places.

SearchResultListener<TextSearchResponse> resultListener = new SearchResultListener<TextSearchResponse>() {
    // Return search results upon a successful search.
    @Override
    public void onSearchResult(TextSearchResponse results) {
        List<Site> siteList;
        if (results == null || results.getTotalCount() <= 0 || (siteList = results.getSites()) == null
                || siteList.size() <= 0) {
            resultTextView.setText("Result is Empty!");
            return;
        }
 updateClusterData(siteList);// Mark places on the map.
    }

    // Return the result code and description upon a search exception.
    @Override
    public void onSearchError(SearchStatus status) {
        resultTextView.setText("Error : " + status.getErrorCode() + " " + status.getErrorMessage());
    }
};
// Call the place search API.
searchService.textSearch(request, resultListener);
Enter fullscreen mode Exit fullscreen mode

3.Draw a map

    @Override
    public void onMapReady(HuaweiMap huaweiMap) {
        hMap = huaweiMap;
        hMap.moveCamera(CameraUpdateFactory.newLatLngZoom(Constants.sMylatLng, 1));
        hMap.setMyLocationEnabled(true);
        hMap.getUiSettings().setMyLocationButtonEnabled(true);
        initCluster(huaweiMap);

    }
Enter fullscreen mode Exit fullscreen mode

4.Cluster markers on the map.

private ClusterManager<MyItem> mClusterManager;
List<MyItem> items = new ArrayList<>();

private void initCluster(HuaweiMap hMap) {
    mClusterManager = new ClusterManager<>(this, hMap);
    hMap.setOnCameraIdleListener(mClusterManager);
    // Add a custom InfoWindowAdapter by setting it to the MarkerManager.Collection object from
    // ClusterManager rather than from GoogleMap.setInfoWindowAdapter
//refer: https://github.com/billtom20/3rd-maps-utils  
    mClusterManager.getMarkerCollection().setInfoWindowAdapter(new HuaweiMap.InfoWindowAdapter() {
        @Override
        public View getInfoWindow(Marker marker) {
            final LayoutInflater inflater = LayoutInflater.from(SearchClusterActivity.this);
            final View view = inflater.inflate(R.layout.custom_marker_window, null);
            final TextView textView = view.findViewById(R.id.textViewTitle);
            String text = (marker.getTitle() != null) ? marker.getTitle() : "Cluster Item";
            textView.setText(text);
            return view;
        }

        @Override
        public View getInfoContents(Marker marker) {
            return null;
        }
    });

}
     // Update clustered markers.
private void updateClusterData(List<Site> siteList) {
    items  = new ArrayList<>();
    mClusterManager.clearItems();
    for (Site s:
            siteList) {
        Coordinate location = s.getLocation();
        MyItem myItem = new MyItem(location.lat,location.lng,s.name,s.formatAddress);
        items.add(myItem);
    }
    mClusterManager.addItems(items);
    Coordinate coordinate =  siteList.get(0).getLocation();
    LatLng latLng = new LatLng(coordinate.lat,coordinate.lng);
    mClusterManager.cluster();
    hMap.animateCamera(CameraUpdateFactory.newLatLngZoom (latLng,14 ));
}
Enter fullscreen mode Exit fullscreen mode

Results

Enter a place or service in the Query box and tap Search. The figures below show how the search results are displayed as markers on the map.
Map1
Map2
The preceding four figures show the effect of searching for food and school, as well as the marker clustering effect at different zoom levels. Congratulations, you have now successfully integrated place search and marker clustering into your in-app map.

References

For more details, you can go to:official website
Development Documentation page, to find the documents you need
Reddit to join our developer discussion
GitHub to download sample codes
Stack Overflow to solve any integration problems

Top comments (0)