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.

Copy to clipboard
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:

Copy to clipboard
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:

Copy to clipboard
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.

Copy to clipboard
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.

Copy to clipboard
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:

Copy to clipboard
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:
Copy to clipboard
MediaManager.get().url().transformation(new Transformation()
  .gravity("face").radius(75).border("10px_solid_grey").crop("crop").chain()
  .overlay(new Layer().publicId("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

A New, Simple Tool for Creating Text Overlays for Images

Many Cloudinary users desire a UI for tasks like creating text overlays for images, which they then embed on webpages or download for marketing campaigns. Generating such overlays with the Cloudinary Media Library UI involves a bit of a learning curve, especially if they require multiple fonts or text lines, which even experienced users might find challenging to implement.

Read more
Transitioning JPEG-Based to JPEG XL-Based Images for Web Platforms

When the JPEG codec was being developed in the late 1980s, no standardized, lossy image-compression formats existed. JPEG became ready at exactly the right time in 1992, when the World Wide Web and digital cameras were about to become a thing. The introduction of HTML’s <img> tag in 1995 ensured the recognition of JPEG as the web format—at least for photographs. During the 1990s, digital cameras replaced analog ones and, given the limited memory capacities of that era, JPEG became the standard format for photography, especially for consumer-grade cameras.

Read more

Amplify Your Jamstack With Video

By Alex Patterson
Amplify Your Jamstack With Cloudinary Video

As defined by Amazon Web Services (AWS), Amplify is a set of products and tools with which mobile and front-end web developers can build and deploy AWS-powered, secure, and scalable full-stack apps. Also, you can efficiently configure their back ends, connect them to your app with just a few lines of code, and deploy static web apps in only three steps. Historically, because of their performance issues, managing images and videos is a daunting challenge for developers. Even though you can easily load media to an S3 bucket with AWS Amplify, transforming, compressing, and responsively delivering them is labor intensive and time consuming.

Read more
Cloudinary Helps Move James Hardie’s Experience Online

While COVID has affected most businesses, it has been particularly hard on those that sell products for the physical ‘brick and mortar’ world. One company that literally fits that bill is our Australian customer James Hardie, the largest global manufacturer of fibre cement products used in both domestic and commercial construction. These are materials that its buyers ideally want to see up close, in detail. When customers have questions, they expect personal service.

Read more