Retrofit的文件上传和进度提示

1.写一个上传监听的接口:

/**
 * Created by Zzm丶Fiona on 2017/7/31.
 */

public interface RetrofitProgressUploadListener {
    /**
     *
     * @param bytesWriting 已经写的字节数
     * @param totalBytes   文件的总字节数
     */
    void onProgress(long bytesWriting, long totalBytes);
}

2.重新写一个类继承于RequesBody:

package zzm.zzmotherthingsshouldknowfortheinterview.upload_progress;

import android.support.annotation.Nullable;

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;

/**
 * Created by Zzm丶Fiona on 2017/7/31.
 */

public class ProgressRequestBody extends RequestBody {
    private final RetrofitProgressUploadListener retrofitProgressUploadListener;
    private final RequestBody requestBody;
    private BufferedSink bufferedSink;

    public ProgressRequestBody(RetrofitProgressUploadListener retrofitProgressUploadListener, RequestBody requestBody) {
        this.retrofitProgressUploadListener = retrofitProgressUploadListener;
        this.requestBody = requestBody;
    }

    @Nullable
    @Override
    public MediaType contentType() {
        return requestBody.contentType();
    }

    @Override
    public long contentLength() throws IOException {
        return requestBody.contentLength();
    }

    //关键方法
    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        if (null == bufferedSink) bufferedSink = Okio.buffer(sink(sink));
        requestBody.writeTo(bufferedSink);
        //必须调用flush,否则最后一部分数据可能不会被写入
        bufferedSink.flush();
    }

    private Sink sink(Sink sink) {
        return new ForwardingSink(sink) {
            long bytesWriting = 0l;
            long contentLength = 0l;

            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                if (0 == contentLength) contentLength = contentLength();
                bytesWriting += byteCount;
                       //调用接口,把上传文件的进度传过去
                retrofitProgressUploadListener.onProgress(bytesWriting, contentLength);
            }
        };
    }
}

3.封装的方法,返回ProgressRequestBody:

package zzm.zzmotherthingsshouldknowfortheinterview.utils;

import android.os.Handler;
import okhttp3.RequestBody;
import zzm.zzmotherthingsshouldknowfortheinterview.upload_progress.ProgressRequestBody;
import zzm.zzmotherthingsshouldknowfortheinterview.upload_progress.RetrofitProgressUploadListener;
import zzm.zzmotherthingsshouldknowfortheinterview.upload_progress.UploadProgressBean;

/**
 * Created by Zzm丶Fiona on 2017/7/31.
 */

public class RetrofitUploadProgressUtil {
//handler把数据传送到主线程中去处理,展示
    public static ProgressRequestBody getProgressRequesBody(RequestBody requestBody, final Handler handler) {
        return new ProgressRequestBody(new RetrofitProgressUploadListener() {
            UploadProgressBean uploadProgressBean = new UploadProgressBean();

            @Override
            public void onProgress(long bytesWriting, long totalBytes) {
                if (null == uploadProgressBean) uploadProgressBean = new UploadProgressBean();
                uploadProgressBean.setBytesWriting(bytesWriting);
                uploadProgressBean.setTotalBytes(totalBytes);
                handler.sendMessage(handler.obtainMessage(2, uploadProgressBean));
            }
        }, requestBody);
    }
}

4.把自己的写的类继承于RequesBody的ProgressRequestBody传进上传的表单中即可:

/**
 * Created by Zzm丶Fiona on 2017/7/30.
 */

public class UploadThingsByRetrofitActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        RequestBody requestBody = RequestBody.create(MediaType.parse("multipart/form-data"),你的上传文件-file);
        ProgressRequestBody progressRequestBody = RetrofitUploadProgressUtil.getProgressRequesBody(requestBody, new Handler() {
            @Override
            public void handleMessage(Message msg) {
           //进度的展示:
                super.handleMessage(msg);
                Log.i("zzmzzm", "已读的字节数:  " + ((UploadProgressBean) msg.obj).getTotalBytes());
                Log.i("zzmzzm", "上传的文件的字节总数:  " + ((UploadProgressBean) msg.obj).getTotalBytes());
            }
        });
        UploadThingsByRetrofitInterface uploadThingsByRetrofitInterface = getUploadThingsInterface();
        Call<ResponseBody> upload = uploadThingsByRetrofitInterface.uploadThings(MultipartBody.Part.createFormData(你的key,文件名,progressRequestBody));
        upload.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
 //求情成功的返回
                try {
                    Log.i("zzmzzm", response.body().string());
                } catch (IOException e) {
                    Log.i("zzmzzm", e.toString());
                }
            }
 //求情失败的返回
            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.i("zzmzzm", t.toString());
            }
        });

    }

    private UploadThingsByRetrofitInterface getUploadThingsInterface() {
        return new Retrofit.Builder()
                .baseUrl("地址")
                .build()
                .create(UploadThingsByRetrofitInterface.class);
    }
}

其中的注解接口:

/**
 * Created by Zzm丶Fiona on 2017/7/30.
 */

public interface UploadThingsByRetrofitInterface {
    @Multipart
    @POST
    Call<ResponseBody> uploadThings(@Part MultipartBody.Part uplodThings);

}

补充说明:

MediaType.parse(String contentType)中参数contentType常见的有:
        text/html : HTML格式
        text/plain :纯文本格式
        text/xml :  XML格式
        text/x-markdown: markdown文档
        image/gif :gif图片格式
        image/jpeg :jpg图片格式
        image/png:png图片格式

        以application开头的媒体格式类型:
        application/xhtml+xml :XHTML格式
        application/xml     : XML数据格式
        application/atom+xml  :Atom XML聚合格式
        application/json    : JSON数据格式
        application/pdf       :pdf格式
        application/msword  : Word文档格式
        application/octet-stream : 二进制流数据(如常见的文件下载)
        application/x-www-form-urlencoded : <form encType=””>中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)

        另外一种常见的媒体格式是上传文件之时使用的:
        multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式

        另外的可以参考:http://www.w3school.com.cn/media/media_mimeref.asp

猜你喜欢

转载自my.oschina.net/u/2987490/blog/1492353