Here's some code that I used to accomplish something similar. In my example, I  had to post JSON, then download and parse a JSON response and store the response in a SqLite database. You will need to adapt my code to your needs, but the concept is simple. The solution basically boils down to:
1) Parse the Json yourself using a JsonReader.
2) Use a FilterInputStream to publish progress.
I recognize that this solution doesn't use retrofit, so maybe you won't want to use it, but perhaps you will find it helpful.
final ProgressDialog dialog = new ProgressDialog(getActivity(), ProgressDialog.THEME_HOLO_LIGHT);
dialog.setTitle(R.string.downloading_data);
dialog.setMessage("Downloading data...");
dialog.setCanceledOnTouchOutside(false);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
if (!BuildConfig.DEBUG) {
    dialog.setProgressNumberFormat(null);
}
mLoginTask = new AsyncTask<Void, Integer, Void>() {
    @Override
    protected Void doInBackground(Void... params) {
        HttpURLConnection connection = null;
        try {
            byte[] request = ...; // I used a JsonWriter to write to a ByteArrayOutputStream. Since you're likely getting this from file or a GET request, this is likely not necessary.
            URL url = new URL("https://example.com/endpoint");
            connection = (HttpURLConnection)url.openConnection();
            connection.setDoOutput(true);
            connection.setUseCaches(false);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
            connection.setRequestProperty("Content-Length", "" + request.length);
            connection.setRequestProperty("Accept","*/*");
            OutputStream out = connection.getOutputStream();
            out.write(request);
            out.flush();
            out.close();
            connection.setConnectTimeout(3000);
            connection.setReadTimeout(10000);
            connection.connect();
            Thread.sleep(2000); // I don't remember why this was necessary. Likely an exception was thrown in the next line without it, at least on slower networks.
            int responseCode = connection.getResponseCode();
            switch (responseCode) {
                case 200:
                    int length = connection.getContentLength();
                    publishProgress(0, length);
                    final InputStreamReader streamReader = new InputStreamReader(new FilterInputStream(connection.getInputStream()) {
                        private int mTotalBytesRead;
                        @Override
                        public int read() throws IOException {
                            int b = super.read();
                            if (b > 0) {
                                updateProgress(1);
                            }
                            return b;
                        }
                        @Override
                        public int read(byte[] buffer) throws IOException {
                            return updateProgress(super.read(buffer));
                        }
                        @Override
                        public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
                            return updateProgress(super.read(buffer, byteOffset, byteCount));
                        }
                        @Override
                        public long skip(long byteCount) throws IOException {
                            return updateProgress(super.skip(byteCount));
                        }
                        @Override
                        public void mark(int readLimit) {
                            throw new UnsupportedOperationException();
                        }
                        @Override
                        public void reset() throws IOException {
                            throw new UnsupportedOperationException();
                        }
                        @Override
                        public boolean markSupported() {
                            return false;
                        }
                        private int updateProgress(long numBytesRead) {
                           if (numBytesRead > 0) {
                                publishProgress(mTotalBytesRead += numBytesRead);
                            }
                            return (int)numBytesRead;
                        }
                    });
                    JsonReader reader = new JsonReader(streamReader);
                    // your code here will depend on the format of the code. It seems like you have simply an array.
                    reader.beginArray();
                    while (reader.peek() == JsonToken.BEGIN_OBJECT) {
                        JsonObject airport = (JsonObject) Streams.parse(reader);
                        // do some stuff with this airport. Perhaps create an Airport object and add it to an ArrayList.
                    }
                    return null;
                default:
                    String response = IOUtils.toString(connection.getErrorStream());
                    try {
                        Util.showToast(JsonUtil.getString(new JSONObject(response), Constants.ERROR), Toast.LENGTH_LONG);
                        if (responseCode == 403) { // Forbidden
                            publishProgress();
                        }
                    } catch (Exception e) {
                        Util.showToast("Unsupported response\n" + connection.getHeaderField(null)+"\n"+response, Toast.LENGTH_LONG);
                    }
                    break;
            }
        } catch (UnknownHostException e) {
            Util.showToast("You don't appear to be connected to the Internet.", Toast.LENGTH_LONG);
        } catch (Exception e) {
            if (e instanceof InterruptedIOException) {
                return null;
            }
            Util.showToast(e.toString(), Toast.LENGTH_LONG);
            Log.e("DashboardActivity", "error downloading data", e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return null;
    }
    @Override
    protected void onPostExecute(Void result) {
        dialog.cancel();
        TaskUtil.synchronize(HomeFragment.this);
    }
    @Override
    protected void onCancelled() {
        dialog.cancel();
        // todo: maybe you have more cleanup
    }
    @Override
    protected void onProgressUpdate(Integer... values) {
        if (values.length == 0) {
            MyActivity.getCurrentActivity().showLoginInfo(true);
        } else {
            dialog.setProgress(values[0]);
            if (values.length == 2) {
                dialog.setMax(values[1]);
                dialog.setIndeterminate(false);
                dialog.show();
            }
        }
    }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
dialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
    @Override
    public void onCancel(DialogInterface dialog) {
        mLoginTask.cancel(true);
    }
});