Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Using the Azure IoT SDK in Android

DZone's Guide to

Using the Azure IoT SDK in Android

See how Azure's SDKs can be used with your Android IoT projects and devices, as well as some handy workarounds for problems that might appear along the way.

· IoT Zone
Free Resource

Download Red Hat’s blueprint for building an open IoT platform—open source from cloud to gateways to devices.

Azure is a great IoT platform — they have SDKs in all major languages. At OnRue Technology Solutions, when we integrated Azure with Android for our product DataWheels, we faced a lot of surprises. I am highlighting the key changes we did for using Azure SDK seamlessly and successfully in the Android OS.

When we started, we did not think that would need to make changes. Android uses Java, and the Azure Java SDK works fine independently. However, the problem is that Azure SDKs were developed using Java 8 features — namely Lambda expressions — and Android did not support Java 8 (at least till August 2016, when we developed). Note that we used the master branch from Azure SDK GitHub.

We used the SDK for both registering a device as well sending a message to the Azure IoT Hub. We used Android API version 18 as the minimum SDK version and 23 as the target SDK version. We tested on a KitKat device (Samsung Galaxy S3).

Changing Lambda Expressions

Lambda expressions are a key feature included in Java 8. In the iothub-java-services-client project, the following classes and methods use lambda expressions:

  • ClassName:com.microsoft.azure.iot.service.sdk.ServiceClient
    methods:openAsync, closeAsync, sendAsync

  • ClassName:com.microsoft.azure.iot.service.sdk.FeedbackReceiver
    methods:addDeviceAsync, getDeviceAsync, getDevicesAsync, updateDevice, updateDeviceAsync, removeDevice, getStatistics, exportDevicesAsync, importDevicesAsync, getJobAsync.

In order to fix it, the logic thT was in the lambda expression was put in another method. For example, check out the code for ServiceClient.openAsync():

public CompletableFuture<Void> openAsync()
    {
    // Codes_SRS_SERVICE_SDK_JAVA_SERVICECLIENT_12_014: [The function shall create an async wrapper around the open() function call]
    final CompletableFuture<Void> future = new CompletableFuture<>();
    executor.submit(() -> {
        try
            {
            open();
            future.complete(null);
        } catch (IOException e)
        {
            future.completeExceptionally(e);
        }
    });
    return future;
}                                                                                                                                           is converted as follows                                                                                  public CompletableFuture<Void> openAsync()
{
    // Codes_SRS_SERVICE_SDK_JAVA_SERVICECLIENT_12_014: [The function shall create an async wrapper around the open() function call]
    final CompletableFuture<Void> future = new CompletableFuture<>();
    OpenAsyncClass callback=new OpenAsyncClass(this, future);                         executor.submit(callback);
    return future;
}                  


And below is the code for OpenAsyncClass:

public class OpenAsyncClass implements Runnable {private ServiceClient client=null;
private CompletableFuture<Void> future=null;
public OpenAsyncClass(ServiceClient client,CompletableFuture<Void> future){this.client=client;
    this.future=future;
}
@Override
public void run() {
    // TODO Auto-generated method stub
    try {
        client.open();
        future.complete(null);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        //e.printStackTrace();
        future.completeExceptionally(e);
    }
}


I tried to find a common implementation, but I couldn't. The need was different in different places. Instead of having the new class as a separate file, you can also use inline classes. But iI am not a big fan of that approach.

    1. CharSet:Class IotHubServiceSasToken uses StandardCharsets.UTF_8 . This is available only with Java 8, and because Android does not support Java 8 (at the time of development in August 2016), we used Charset.availableCharsets().get("UTF-8").name() instead of StandardCharsets.UTF_8 Without doing the fix, we were not able to register the devices.

      Another strange error what we got was that Android was not able to find the org.apache.commons.codec.binary.Base64.encodeBase64String method in spite of having the correct JAR (which has the correct class and method). As a workaround, we cloned the commons package from a repository, created a new class by copying Base64, and use the new class.
    2. Endurance testing failed for App: This might not be a problem for everyone, but if you are posting messages to IoT Hub in regular intervals (e.g once every 3 seconds) using MQTT (again using Azure SDKs), you might encounter this problem.

      In our case, as recommended by Android, the logic for sending the message was insulated from UI activity by encapsulating it into a service. The service was called once every five seconds. We noticed that after four or five sequences, the services weren't executed. As per Android, a new execution of a service will not start if a previous one is pending. And we used a single instance of a client across multiple messages posting (this was recommended by Azure). We were posting messages using the sendEventAsync(msg, callback, lockobj)method of the client. This method adds the messages to a list. The list was picked up at regular intervals.

      Upon further debugging, we found that messages were posted using sendEventMethod of MQTTIoTHubConnection. This method shares a lock with the open and connectionLost methods in them. To add messages to a temporary list, the sendEvent method calls the addMessage method of the class, which implements IotHubTransportInterface. The addMessage method of the transport shares a lock with the sendMessage method of the transport, because sendMessage calls sendEventMethod of MQTTIoTHubConnection.
       
      If there is an intermittent network error, then the connection class is busy sharing locks between the open and close methods and messages, which need to be posted, and is waiting for the lock to release. These waiting messages, in turn, hold locks in the transport class which prevents new messgaes being added to the list. So as long as the messages are not added to the list, service remains active and is not completed and waits for a longer time.

      In order to overcome this, we have added new messages to the DeviceClient and Transport classes so that messages are sent immediately. In case any connection is lost or closed, and if messages are not sent, then an exception is thrown and we store the message in the local store. This will be sent during synchronization. We also changed the open method in DeviceClient. I'm sorry, I know that a design diagram would have helped out here, but I didn't have the time.
    3. High CPU: When using Azure's default SDKs for posting messages, I had observed that my app was consuming a lot of the CPU. It was found to be due to the default implementation of DeviceClient, which adds the messages to a list. A scheduled thread will run at a specfic duration (once everything 101 ms). This kind of looping, and an ever-present background thread, added overhead.

      As part of a fix for services not getting executed, we moved from delayed posting to real-time posting, and it indirectly solved this issue. The design developed by Azure is great, and their async posting of messages is perfect and glitch free. But if you are using it in a resource- and networked-crunched system, you might need to tweak it a bit like we did. Drop a comment if you have any questions.

Build an open IoT platform with Red Hat—keep it flexible with open source software.

Topics:
azure iot suite ,android ,iot ,lambda expressions

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}