使用Retrofit2下载文件会因错误而停止工作

时间:2017-02-27 18:31:15

标签: java android retrofit retrofit2 okhttp

我正在使用以下代码使用Retrofit下载文件并显示进度。但是在下载了几个百分比,即20%,50%等之后,它会通过提供以下致命异常来停止。可能是什么问题以及如何解决这个问题?

错误:

E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)

              --------- beginning of crash
E/AndroidRuntime: FATAL EXCEPTION: Timer-363
                  Process: com.solutionz.mp3.songs.cloud, PID: 9093
                  DeadSystemException: The system died; earlier logs will point to the root cause
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
W/art: Suspending all threads took: 66.167ms
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 2844)
D/DownloadFile: Progress: 3710576/5061039 >>>> 0.73316485
D/DownloadFile: Progress: 3712624/5061039 >>>> 0.7335695
D/DownloadFile: Progress: 3714672/5061039 >>>> 0.7339742

代码:

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Response;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Streaming;
import retrofit2.http.Url;

    public class DownloadFileWithProgress {
        private static final String TAG = "DownloadFile";
        private String BASE_URL;
        private String fileName, fileTitle;
        private Context context;
        private ProgressNotification mNotification;
        private int notificationId;
        private ProgressResponseBody.ProgressListener progressListener = new ProgressResponseBody.ProgressListener() {
            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                System.out.println(bytesRead);
                System.out.println(contentLength);
                System.out.println(done);
                int percentage = (int) ((100 * bytesRead) / contentLength);
                System.out.format("%d%% done\n", percentage);
                if (!done) {
                    mNotification.progressUpdate(percentage, contentLength, (int) bytesRead, "");
                    mNotification.updateNotification(notificationId);
                } else {
                    //  mNotification.setCompletion();
                    mNotification.getTimer().cancel();
                    mNotification.completed(notificationId);
                }
                AppGlobal.Log("usm_notificationId", "id= " + notificationId);
            }

            @Override
            public void onError(String error) {
                AppGlobal.Log("usm_error", "error= " + error);
                mNotification.getTimer().cancel();
                mNotification.completed(notificationId);
            }
        };

        public DownloadFileWithProgress(Context context, String title, String fileUrl) {
            this.context = context;
            String[] fileStr = fileUrl.split("/");
            this.BASE_URL = fileUrl.substring(0, fileUrl.lastIndexOf("/")) + "/";
            this.fileName = fileStr[fileStr.length - 1];
            this.fileTitle = title;
            this.mNotification = new ProgressNotification(context);
        }

        public void run() {

            OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
                    .addNetworkInterceptor(new Interceptor() {
                        @Override
                        public Response intercept(Chain chain) throws IOException {
                            try {
                                Response originalResponse = chain.proceed(chain.request());
                                return originalResponse.newBuilder()
                                        .body(new ProgressResponseBody(originalResponse.body(), progressListener))
                                        .build();
                            } catch (Exception e) {
                                e.printStackTrace();
                                progressListener.onError(e.getCause() + ": " + e.getMessage());

                            }
                            return chain.proceed(chain.request());
                        }
                    });
            Retrofit.Builder builder = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());
            Retrofit retrofit = builder.client(httpClient.build()).build();
            RetrofitInterface downloadService = retrofit.create(RetrofitInterface.class);
            Call<ResponseBody> call = downloadService.downloadFileByUrl(fileName);
            this.notificationId = this.mNotification.createNotification(fileTitle, "Downloading...");
            call.enqueue(new Callback<ResponseBody>() {

                @Override
                public void onResponse(Call<ResponseBody> call, final retrofit2.Response<ResponseBody> response) {
                    if (response.isSuccessful()) {
                        Log.d(TAG, "Got the body for the file");

                        new AsyncTask<Void, Long, Void>() {
                            @Override
                            protected Void doInBackground(Void... voids) {
                                saveToDisk(response.body());
                                return null;
                            }
                        }.execute();

                    } else {
                        Log.d(TAG, "Connection failed " + response.errorBody());
                    }
                }

                @Override
                public void onFailure(Call<ResponseBody> call, Throwable t) {
                    t.printStackTrace();
                    Log.e(TAG, t.getMessage());
                }
            });
        }

        private void saveToDisk(ResponseBody body) {
            try {

                File mydir = new File(AppGlobal.DIRECTORY_PATH);
                if (!mydir.exists())
                    mydir.mkdir();
                File destinationFile = new File(AppGlobal.DIRECTORY_PATH + "/" + fileName);

                InputStream is = null;
                OutputStream os = null;

                try {
                    Log.d(TAG, "File Size=" + body.contentLength());

                    is = body.byteStream();
                    os = new FileOutputStream(destinationFile);

                    byte data[] = new byte[4096];
                    int count;
                    int progress = 0;
                    while ((count = is.read(data)) != -1) {
                        os.write(data, 0, count);
                        progress += count;
                        Log.d(TAG, "Progress: " + progress + "/" + body.contentLength() + " >>>> " + (float) progress / body.contentLength());
                    }

                    os.flush();

                    Log.d(TAG, "File saved successfully!");
                    return;
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "Failed to save the file!");
                    return;
                } finally {
                    if (is != null) is.close();
                    if (os != null) os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                Log.d(TAG, "Failed to save the file!");
                return;
            }
        }

        public interface RetrofitInterface {
            @Streaming
            @GET
            Call<ResponseBody> downloadFileByUrl(@Url String fileUrl);
        }

    }

ProgressResponseBody:

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;
import okio.ForwardingSource;
import okio.Okio;
import okio.Source;


public class ProgressResponseBody extends ResponseBody {

    private final ResponseBody responseBody;
    private final ProgressListener progressListener;
    private BufferedSource bufferedSource;

    public ProgressResponseBody(ResponseBody responseBody, ProgressListener progressListener) {
        this.responseBody = responseBody;
        this.progressListener = progressListener;
    }

    @Override
    public MediaType contentType() {
        //return MediaType.parse("image/*");
        return responseBody.contentType();
    }

    @Override
    public long contentLength() {
        return responseBody.contentLength();
    }

    @Override
    public BufferedSource source() {
        if (bufferedSource == null) {
            bufferedSource = Okio.buffer(source(responseBody.source()));
        }
        return bufferedSource;
    }

    private Source source(Source source) {
        return new ForwardingSource(source) {
            long totalBytesRead = 0L;

            @Override
            public long read(Buffer sink, long byteCount) throws IOException {
                long bytesRead = super.read(sink, byteCount);
                // read() returns the number of bytes read, or -1 if this source is exhausted.
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1);
                return bytesRead;
            }
        };
    }

    public interface ProgressListener {
        void update(long bytesRead, long contentLength, boolean done);
        void onError(String error);
    }
}

0 个答案:

没有答案