AWS Mobile Blog

AWS SDK for Android Transfer Manager to Transfer Utility Migration Guide

by Weston Edwards | on | Permalink | Comments |  Share

With the announcement of the S3 Transfer Utility, we deprecated the S3 Transfer Manager. This post is a guide to help developers currently using the Transfer Manager migrate to the new Transfer Utility. The guide is split into sections based on functionality, and shows how Transfer Manager code will change to work with the Transfer Utility. So lets get started!

Client Construction

The Transfer Utility has a single constructor, which requires an instance of AmazonS3Client (which we recommend setting the region on, prior to passing to the Transfer Utility), and the application context. As with the Transfer Manager, we recommend constructing the Transfer Utility client once, and using a single instance throughout your application. An example is shown below:

CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
context.getApplicationContext(),
YOUR_IDENTITY_POOL_ID,
Regions.US_EAST_1);

AmazonS3Client s3Client = new AmazonS3Client(credentialsProvider);

TransferUtility transferUtility = new TransferUtility(s3Client,context.getApplicationContext());

Permissions & Service Declaration

The Transfer Manager only requires the INTERNET permission. However, since the Transfer Utility automatically detects network state and pauses/resumes transfers based on the network state, your app will require the ACCESS_NETWORK_STATE permission as well.

<uses-permission android:name="android.permission.INTERNET" />  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

The Transfer Utility is now based on an Android service, which must be declared in the AndroidManifest.xml within the Application tag.

<service android:name= "com.amazonaws.mobileconnectors.s3.transferutility.TransferService" android:enabled="true" />

Uploading and Downloading

The Transfer Manager has a plethora of APIs for uploading and downloading. Pausing transfers using the Transfer Manager is not possible with stream based uploads or downloads, or those using client-side encryption. Additionally, when using streams, developers must still specify the content length ahead of time. To create one coherent API, which can always be paused and resumed, the Transfer Utility has one single-file-based method for uploads, and downloads. All requests will need to be converted to the API below:

Uploading:

TransferObserver observer = transferUtility.upload(
MY_BUCKET,           // The S3 bucket to upload to
OBJECT_KEY,          // The key for the uploaded object          FILE_TO_UPLOAD       // The location of the file to be uploaded          );

Downloading:


TransferObserver observer = transferUtility.download(
MY_BUCKET,           // The S3 bucket to download from
OBJECT_KEY,          // The key for the object to download
FILE_TO_UPLOAD       // The name of the file to download
);  

Tracking Transfers

To track transfer progress with the Transfer Manager, developers pass an S3ProgressListener callback to upload or download, which periodically fires the method below.

public void progressChanged(ProgressEvent progressEvent);  

The ProgressEvent gives developers an integer code if the state of the transfer had changed, and would tell developers the amount of data transferred since the last progressChanged was fired.

The Transfer Utility returns a TransferObserver object when you call Upload/Download/Resume. You can also query for TransferObservers from anywhere within your app using the following APIs:

public TransferObserver getTransferById(int id)
public List<TransferObserver> getTransfersWithType(TransferType type)
public List<TransferObserver> getTransfersWithTypeAndState(TransferType type,
            TransferState state)

You can get the current state and progress from the TransferObserver, or if you are interested in continual updates you can call

public void setTransferListener(TransferListener listener)

on the TransferObserver, and the TransferListener will fire the following callbacks:

public void onStateChanged(int id, TransferState state);
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal);
public void onError(int id, Exception ex);

So code relating to :

  • progressEvent.getEventCode() will now be handled by the onStateChange() function, which now uses an enum to describe the state of the transfer.

  • progressEvent.getBytesTransferred() will need to be updated to use the onProgressChanged() method. NOTE: bytesCurrent in onProgressChanged() represents the total number of bytes transferred, while the getBytesTransferred in the ProgressEvent class gives the number of bytes since the last ProgressEvent was fired.

Pausing Transfers

With the Transfer Manager, transfers using APIs involving I/O streams cannot be paused. For transfers that can be paused, developers call pause() on the Upload or Download object, or pass a callback to upload and download which fires when a transfer is able to be paused. In either case, a PersistableTransfer object is received, which then produces a String via the serialize() method. This String then has to be written to persistable storage by the developer. Migrating pause functionality to the Transfer Utility is easy, since all transfers can be paused and resumed. Additionally, the Transfer Utility stores all of the metadata about transfers to the local SQLite database, so developers do not need to persist anything. The Transfer Utility automatically pauses transfers when the app loses network connectivity, and will automatically resume them when the app regains connectivity. You can manually pause a single transfer using

public boolean pause(int id)

or pause uploads, downloads, or all transfers with

public void pauseAllWithType(TransferType type)

The transfer id can be retrieved from any TransferObserver instance, which can be queried for as described in the Tracking Transfers sections above. The only other consideration is that pausing will return false and do nothing unless the transfer is in one of the following states:

TransferState.IN_PROGRESS
TransferState.RESUMED_WAITING
TransferState.WAITING

Resuming Transfers

In Transfer Manager code, to resume an upload you first create a PersistableTransfer with the static deserializeFrom() method, passing it the String you received from calling serialize() on an Upload or Download. Then with the PersistableTransfer object, you call resume() from the TransferManager class.

The Transfer Utility handles persisting the transfer metadata, so all you need to do is call

public TransferObserver resume(int id)

where id is the id from a TransferObserver. If you do not have a TransferObserver you can query for one as described in the Tracking Transfers section above. Remember that if a transfer is paused because of a loss of network connectivity, it will automatically be resumed and there is no action you need to take. Transfers that are automatically paused and waiting for network connectivity will have the state TransferState.WAITING_FOR_NETWORK to distinguish them from manually paused transfers.

Copying Transfers

The Transfer Utility does not support a copy() API, because it is not a commonly used API on mobile. However you can accomplish much of the same functionality using the AmazonS3Client class copyObject() method shown below.

public CopyObjectResult copyObject(String sourceBucketName, String sourceKey,String destinationBucketName, String destinationKey)

Aborting Transfers Using the Transfer Manager you can abort a transfer by calling

public void abort();

on an Upload or Download object. With the Transfer Utility to abort a transfer you call

public boolean cancel(int id)

on the Transfer Utility class. Canceling a transfer using the Transfer Utility will not remove it from the local SQLite database, and it can still be queried for. To completely remove the transfer from local storage, you must first cancel the transfer (if it is running), and call the delete method shown below. It is an error to delete a running transfer without first canceling it.

public boolean deleteTransferRecord(int id)

For additional help using the Transfer Utility see:

The step by step Getting Started Guide

The Sample on GitHub (including tutorial)

The latest SDK API Reference

This guide is intended to make transitioning from the Transfer Manager to the Transfer Utility as easy and quick as possible. If you have any additional questions or feedback, do not hesitate to contact us: as a comment on this blog, a post on our forums, or as a GitHub issue.