2015-06-29 2 views
5

Я загружаю PDF-файл с модифицированной версией, способ, которым я загружаю его по блокам. Я использую заголовок Content-Range, чтобы получить диапазон байтов, тогда мне нужно записать эти байты на file, проблема в том, чтобы написать их. Я использую функцию flatMap() для возврата наблюдаемого для каждого запроса, который должен быть выполнен для загрузки файла.Загрузите и напишите файл с Retrofit и RxJava

.flatMap(new Func1<Integer, Observable<Response>>() { 
       @Override 
       public Observable<Response> call(Integer offset) { 
        int end; 

        if (offset + BLOCK_SIZE > (contentLength - 1)) 
         end = (int) contentLength - 1 - offset; 

        else 
         end = offset + BLOCK_SIZE; 

        String range = getResources().getString(R.string.range_format, offset, end); 

        return ApiAdapter.getApiService().downloadPDFBlock(range); 
       } 
      }) 

The downloadPDFBlock Присылать строки, который необходим заголовок: Range: bytes=0-3999. Затем я использую подписываться функцией, чтобы записать байты загруженных

subscribe(new Subscriber<Response>() { 
       @Override 
       public void onCompleted() { 
        Log.i(LOG_TAG, file.getAbsolutePath()); 
       } 

       @Override 
       public void onError(Throwable e) { 
        e.printStackTrace(); 
       } 

       @Override 
       public void onNext(Response response) { 
        writeInCache(response); 
        } 
       } 
      }); 

Но проблема заключается в том, что процесс записи производится неупорядоченным. Например: если сначала загружается Range: bytes=44959-53151, это будут байты, которые будут записаны сначала в файле. Я прочитал около BlockingObserver, но я не знаю, могло ли это быть решением.

Надеюсь, вы могли бы мне помочь.

+1

Проверить 'оператор concatMap' http://fernandocejas.com/2015/01/11/rxjava-observable-tranformation-concatmap-vs-flatmap/ –

+1

В качестве альтернативы, используйте RandomAccessFile и запись в тот же файл смещения запрос был сделан. – akarnokd

+0

Вы должны использовать DownloadManager для загрузки большого содержимого. http://developer.android.com/reference/android/app/DownloadManager.html –

ответ

8

Это example для скачивания файла и сохранения его на диске в Android.

Ниже приведена ссылка на приведенный выше пример ссылки без использования выражения лямбда.

Интерфейс Retrofit 2, @Streaming для загрузки больших файлов.

Код для загрузки файла и сохранения его на диск с использованием Retrofit 2 и rxjava. Обновите baseUrl и URL-адрес в приведенном ниже коде на ваш фактический URL-адрес файла, который вам нужно загрузить.

public void downloadZipFile() { 
    Retrofit retrofit = new Retrofit.Builder() 
      .baseUrl("https://my.resources.com/") 
      .client(new OkHttpClient.Builder().build()) 
      .addCallAdapterFactory(RxJavaCallAdapterFactory.create()).build(); 
    RetrofitApi downloadService = retrofit.create(RetrofitApi.class); 

    downloadService.downloadFile("resources/archive/important_files.zip") 
      .flatMap(new Func1<Response<ResponseBody>, Observable<File>>() { 
       @Override 
       public Observable<File> call(final Response<ResponseBody> responseBodyResponse) { 
        return Observable.create(new Observable.OnSubscribe<File>() { 
         @Override 
         public void call(Subscriber<? super File> subscriber) { 
          try { 
           // you can access headers of response 
           String header = responseBodyResponse.headers().get("Content-Disposition"); 
           // this is specific case, it's up to you how you want to save your file 
           // if you are not downloading file from direct link, you might be lucky to obtain file name from header 
           String fileName = header.replace("attachment; filename=", ""); 
           // will create file in global Music directory, can be any other directory, just don't forget to handle permissions 
           File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsoluteFile(), fileName); 

           BufferedSink sink = Okio.buffer(Okio.sink(file)); 
           // you can access body of response 
           sink.writeAll(responseBodyResponse.body().source()); 
           sink.close(); 
           subscriber.onNext(file); 
           subscriber.onCompleted(); 
          } catch (IOException e) { 
           e.printStackTrace(); 
           subscriber.onError(e); 
          } 
         } 
        }); 
       } 
      }) 
      .subscribeOn(Schedulers.io()) 
      .observeOn(AndroidSchedulers.mainThread()) 
      .subscribe(new Observer<File>() { 
          @Override 
          public void onCompleted() { 
           Log.d("downloadZipFile", "onCompleted"); 
          } 

          @Override 
          public void onError(Throwable e) { 
           e.printStackTrace(); 
           Log.d("downloadZipFile", "Error " + e.getMessage()); 
          } 

          @Override 
          public void onNext(File file) { 
           Log.d("downloadZipFile", "File downloaded to " + file.getAbsolutePath()); 
          } 
         }); 
} 
+0

эй человек, вы создаете экземпляр сервера api каждый раз при загрузке файла –

+2

Это для демонстрации, экземпляр Retrofit можно перенести в глобальное состояние. –

+0

У вас есть вставка как param '@Url String fileUrl', но введите path' "resources/archive/important_files.zip" ... ... метод должен быть '@Streaming @GET ({path}) Наблюдаемый > downloadFile (@Path ("путь") String fileUrl); ' – NickUnuchek

Смежные вопросы