Downloading a file using retrofit

I've started using retrofit recently and it's intuitively simpler than Google's volley. And it's got really good benchmarks. And it's made by the same guys who made Dagger and Picasso. So you should give it a try too if you haven't.

I spent considerable amount of time figuring how to download an image yesterday. So here's how to do it using retrofit. This will work for any file type - not just images.

Create the service interface
public interface IMyService {
    Call<ResponseBody> getFile(@Url String url);
Set permissions

The app will require the following permissions:

  1. INTERNET - to access the internet & download the file
  2. WRITE_EXTERNAL_STORAGE - to be able to write to the filesystem & save the file

Add the following code before opening the <application> in the AndroidManifest.xml file:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Create the AsyncTask

Since I'm downloading an image, I'm going to save the file in a folder named after the app in the pictures directory.

private class DownloadFileAsyncTask extends AsyncTask<InputStream, Void, Boolean> {

    final String appDirectoryName = "AppName";
    final File imageRoot = new File(Environment.getExternalStoragePublicDirectory(
            Environment.DIRECTORY_PICTURES), appDirectoryName);
    final String filename = "image.jpg";

    protected Boolean doInBackground(InputStream... params) {
        InputStream inputStream = params[0];
        File file = new File(imageRoot, filename); 
        OutputStream output = null;
        try {
            output = new FileOutputStream(file);

            byte[] buffer = new byte[1024]; // or other buffer size
            int read;

            Log.d(TAG, "Attempting to write to: " + imageRoot + "/" + filename);
            while ((read = != -1) {
                output.write(buffer, 0, read);
                Log.v(TAG, "Writing to buffer to output stream.");
            Log.d(TAG, "Flushing output stream.");
            Log.d(TAG, "Output flushed.");
        } catch (IOException e) {
            Log.e(TAG, "IO Exception: " + e.getMessage());
            return false;
        } finally {
            try {
                if (output != null) {
                    Log.d(TAG, "Output stream closed sucessfully.");
                    Log.d(TAG, "Output stream is null");
            } catch (IOException e){
                Log.e(TAG, "Couldn't close output stream: " + e.getMessage());
                return false;
        return true;

    protected void onPostExecute(Boolean result) {

        Log.d(TAG, "Download success: " + result);
        // TODO: show a snackbar or a toast

In my case, the class is an inner class. TAG is defined in the outer class as:

private static final String TAG = "###ActivityName";
Build an instance of the Service
Retrofit retrofit = new Retrofit.Builder()
IMyService service = retrofit.create(IMyService.class);

The base url is required. The url doesn't matter if you're going to be using an absolute url to download the file. Relative urls must however be relative to the base url.

Initiate the download
service.getFile("https://image.url/goes/here).enqueue(new Callback<ResponseBody>() {
    public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
        Log.d(TAG, response.message());
            Log.e(TAG, "Something's gone wrong");
            // TODO: show error message
        DownloadFileAsyncTask downloadFileAsyncTask = new DownloadFileAsyncTask();

    public void onFailure(Call<ResponseBody> call, Throwable t) {
        Log.e(TAG, t.getMessage());
        // TODO: show error message