Cloudinary Blog

Addressing mobile challenges with the new Cloudinary SDK for Android

Address mobile challenges with the Cloudinary Android SDK

Developing applications for mobile consumption requires facing, and overcoming, some difficult challenges. Apps need to limit their RAM, CPU and battery usage while still performing the required tasks in a reasonable time frame. If too many background tasks are running, the mobile device can become sluggish, with the battery running out very quickly. Coordination with other apps is crucial to keep the device responsive and make the battery last longer.

Networks on mobile devices are also often unstable. Especially in some areas, disconnections are frequent and there are many switches between different network nodes, as well as slow network performance with a high percentage of packet loss. Apps need to be able to handle all the network issues, and if necessary, network activity needs to fail smoothly and resume when the network is available again, automatically if possible.

To support higher resolution mobile devices, the app backend needs to serve high-quality images and videos. Those resources take longer to download, and also consume more CPU and RAM to decode and then display on screen. On the other hand, for a low-resolution mobile device those are wasted resources, because you only need a low-quality resource. So you need to maintain a lot of different versions for each of your resources and then determine which one is most appropriate to serve to each mobile device.

With all that in mind, Cloudinary's latest version of the Android SDK lets you easily implement background upload functionality in your app to ensure the best user experience. If the user is doing something CPU, RAM or power intensive, the uploads can be paused so that the user experience doesn't suffer, and then continue when conditions are more favorable. And with Cloudinary's Dynamic URL feature, the delivered resource can be generated on the fly, eliminating the need to pre-generate all the various versions of your resources for different mobile devices.

The Cloudinary Android SDK v2.0

The Cloudinary SDK works on the principle that Android knows how to manage its own memory, CPU and power, and so relies on the operating system itself doing the prioritization of those limited hardware resources. All uploads are presented as requests to the operating system, which will schedule the uploads accordingly. The Cloudinary SDK hooks into Android's JobScheduler, which makes sure the mobile device works smoothly when running background uploads. If the mobile device is running an older version of Android that does not support the JobScheduler API, then the Cloudinary SDK transparently falls back to using the scheduling engine inside Google Play services.

All upload requests can be finely-tuned using the new policy mechanism, and the SDK can handle global callbacks, even when your app is down, or is running in the background.

Presenting the Cloudinary MediaManager

The Cloudinary Android SDK v2.0 provides you with the MediaManager class, with methods for configuring and handling all your media-related operations. Use the upload method to build your request, which is then dispatched to a background queue via the MediaManager's dispatch method.

MediaManager.get().upload(imageFile).dispatch();

The MediaManager's option method lets you include any upload parameters for Cloudinary, for example, adding the tag user_uploaded:

MediaManager.get().upload(imageFile)
   .option("tags", "user_uploaded")
   .dispatch();

While you are at it, you might want to specify some upload conditions in your request, such as how many times to retry after a recoverable error (e.g., network issues), to limit the upload to a wifi network, or only when the device is charging. The MediaManager's policy method lets you do just that, overriding the default values for that particular upload request:

MediaManager.get().upload(filePath)
   .policy(new UploadPolicy.Builder()
      .maxRetries(7)
      .requiresCharging(true)
      .networkPolicy(UploadPolicy.NetworkType.UNMETERED)
      .build())
   .dispatch();

Callbacks

Since all uploads are ultimately run asynchronously by the system, the MediaManager's callback method provides an easy way to hook into the upload's progress and provide specific code to run at each stage of the upload.

String requestId = MediaManager.get().upload(filePath)
   .callback(new UploadCallback() {
      @Override
      public void onProgress(String requestId, long bytes, long totalBytes) {
         Double progress = (double) bytes/totalBytes;
         // post progress to app UI (e.g. progress bar, notification)
      }
      @Override
      public void onSuccess(String requestId, Map resultData) {
      }
    ...
   })
   .dispatch();

This method of implementing callbacks won't suffice if your app is down or is running in the background. In this case, you would want to implement global callbacks for your app by registering a new service class that extends the provided ListenerService class. All upload request callbacks will be routed to your service, which implements the code to run at each stage of the upload.

public class MyClass extends ListenerService {
   @Override
   public void onProgress(String requestId, long bytes, long totalBytes) {
      Double progress = (double) bytes/totalBytes;
      // post progress to app UI (e.g. progress bar, notification)
   }
   @Override
   public void onSuccess(String requestId, Map resultData) {
   }
   ...
}

Not only upload

Once your media assets have been uploaded to Cloudinary, you can take advantage of Cloudinary's Dynamic URL feature to deliver your images and videos to your users. Dynamic URLs include instructions telling Cloudinary how to transform and optimize the asset on-the-fly, and then deliver it through a fast CDN to the end user for optimal user experience. There is no need to pre-generate all the different versions you may need for the various devices running your app.

Besides taking care of all your resource uploads directly to your Cloudinary account, the MediaManager class provides the url method to generate a URL string for accessing resources uploaded to your Cloudinary account:

MediaManager.get().url().generate("sample.jpg")
// returns: http://res.cloudinary.com/demo/image/upload/sample.jpg

You can also call the transformation method to include any transformation instructions in the generated URL:

Android:
MediaManager.get().url().transformation(new Transformation()
  .gravity("face").radius(75).border("10px_solid_grey").crop("crop").chain()
  .overlay("couple").width(170).height(150).radius("max").gravity("faces").border("3px_solid_black").crop("thumb").chain()
  .flags("layer_apply").gravity("north_east")).generate("woman2.jpg");
image cropped with face detection and given rounded corners and a grey border, with an overlay of the image of `couple` resized to an oval thumbnail with face detection and a black border added to the northeast corner

Summary

The new version of the Cloudinary SDK for Android is a major release that now makes it simple to include upload functionality in your mobile app, and let your users upload their media directly to your Cloudinary account. The SDK takes advantage of Android's built-in functionality when executing the uploads, to make sure that your users enjoy an uninterrupted experience while using your app. Integrating with Cloudinary to upload, manage, and deliver all your app resources is now easier than ever. Make sure you check out the Android integration documentation, and if you don't already have a Cloudinary account, you can sign up for free.

Recent Blog Posts

Give your mobile app a boost: pre-upload image processing

As a mobile developer, enabling users to upload images and share them with other users is a very common requirement. When developing those capabilities, we need to take into account that most users won't think twice about uploading the massive images that their high-resolution mobile cameras capture. Those huge files are not only overkill for on-screen display, but can also cause significant slow downs in upload and delivery times. And of course those same users wouldn't think twice about complaining or abandoning our app if their overall user experience wasn't smooth and fast.

Read more
Cloudinary Helps Hinge Keep Modern Romance Real

To create a profile, Hinge users initially had to connect their Facebook and/or Instagram accounts to the app, which would import images to the users’ Hinge profiles. Hinge stored those images with a URL that expired after two months, unless the user logged into the app regularly. This aspect of the app was frustrating for users because the photos would become inaccessible for others to view.

Read more
Building a Smart AI Image Search Tool Using React

In our first article, we built a part of the front-end of our image search tool with the focus mainly on the parent App.js stateful component.

In this article - part two of a series - we will continue developing a Smart Search App, in which users can search for content in an image, not just the description. The app is built with React for UI interaction, Cloudinary for image upload and management and Algolia for search.

Read more