2017-12-28 35 views
0

私はアンドロイドでCSVファイルをダウンロードしようとしています。それがダウンロードされると、私はジャクソンを使用してマップし、sqlite3 dbに保存します。私が直面している問題は、ファイルをダウンロードする呼び出しを行うと、私はを取得しているということです。ファイルサイズは12MBです。私はブラウザで同じものを試してみるとファイルをダウンロードできるので、エンドポイントの問題はないと思う。ファイルをダウンロード中にメモリが不足しました

ダウンロードするには、AsyncTaskを使用しています。

class DownloadCSVTask extends AsyncTask<Void, String, Void> { 

    private final Call<ResponseBody> csvDump; 
    private final Context context; 

    public DownloadCSVTask(Call<ResponseBody> csvDump, Context context) { 
     this.csvDump = csvDump; 
     this.context = context; 
    } 

    @Override 
    protected Void doInBackground(Void... voids) { 
     try { 
      Response<ResponseBody> response = csvDump.execute(); 
      File fileFromResponse = createFileFromResponse(response); 
      mapFileContentsToModelAndPersist(fileFromResponse); 
     } catch (IOException e) { 
      Log.e(getClass().getSimpleName(), "CSV pull failed"); 
     } 
     return null; 
    } 

    private File createFileFromResponse(Response<ResponseBody> response) throws IOException { 
     File path = context.getFilesDir(); 
     File csvFile = File.createTempFile(TEMP_PREFIX, CSV_EXTENSION, path); 
     FileOutputStream fileOutputStream = context.openFileOutput(csvFile.getName(), Context.MODE_PRIVATE); 
     fileOutputStream.write(response.body().bytes()); 
     Log.i(getClass().getCanonicalName(), "Writing file completed" + csvFile.getAbsolutePath()); 
     fileOutputStream.close(); 
     return csvFile; 
    } 

    private void mapFileContentsToModelAndPersist(File fileFromResponse) { 
     try { 
      MappingIterator<City> cityIter = new CsvMapper().readerWithTypedSchemaFor(City.class).readValues(fileFromResponse); 
      List<City> cities = cityIter.readAll(); 
      Stream.of(cities).forEach(City::persist); 
     } catch (IOException e) { 
      Log.e(getClass().getSimpleName(), "Failed to map contents of file to City Class"); 
     } 
    } 
} 

私は取得していますエラーログ:

java.lang.RuntimeException: An error occured while executing doInBackground() 
         E  at android.os.AsyncTask$3.done(AsyncTask.java:300) 
         E  at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355) 
         E  at java.util.concurrent.FutureTask.setException(FutureTask.java:222) 
         E  at java.util.concurrent.FutureTask.run(FutureTask.java:242) 
         E  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) 
         E  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) 
         E  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) 
         E  at java.lang.Thread.run(Thread.java:841) 
         E Caused by: java.lang.OutOfMemoryError 
         E  at java.lang.String.<init>(String.java:354) 
         E  at java.lang.String.<init>(String.java:393) 
         E  at okio.Buffer.readString(Buffer.java:616) 
         E  at okio.Buffer.readString(Buffer.java:599) 
         E  at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:263) 
         E  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
         E  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
         E  at com.someclass.somepath.network.util.CustomHeadersInterceptor.intercept(CustomHeadersInterceptor.java:42) 
         E  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
         E  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
         E  at com.someclass.somepath.network.util.NetworkInterceptor.intercept(NetworkInterceptor.java:23) 
         E  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) 
         E  at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) 
         E  at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:170) 
         E  at okhttp3.RealCall.execute(RealCall.java:60) 
         E  at retrofit2.OkHttpCall.execute(OkHttpCall.java:174) 
         E  at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:89) 
         E  at com.someclass.somepath.service.DownloadCSVTask.doInBackground(CsvPullHandler.java:60) 
         E  at com.someclass.somepath.service.DownloadCSVTask.doInBackground(CsvPullHandler.java:47) 
         E  at android.os.AsyncTask$2.call(AsyncTask.java:288) 
         E  at java.util.concurrent.FutureTask.run(FutureTask.java:237) 

私はここで何か間違ったことをやっていますか?それを行う別の方法がありますか?

答えて

1

AndroidのJavaコードのメモリ容量は、16 Mb(デバイスによって異なります)に制限されています。 したがって、この部分をネイティブのNDKコードに移動する必要があります。このコードでは、デバイスと同じくらい多くのメモリをmalloc()したり、ファイルをディスクに直接保存したりして、ファイル全体をJavaバッファにロードすることなく処理します。 ファイル全体をresponseアレイにコピーする代わりに、URLConnection.getInputStream()またはURLConnection.read()を16Kバイトバイト配列のループで使用してください。 また、BufferedReader.readLine()を使用して、HTTPストリームから直接行ごとに読み取って、データベースを行単位で入力することもできます。

+0

ありがとうございました。接続からストリーミングし、ファイルを保存しました。 – leoOrion

関連する問題