Rx系列<第三十三篇>:Retrofit2之上传和下载

本文是RxJava<第三十二篇>:RxJava+Retrofit+OkHttp+MVP的扩展,着重分析单文件上传单文件下载

本章重点想展示一下上传和下载的进度是如何实现的,后续会推出一个完整封装:RxJava+RxBinding+Retrofit+OkHttp+MVP+Dagger2来实现get请求、post请求、单文件上传、单文件下载、多文件上传、多文件下载

(1)Retrofit+OkHttp实现文件上传

第一步 自定义带进度条文件体

/**
 * 带进度条的RequestBody封装
 */
public class ProgressRequestBody extends RequestBody {

    private File mFile;
    private String mMediaType;//文件类型
    private UploadResultListener mListener;//上传结果回调监听
    private int bufferSize = 1024;//缓存大小

    public ProgressRequestBody(final File file, String mediaType, final UploadResultListener listener) {
        mFile = file;
        mMediaType = mediaType;
        mListener = listener;
    }

    public ProgressRequestBody(final File file, String mediaType, int eachBufferSize, final UploadResultListener listener) {
        mFile = file;
        mMediaType = mediaType;
        bufferSize = eachBufferSize;
        mListener = listener;
    }

    @Override
    public MediaType contentType() {
        return MediaType.parse(mMediaType);
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        long fileLength = mFile.length();
        byte[] buffer = new byte[bufferSize];
        FileInputStream in = new FileInputStream(mFile);
        long uploaded = 0;
        try {
            int read;
            Handler handler = new Handler(Looper.getMainLooper());
            while ((read = in.read(buffer)) != -1) {
                handler.post(new ProgressUpdate(uploaded, fileLength));
                uploaded += read;
                sink.write(buffer, 0, read);
            }
        } finally {
            in.close();
        }
    }

    private class ProgressUpdate implements Runnable {
        private long mUploaded;
        private long mTotal;
        public ProgressUpdate(long uploaded, long total) {
            mUploaded = uploaded;
            mTotal = total;
        }

        @Override public void run() {
            mListener.onProgressChange((int) (100 * mUploaded / mTotal));
        }
    }
}

第二步 上传文件结果回调监听

/**
 * 上传文件监听接口
 */
public interface UploadResultListener {

    void onProgressChange(int percent);//进度变化回调
    void onFinish();//上传完成回调
    void onInterrupted();//上传中断回调

}

第三步 retrofit接口定义

    public interface FileAPIService {
    
            //文件上传
            @Multipart
            @POST("FileUpload/FileUploadServlet")
            Call uploadFlie(@Part MultipartBody.Part file);
    
    
    }

第四步 实现

    UploadResultListener uploadResultListener = new UploadResultListener() {
        @Override
        public void onProgressChange(int percent) {
            //进度条更新
            Log.d("aaa", "percent:"+percent + "%");
            ((TextView)findViewById(R.id.result_text1)).setText("当前上传进度:" + percent + "%");
        }

        @Override
        public void onFinish() {
            //上传完成
            ((TextView)findViewById(R.id.result_text1)).setText("上传完成");
        }

        @Override
        public void onInterrupted() {
            //上传中断
            ((TextView)findViewById(R.id.result_text1)).setText("上传失败");
        }
    };

    findViewById(R.id.bt_1).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //单文件上传

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("http://192.168.0.105:8080")
                    .build();
            FileAPIService fileAPIService = retrofit.create(FileAPIService.class);

            File file = new File(Environment.getExternalStorageDirectory() + File.separator + "myapk.apk");

            // 创建 RequestBody
            ProgressRequestBody progressRequestBody = new ProgressRequestBody(file, "application/otcet-stream", uploadResultListener);

            //新建Part
            MultipartBody.Part body = MultipartBody.Part.createFormData("myapk", file.getName(), progressRequestBody);

            Call call = fileAPIService.uploadFlie(body);
            call.enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {
                    if(response != null && response.isSuccessful()){
                        uploadResultListener.onFinish();
                    }else{
                        uploadResultListener.onInterrupted();
                    }
                }

                @Override
                public void onFailure(Call call, Throwable t) {
                    uploadResultListener.onInterrupted();
                }
            });

        }
    });

总体四步就可以实现文件的上传,其中第一步是带进度上传文件的核心。

效果如下:


图片.png
图片.png
(2)Retrofit+OkHttp实现文件下载

第一步 下载结果回调监听

public interface DownloadResultListener {

    void onProgressChange(int percent);//进度变化回调
    void onFinish();//下载完成回调
    void onInterrupted();//下载中断回调

}

第二步 retrofit接口定义

public interface FileAPIService {


    @Streaming
    @GET("/1.apk")
    Call downloadFile();
}

第三步 实现

    DownloadResultListener downloadResultListener = new DownloadResultListener() {
        @Override
        public void onProgressChange(int percent) {
            //进度条更新
            ((TextView)findViewById(R.id.result_text2)).setText("当前下载进度:" + percent+ "%");
        }

        @Override
        public void onFinish() {
            //上传完成
            ((TextView)findViewById(R.id.result_text2)).setText("下载完成");
        }

        @Override
        public void onInterrupted() {
            //上传中断
            ((TextView)findViewById(R.id.result_text2)).setText("下载失败");
        }
    };

    findViewById(R.id.bt_2).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //文件下载
            Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.0.105:8080").build();
            FileAPIService searchFileAPIService = retrofit.create(FileAPIService.class);
            Call call = searchFileAPIService.downloadFile();
            call.enqueue(new Callback() {
                @Override
                public void onResponse(Call call, Response response) {
                    if(response != null && response.isSuccessful()){
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                boolean writtenToDisk = writeResponseBodyToDisk(response.body(), downloadResultListener);
                                downloadResultListener.onFinish();
                            }
                        }).start();

                    }
                }

                @Override
                public void onFailure(Call call, Throwable t) {
                    downloadResultListener.onInterrupted();
                }
            });
        }
    });


//写入到磁盘根目录
private boolean writeResponseBodyToDisk(ResponseBody body, DownloadResultListener downloadResultListener) {
    try {
        File futureStudioIconFile = new File(Environment.getExternalStorageDirectory() + File.separator + "mydownloadapk.apk");
        InputStream inputStream = null;
        OutputStream outputStream = null;

        try {
            byte[] fileReader = new byte[4096];

            int fileSize = (int) body.contentLength();
            int fileSizeDownloaded = 0;

            inputStream = body.byteStream();
            outputStream = new FileOutputStream(futureStudioIconFile);
            while (true) {
                int read = inputStream.read(fileReader);

                if (read == -1) {
                    break;
                }

                outputStream.write(fileReader, 0, read);

                fileSizeDownloaded += read;


                final int finalFileSizeDownloaded = fileSizeDownloaded;
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        downloadResultListener.onProgressChange(100 * finalFileSizeDownloaded / fileSize);
                    }
                });
            }

            outputStream.flush();

            return true;
        } catch (IOException e) {
            return false;
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }

            if (outputStream != null) {
                outputStream.close();
            }
        }
    } catch (IOException e) {
        return false;
    }
}

效果如下:

图片.png
图片.png

你可能感兴趣的:(Rx系列<第三十三篇>:Retrofit2之上传和下载)