[Huawei Developers] muraliameakula:
Introduction

I wanted to explain Huawei Map Kit with an app so I coded a sample Android app which name is ISS Detector. Users can instantly track the location of the ISS (International Space Station) on the map via Huawei Map Kit.

The main purpose of this article is to show how to use Huawei Map Kit, marker display operations on Huawei MapView, and polyline drawing operations.

So I will not mention parts such as MVP, binding and UI.

About the data?

used open-notify API for getting location information. You can reach the relevant API page from here.

ISS Detector Code Review

The application consists of a single Activity, this Activity has the MapView component via Huawei Map Kit. Also, I used the View Binding structure because it provides ease of access to the components.

I think it will be easier if I summarize the file structure.

data: There are response classes from the API.

service: The package containing the classes required for Retrofit2.

ui.main: UI-related classes are located here. MainContract and MainPresenter classes are included in this package because I use MVP Pattern.

util: Utility classes.

Create Project & HMS Integrations

First of all, you must integrate HMS into the project. I am not going to explain these steps You can check this article.

dependencies {
.
.
// Huawei Map Kit
implementation 'com.huawei.hms:maps:5.0.0.300'
.
.
}

After adding this implementation line to build.gradle file, we can now start using Huawei Map Kit.

<manifest ...>

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA"/>

...
</manifest>

We have defined the necessary permissions in the AndroidManifest file.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:map="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.main.MainActivity">

<com.huawei.hms.maps.MapView
android:id="@+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
map:cameraZoom="1"
map:mapType="normal"
map:uiCompass="true"
map:uiZoomControls="true" />

<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_margin="14dp"
app:cardCornerRadius="2dp"
app:cardElevation="4dp">

<CheckBox
android:id="@+id/checkBoxTrack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:checked="true"
android:text="Track ISS" />

</androidx.cardview.widget.CardView>

</RelativeLayout>

In activity_main.xml, the MapView component offers a full-screen map. Users can follow the ISS on the map, as well as go to the places they want freely while the ISS data continues to arrive.

public class MainActivity extends AppCompatActivity implements MainContract.View, OnMapReadyCallback {
...

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());

presenter = new MainPresenter(this);

Bundle mapViewBundle = null;
if (savedInstanceState != null) {
mapViewBundle = savedInstanceState.getBundle(Constant.MAP_BUNDLE);
}
initHuaweiMap(mapViewBundle);
}

@Override
public void onMapReady(HuaweiMap huaweiMap) {
Log.w(Constant.TAG, "onMapReady : ");
this.huaweiMap = huaweiMap;
presenter.mapReady();
}

@Override
public void initHuaweiMap(Bundle bundle) {
Log.w(Constant.TAG, "initHuaweiMap : ");
MapsInitializer.setApiKey(Constant.MAP_KEY);
binding.mapView.onCreate(bundle);
binding.mapView.getMapAsync(this);
}
...
}

We call the initHuaweiMap() function in onCreate. When the process is completed asynchronously with the binding.mapView.getMapAsync(this) line, the override onMapReady(HuaweiMap huaweiMap) function is triggered via OnMapReadyCallback, which we implement to MainActivity.

As a result of these operations, the map is now available and the presenter.mapReady() function is called.

We’ll come back to the MainActivity class later, but let’s go to explain the Presenter class.

public class MainPresenter implements MainContract.Presenter {
...
@Override
public void mapReady() {
this.getISSLocation();
...
}

@Override
public void getISSLocation() {
Call<ResponseISSLocation> call = request.getISSLocation();
call.enqueue(new Callback<ResponseISSLocation>() {
@Override
public void onResponse(Call<ResponseISSLocation> call, Response<ResponseISSLocation> response) {
if (response.isSuccessful()) {
LatLng currentLatLng = response.body().getIssPosition().getLocationAsLatLng();
Log.w(Constant.TAG, "getISSLocation : " + currentLatLng.toString());
view.setMarker(currentLatLng);
view.drawRoute(currentLatLng);
if (isChecked)
view.moveCamera(currentLatLng);
waitAndCallRequest();
}
}

@Override
public void onFailure(Call<ResponseISSLocation> call, Throwable t) {
Log.w(Constant.TAG, "getISSLocation - onFailure : " + t.getMessage());
view.showErrorMessage(t.getMessage());
}
});
}

@Override
public void waitAndCallRequest() {
Log.d(Constant.TAG, "waitAndCallRequest ");
new android.os.Handler().postDelayed(() -> getISSLocation(), 2000
);
}
}

The getISSLocation() function is calling in mapReady() for the first time for the ISS current location.

We are going to call setMarker(), drawRoute() and moveCamera() functions in the getISSLocation() function. Finally, the waitAndCallRequest() function is calling so that we can resend the same request every 2 seconds and get new location data.

Now let’s come to the setMarker(), drawRoute(), and moveCamera() functions, which is the main purpose of the article.

@Override
public void setMarker(LatLng latLng) {
Log.w(Constant.TAG, "setMarker ");
if (marker != null)
marker.remove();
MarkerOptions options = new MarkerOptions()
.position(latLng)
.icon(BitmapDescriptorFactory.fromResource(R.drawable.marker_iss));
marker = huaweiMap.addMarker(options);
}

In the setMarker() function, we first check the marker, if there is a marker on the map, firstly delete this marker with the marker.remove() line. Next, we create a MarkerOptions object, here we set the position of the marker with .position(), the marker icon with .icon(), and finally, we show the marker created with the huaweiMap.addMarker(options) line on the map.

@Override
public void drawRoute(LatLng latLng) {
if (huaweiMap == null) return;
if (polyline == null) {
polyline = huaweiMap.addPolyline(new PolylineOptions()
.add(latLng)
.color(getColor(R.color.colorAccent))
.width(3));
polylineList = new ArrayList<>();
polylineList.add(latLng);
} else {
polylineList.add(latLng);
polyline.setPoints(polylineList);
}
}

We have to check if the huaweiMap is null in drawRoute() function, if the polyline object is null -the application will enter the if block when it first opens because our polyline object is still null- we set the polyline object to huaweiMap with the huaweiMap.addPolyline(new PolylineOptions()) line. We set the location data with.add(), we set the polyline color with .color(), we set the polyline width .width(). Since the polyline will not consist of a single point, we create a polylineList of type ArrayList and add the location data to this list. Let’s come to the else block, we add the location here to the list and use the polyline.setPoints() function to update the route on the map.

@Override
public void moveCamera(LatLng latLng) {
Log.w(Constant.TAG, "moveCamera ");
huaweiMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, huaweiMap.getCameraPosition().zoom));
}

moveCamera() is the last function called in these steps. We send the latLng variable returned from the request and the zoom level value we get with huaweiMap.getCameraPosition().zoom to the animateCamera() function, and as a result of this line, our map moves to the new location.

Tips & Tricks

MAP_KEY value generated from AGC for Huawei Mobile Services.

Also, you can access the source codes of the application from the Github and Huawei AppGallery links below.

Conclusion

In this article, I tried to explain how to use Huawei Map Kit, marker display operations on Huawei MapView, and polyline drawing operations. I hope it was a useful article for everyone. Thank you for taking the time to read.

References

App Gallery

Source Code

Huawei Map Kit

Original Source