下载一个非常大的文件会无声地死掉

时间:2018-04-19 14:17:26

标签: android android-asynctask download retrofit2 intentservice

所以我试图通过Retrofit2下载一个非常大的文件。文件最大可达5-10 GB。我从一个活动/片段(我已尝试过AsyncTask和IntentService)启动一个异步结构,然后将文件流式传输并将字节写入内部存储器上的文件。我在每个缓冲区读取后发布文件写入的进度。

最大150 MB左右的文件工作正常,但是当我尝试5 GB文件时,流在大约1 GB后无声地消失。我没有看到日志或logcat,也没有抛出异常。

有没有人知道发生了什么,或者我写错了什么?

public interface IFileshareDownload {
    @Streaming
    @GET("File/Download/{guid}")
    Call<ResponseBody> downloadFileByGuid(@Path("guid") String guid);
}

public class FileshareDownloadService extends IntentService {
    private static final String TAG = "[FileDownloadService]";
    private static final String PATH = "/ftp/";
    private static final int FILE_CHUNK_SIZE = 2 * 1024 * 1024; //2MB buffer

    private String mFilename;
    private String mFileshareDirectory;
    private String mAbsoluteFilePath;

    private String mBaseUrl;
    private String mGuid;
    private Long mFileSize;
    private Retrofit mRetrofit;
    private IFileshareDownload mDownloader;
    private ResultReceiver mReceiver;

    public FileshareDownloadService() {
        super("FileshareDownload");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        this.mBaseUrl = intent.getStringExtra("baseUrl");
        this.mGuid = intent.getStringExtra("guid");
        this.mFilename = intent.getStringExtra("fileName");
        this.mFileSize = intent.getLongExtra("fileSize", -1);
        this.mFileshareDirectory = getApplicationContext().getFilesDir().getAbsolutePath() + PATH;
        this.mAbsoluteFilePath = mFileshareDirectory + mFilename;

        this.mRetrofit = new Retrofit.Builder()
                .baseUrl(mBaseUrl)
                .callbackExecutor(Executors.newSingleThreadExecutor())
                .build();

        this.mDownloader = mRetrofit.create(IFileshareDownload.class);
        this.mReceiver = intent.getParcelableExtra("listener");

        downloadFile();
    }

    public void downloadFile() {
        Call<ResponseBody> call = mDownloader.downloadFileByGuid(mGuid);
        try {
            Response<ResponseBody> response = call.execute();
            if(response.isSuccessful()) {
                File file = new File(mAbsoluteFilePath);
                file.createNewFile();

                try(FileOutputStream fos = new FileOutputStream(file)) {
                    InputStream is = response.body().byteStream();
                    setUpdateProgress(SHOW_PROGRESS);
                    int count = 0;
                    long bytesRead = 0;

                    byte[] buffer = new byte[FILE_CHUNK_SIZE];
                    try {
                        while ((count = is.read(buffer)) != -1) {

                            fos.write(buffer, 0, count);
                            fos.flush();
                            bytesRead += count;

                            int progress = getPercent(bytesRead, mFileSize);
                            Log.d(TAG, String.format("Read %d out of %d bytes.", bytesRead, mFileSize));
                            setUpdateProgress(UPDATE_PROGRESS, progress);
                        }
                    } catch (Throwable t)
                    {
                        Log.e(TAG, "What happened?", t);
                    }
                }
                setUpdateProgress(HIDE_PROGRESS);
            } else {
                setUpdateProgress(HIDE_PROGRESS);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

1 个答案:

答案 0 :(得分:0)

这是一个关于下载文件的精彩教程。它可能会提到你需要的东西:

https://futurestud.io/tutorials/retrofit-2-how-to-download-files-from-server

如果没有,请查看@Multipart注释以及@Part。我不确定你是否可以在GET中使用它,但由于你还没有答案,我会在这里发布,这样你就可以随意拍摄。

这是我的项目中的一个示例,我们在其中创建了一个多部分主体来上传图像。我知道你想要一个GET,但这个例子仍然是相关的:

// Setting up the multipart file
File newAvatar = new File(getRealPathFromURI(avatarUri)); // the new avatar
RequestBody filePart = RequestBody.create(MediaType.parse(getActivity().getContentResolver().getType(avatarUri)), newAvatar);

您的请求(本例中的POST)应该是这样的:

@Multipart
@POST("/api/v1/me/account/upload-cover") // upload avatar
Call<ResponseChangeAvatar> sendChangeAvatarRequest(@Part MultipartBody.Part file, @Header("Authorization") String token);

改装文档(只搜索multipart):

http://square.github.io/retrofit/

一个教程,他在其中创建了一个多部分正文以将文件上传到服务器:

https://futurestud.io/tutorials/retrofit-2-how-to-upload-files-to-server

希望这会有所帮助。如果您找到了解决方案,请告诉我。