# Best practices
In the following sections, we will guide you through the most common usage scenarios and reveal tips and easy-to-understand guidelines to help you get the most out of the HERE SDK for Android.
## Optimization strategies
Explore further options to enhance the performance of the HERE SDK:
* **Optimize map caching:** Adjust the caching mechanisms by following the guidelines in our [map caching documentation](https://docs.here.com/here-sdk/docs/tips-engines#work-with-the-map-cache).
* **Conditional HERE SDK initialization:** To conserve resources, [initialize the HERE SDK](https://docs.here.com/here-sdk/docs/tips-engines) only when it is necessary.
* **Adjust the frame fate:** Modify the frame rate settings of the `MapView` to balance performance and visual fluidity. Detailed guidance can be found in the frame rate adjustment section [below](#adjust-the-frame-rate).
* **Simplify visuals with custom map styles:** Employ [custom map styles](https://docs.here.com/here-sdk/docs/custom-map-styles) that include fewer elements to render, thereby enhancing rendering efficiency and reducing computational load.
When using the **HERE SDK for Android Navigate**, you can:
* **Preload map data:** Use [offline maps](https://docs.here.com/here-sdk/docs/offline-maps) to download and store map data in advance, allowing for smoother access and reduced reliance on live data connections.
Additionally, the HERE SDK provides versatile configuration options across various engines. For instance, with the `SearchEngine`, you can define `SearchOptions` to refine and limit the scope of returned search results.
## Handling low memory states
When your application runs on a memory-constrained device or under heavy load, it is important to manage memory efficiently to avoid crashes. The HERE SDK provides mechanisms to optimize its memory usage under such scenarios.
### Detect and respond to low memory warnings
To respond to memory pressure from the operating system (e.g., through `onLowMemory()` or `onTrimMemory()` callbacks), implement a handler that listens to memory warnings and takes action accordingly. Below is a possible implementation:
```java
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
handleLowMemory();
}
}
@Override
public void onLowMemory() {
super.onLowMemory();
handleLowMemory();
}
```
A possible implementation for `handleLowMemory()` is shown below.
### Enable low memory mode and purge the cache
To proactively reduce memory consumption, enable `lowMemoryMode` in `SDKOptions` and optionally purge the cache:
```java
public void handleLowMemory() {
Log.d("Low Memory", "System is running low on memory. Initiating memory cleanup.");
SDKNativeEngine.getSharedInstance().purgeMemoryCaches(SDKNativeEngine.PurgeMemoryStrategy.FULL);
AuthenticationMode authenticationMode = AuthenticationMode.withKeySecret("YOUR_ACCESS_KEY_ID", "YOUR_ACCESS_KEY_SECRET");
SDKOptions options = new SDKOptions(authenticationMode);
options.lowMemoryMode = true;
try {
SDKNativeEngine.makeSharedInstance(context, options);
Log.d("Low Memory", "Reinitialized HERE SDK with low memory mode enabled.");
} catch (InstantiationErrorException e) {
Log.e("Low Memory", "Failed to reinitialize HERE SDK: " + e.error.name());
}
}
```
Setting `lowMemoryMode = true` configures the SDK’s internal caches to use less memory. This can be beneficial on devices with limited RAM or during times of high memory pressure.
Turning on the `lowMemoryMode` will impact the performance of several HERE SDK features such as rendering the map view. Therefore, it may make sense to enable it only after you receive a low-memory warning from the operation system. The next section describes how to do this.
When the system sends memory pressure signals, use the following method to clear the HERE SDK’s internal caches:
```java
SDKNativeEngine.getSharedInstance().purgeMemoryCaches(SDKNativeEngine.PurgeMemoryStrategy.FULL);
```
This will release memory held by all in-memory caches and will help prevent OOM (Out of Memory) crashes.
Currently, only `PurgeMemoryStrategy.FULL` is supported, which clears all cached content without preserving any data.
## Integrate JavaDoc into your IDE
In your release package you can find the latest API Reference as a zipped HTML package for offline use and a `heresdk-javadoc.jar` file containing the same data as a JAR package. When working in your IDE, then usually, the API Reference cannot be accessed right-away.
In order to get easy access to the API Reference from within your IDE of choice, you can integrate the API Reference file according to the instructions of your IDE.
As an example, for Android Studio, you can link the HERE SDK AAR to the JavaDoc file like so:
1. For convenience, copy the `heresdk-javadoc.jar` file to the same folder as the HERE SDK AAR.
2. Open Android Studio and switch to the **Project** view: it is selectable from the pull-down menu above the navigation bar.
3. Expand the **External Libraries** node. The HERE SDK AAR should appear.
4. Right-click on the HERE SDK AAR file and choose **Library Properties**.
5. From the **Library Properties** dialog select the **+** sign.
6. Navigate to the downloaded JavaDoc JAR file and select it.
7. Choose **JavaDocs** as category for the selected `heresdk-javadoc.jar` file.
8. Click **OK**.
Finally, verify that the JavaDoc API Reference is available within your project.
## Free resources
All HERE SDK classes will be garbage collected by Android if the instance is no longer referenced or set to null.
When the app's lifetime has ended, you can free resources by calling `SDKNativeEngine.getSharedInstance().dispose()`. Also, all references to `SDKNativeEngine` must be set to `null` (if any). Calling `dispose()` will stop pending requests and close open files and databases that are still running. After calling `dispose()` any related HERE SDK feature should no longer be used - unless you initialize the HERE SDK again: if you have created engines like `SearchEngine()` or `RoutingEngine()` using the default constructor, then these instances need to be recreated as well. Basically, all engines that used the same instance of the `SDKNativeEngine` need to be recreated after it was disposed.
## Remove unused voice and font files to reduce the package size
By removing unused **voice files** like `voice_package_ar-SA` you can reduce the package size of the HERE SDK. These voice packages are only needed when you want to use turn-by-turn navigation with text-to-speech engines. Note that voice files are only included as part of Navigate.
On top, the HERE SDK contains several **font files** to render map labels for all supported languages. If you want to optimize the size of the overall app, you can remove selected fonts.
For example, the `DroidSansFallback` font uses the Simplified Chinese ideographs for shared Unicode code points. It is packaged in the HERE SDK `AAR` file (which can be opened by appending ".zip" to the file name):
* `assets/geoviz/fonts/DroidSansFallback.ttf`
As another example, if you do not need to render the full set of Japanese characters, you can remove:
* `assets/geoviz/fonts/NotoSansJP-Regular.otf`
Note that such fonts may not only be used in [Japan](https://docs.here.com/here-sdk/docs/customization-catalogs#configure-a-japan-map) and China, but also for other areas around the world when users switch their device language to Japanese or Chinese.
In order to [remove files](https://developer.android.com/reference/tools/gradle-api/8.3/com/android/build/api/variant/ResourcesPackaging#excludes), you need to edit the app's `build.gradle` file.
For **Android Gradle plugin** versions >= 7.0 use [AndroidResources](https://developer.android.com/reference/tools/gradle-api/8.3/com/android/build/api/dsl/AndroidResources) like shown below:
```xml
android {
...
androidResources {
def languagesToRemove = ['ru-Ru', 'zh-HK']
def languagePatterns = languagesToRemove.collect {"!voice_package_${it}*"}.join(":")
ignoreAssetsPattern "${languagePatterns}:!DroidSansFallback.ttf:!NotoSansJP-Regular.otf"
}
...
}
```
This excludes the listed fonts and voice assets from the final package. If you need to exclude more assets you need to list them as well.
Note that this example uses the [delimiter syntax](https://android.googlesource.com/platform/frameworks/base/+/6d2c0e5/tools/aapt2/Files.h#88) to exclude files.
[Here](https://docs.here.com/here-sdk/docs/navigation-voice-guidance#supported-languages-for-voice-guidance) you can find a list of all supported voice languages together with the name of the related voice skin that is stored inside the HERE SDK framework. Alternatively, look into the AAR by unzipping it and search for the voice and/or font files that you want to exclude.
If your Android Gradle plugin version is below 7.0 you can replace `androidResources` with [aaptOptions](https://developer.android.com/reference/tools/gradle-api/8.3/com/android/build/api/dsl/AaptOptions).
> #### Note
>
> When you remove a font, it is recommended to switch the map language to any other language than the removed font. At least one font needs to be left to see any map labels. Note that each time a label needs to be displayed in a language for a font that was removed an error message is logged - for each character that is missing.
Note that the size of a font file may range from a few hundred kilobytes to a few megabytes in size. After removing selected fonts your application consumes less space when it is installed on a device. The maximum amount that you can save with these steps is approximately 11 MB.
## Remove unused truck restriction icons to reduce the package size
You can manually remove unused truck restriction icons from the following paths inside the HERE SDK binary:
```
- /assets/geoviz/assets/oslo/truck_restriction/night/ui/
- /assets/geoviz/assets/oslo/truck_restriction/day/ui/
```
These icons are only used when creating vehicle restriction icons with `IconProvider.createVehicleRestrictionIcon()` and the `IconProviderAssetType.UI` setting. They are better suited for UI rendering compared to their `IconProviderAssetType.MAP` counterparts. If these files are removed, the HERE SDK will automatically fall back to using the `MAP` assets.
These SVG icons are included in the HERE SDK binary and occupy approximately 264 KB when compressed.
If you do not plan to use the `IconProvider` and if you do not need to show the `MapFeatures.VEHICLE_RESTRICTION` layer, then you can save considerably more space by removing the entire folder `assets/geoviz/assets/oslo/truck_restriction`.
To remove these files, follow the steps outlined in the [section above](#remove-unused-voice-and-font-files-to-reduce-the-package-size).
## Use ABI splits for Android to remove unused ABIs
Size management: with ABI splits you can reduce the package size of the HERE SDK AAR binary file. As a result, your application will occupy less storage space on a device.
By default, the HERE SDK for Android includes the following ABIs: `armeabi-v7a`, `arm64-v8a` (mainly used for devices) and `x86`, `x86_64` (mainly used for emulators). You can enable ABI splits to build your app, for example, only for the `armeabi-v7a` or `arm64-v8a` architectures. The `armeabi-v7a` architecture is mostly used by older devices.
Do this by modifying your app's `build.gradle` file:
```
android {
(...)
splits {
abi {
enable true
reset()
include 'x86_64', 'arm64-v8a' // Choose what you need.
universalApk false
}
}
(...)
}
```
Now, when you execute `./gradlew assembleRelease` from command line, the following two APKs are generated: `app-x86_64-release.apk` and `app-arm64-v8a-release.apk`. Each APK contains only the desired ABI and is therefore much smaller in size. If you change the `splits` block to set `universalApk true`, then also a universal APK is generated that contains all ABIs, which is obviously much bigger.
For more information about the `splits` Gradle block, see [Configure Multiple APKs for ABIs](https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split).
We recommend to use [legacy packaging](https://developer.android.com/build/releases/past-releases/agp-4-2-0-release-notes#compress-native-libs-dsl).
> #### Note
>
> By default, an APK built with the HERE SDK for release will be around 103 MB or higher - depending on the app features. Therefore, in order to release an app the Play Store, it is required to use either ABI Splits or [Android App Bundles (AAB)](https://developer.android.com/guide/app-bundle): as of now, the Play Store limits APKs to 100 MB and for ABBs the limit is 150 MB. If you do not want to maintain several APKs built via ABI splits for selected architectures, consider to use ABBs instead.
## Map rendering modes
Choose surface or texture view: depending on your application needs, the `MapView` supports two different native render modes.
* By default, `MapRenderMode.SURFACE` is used, which offers the best performance, but may suffer from graphical glitches that may occur on Android 12 and newer.
* For applications with complex and dynamic UI or with multiple `MapView` instances consider to use `MapRenderMode.TEXTURE` to avoid graphical glitches. This mode may have a greater performance impact than using the default `SurfaceView`.
Choose the `MapRenderMode` via `HereMapOptions.renderMode`, which allows to set internally a native `SurfaceView` or `TextureView` for rendering.
## Adjust the frame rate
By default, the `MapView` is rendered with 60 frames per second (FPS). Via `mapView.get/setFrameRate()` the maximum frame rate can be adjusted - for example, to reduce CPU / GPU usage on low end devices. It is also possible to deactivate automatic render cycles by setting FPS to 0. Setting negative values has no effect. The value can be set individually per `MapView` instance - in case your app contains multiple `MapView`'s.
Another option is to use [custom map styles](https://docs.here.com/here-sdk/docs/custom-map-styles) that contain less elements to render.
## Protect your credentials
Your credentials should be protected to provide misuse by other parties that are not intended to use them.
One option to keep credentials secure is to store them on a secure server and retrieve them by requests using SSL connections.
For best practice, consider:
* To avoid keeping sensitive data in plain text.
* To transfer credentials using a secure communication channel.
* To store credentials using device security mechanisms and strong encryption ciphers.
* To add anti-tampering and anti-debugging code, so that a potential attacker cannot intercept data during dynamic runtime execution.
* Track the application usage to detect anomalies.
## Callbacks and listeners
* The HERE SDK exposes callbacks for single event notification such as for search results.
* For reoccurring event notifications such as for gesture events, listeners are used. When multiple listeners can be set, then the method pattern `add_x()` and `remove_x()` is used as naming convention. If only one listener can be set at a time, the property pattern is used. Set a listener property to `null` to stop listening.
* It is the responsibility of the developer to handle errors inside the scope of a callback gracefully: As a guideline, code that can throw an exception should be handled.
## Use TaskHandles to cancel asynchronous operations
Most asynchronous methods provide a `TaskHandle` as immediate return value, while the final result of the operation will be returned in a completion handler with a delay. The `TaskHandle` provides status information and it allows to abort an ongoing operation.
## Get access tokens for use with external REST APIs
Each time the HERE SDK is initialized, a new access token is generated internally. In case of multiple `SDKNativeEngine` instances, each instance holds its own token. You can also refresh and fetch the token via `Authentication.authenticate(SDKNativeEngine.getSharedInstance(), callback)` where the callback provides the token via `authenticationData.token` - you can use this token to access external HERE REST APIs.
For using the HERE SDK itself, you do not need to know the token - it is only required under the hood and the HERE SDK is handling the token generation automatically.
To protect our backends against misusage, a rate limit may apply when too many tokens are generated or when too many services are accessed in a too short time frame. In such a case, an engine will respond with a `requestLimitReached` error or similar. If you expect very high app usage, please talk to your HERE representative upfront to adapt the limits where needed.