android 积累okhttp3与retrofit2常见的使用方法

1.上传多张图片与文字参数

 OkHttpClient httpClient = new OkHttpClient();
                        // mImgUrls为存放图片的url集合
                        MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
                        if (Bimp.tempSelectBitmap != null) {
                            for (int i = 0; i < Bimp.tempSelectBitmap.size(); i++) {
                                ImageItem imageItem = Bimp.tempSelectBitmap.get(i);
                                File file = new File(imageItem.getImagePath());
                                if (file != null && file.exists()) {
                                    builder.addFormDataPart("pic" + i, file.getName(), RequestBody.create(MediaType.parse("image/png"), file));
                                }
                            }
                        }
                        builder.addFormDataPart("classid", classId);
                        builder.addFormDataPart("notice_content", text);
                        builder.addFormDataPart("userno", userno);
                        builder.addFormDataPart("time", "" + time);
                        builder.addFormDataPart("sign", sign);
                        MultipartBody requestBody = builder.build();
                        //构建请求
                        Request request = new Request.Builder()
                                .url(Contacts.FABUDONGTAI)//地址
                                .post(requestBody)//添加请求体
                                .build();

                        httpClient.newCall(request).enqueue(new Callback() {
                            @Override
                            public void onFailure(Call call, IOException e) {
                                Log.i("上传照片", "失败::" + e.getLocalizedMessage());
                            }

                            @Override
                            public void onResponse(Call call, Response response) throws IOException {
                                Log.i("上传照片", "成功::" + response.body().string());
                            }
                        });

2.监听上传进度

package utils;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Administrator on 2017/1/19.
 * func:上传进度的类
 */

public class FileUploadProgress implements Parcelable {


    private long bytesWritten;//当前已上传的大小
    private long contentLength;//需要上传的文件的总大小
    private boolean done;//是否上传完成


    public FileUploadProgress(long bytesWritten, long contentLength, boolean done) {
        this.bytesWritten = bytesWritten;
        this.contentLength = contentLength;
        this.done = done;
    }

    public FileUploadProgress() {
    }

    public long getBytesWritten() {
        return bytesWritten;
    }

    public void setBytesWritten(long bytesWritten) {
        this.bytesWritten = bytesWritten;
    }

    public long getContentLength() {
        return contentLength;
    }

    public void setContentLength(long contentLength) {
        this.contentLength = contentLength;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }

    @Override
    public String toString() {
        return "FileUploadProgress{" +
                "bytesWritten=" + bytesWritten +
                ", contentLength=" + contentLength +
                ", done=" + done +
                '}';
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(this.bytesWritten);
        dest.writeLong(this.contentLength);
        dest.writeByte(this.done ? (byte) 1 : (byte) 0);
    }

    protected FileUploadProgress(Parcel in) {
        this.bytesWritten = in.readLong();
        this.contentLength = in.readLong();
        this.done = in.readByte() != 0;
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        @Override
        public FileUploadProgress createFromParcel(Parcel source) {
            return new FileUploadProgress(source);
        }

        @Override
        public FileUploadProgress[] newArray(int size) {
            return new FileUploadProgress[size];
        }
    };
}

 

package utils;

/**
 * Created by hcy on 2017/1/19.
 */

public interface OkhttpListener {


    /**
     * 上传进度的监听
     */
    public interface ProgressRequestListener {
        void onRequestProgress(FileUploadProgress  progress);
    }
}

 

 

package utils;

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 hcy on 2017/1/19.
 */

public class ProgressRequestBody extends RequestBody {
    //实际的待包装请求体
    private final RequestBody requestBody;
    //进度回调接口
    private final OkhttpListener.ProgressRequestListener progressListener;
    //包装完成的BufferedSink
    private BufferedSink bufferedSink;

    /**
     * 构造函数,赋值
     *
     * @param requestBody      待包装的请求体
     * @param progressListener 回调接口
     */
    public ProgressRequestBody(RequestBody requestBody, OkhttpListener.ProgressRequestListener progressListener) {
        this.requestBody = requestBody;
        this.progressListener = progressListener;
    }

    /**
     * 重写调用实际的响应体的contentType
     *
     * @return MediaType
     */
    @Override
    public MediaType contentType() {
        return requestBody.contentType();
    }

    /**
     * 重写调用实际的响应体的contentLength
     *
     * @return contentLength
     * @throws IOException 异常
     */
    @Override
    public long contentLength() throws IOException {
        return requestBody.contentLength();
    }

    /**
     * 重写进行写入
     *
     * @param sink BufferedSink
     * @throws IOException 异常
     */
    @Override
    public void writeTo(BufferedSink sink) throws IOException {
        if (bufferedSink == null) {
            //包装
            bufferedSink = Okio.buffer(sink(sink));
        }
        //写入
        requestBody.writeTo(bufferedSink);
        //必须调用flush,否则最后一部分数据可能不会被写入
        bufferedSink.flush();

    }

    /**
     * 写入,回调进度接口
     *
     * @param sink Sink
     * @return Sink
     */
    private Sink sink(Sink sink) {
        return new ForwardingSink(sink) {
            //当前写入字节数
            long bytesWritten = 0L;
            //总字节长度,避免多次调用contentLength()方法
            long contentLength = 0L;

            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                if (contentLength == 0) {
                    //获得contentLength的值,后续不再调用
                    contentLength = contentLength();
                }
                //增加当前写入的字节数
                bytesWritten += byteCount;
                //回调
                progressListener.onRequestProgress(new FileUploadProgress(bytesWritten, contentLength, bytesWritten == contentLength));
            }
        };
    }
}

 

   Request request = new Request.Builder()
                                .url(Contacts.FABUDONGTAI)//地址
                                .post(new ProgressRequestBody(requestBody, new OkhttpListener.ProgressRequestListener() {
                                    @Override
                                    public void onRequestProgress(FileUploadProgress progress) {
                                        Log.i("上传照片进度::", progress.toString());
                                        if (myHandler != null) {
                                            Message msg = Message.obtain();
                                            msg.what = 1;
                                            msg.obj = progress;
                                            myHandler.sendMessage(msg);
                                        }
                                    }
                                }))//添加请求体
                                .build();

 

下载文件并监听下载进度

思路:最近将项目都改成了mvp+retrofit+rxjava的工程了,感觉确实在代码的整洁方面进步不小。retrofit2其实是基本okhttp3的,和上传一样只需要在okhttpclient设置拦截器就好

 

1.写下载进度的bean类:包含三方面:当前下载进度 ,文件大小,是否完成

package wytnewhttp;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by hcy on 2017/3/10.
 */

public class FileDownLoadProgress implements Parcelable {
    private long bytesDown;//当前已下载的大小
    private long contentLength;//需要下载的文件的总大小
    private boolean done;//是否下载完成

    public FileDownLoadProgress() {
    }



    public FileDownLoadProgress(long bytesDown, long contentLength, boolean done) {
        this.bytesDown = bytesDown;
        this.contentLength = contentLength;
        this.done = done;
    }

    public long getBytesDown() {
        return bytesDown;
    }

    public void setBytesDown(long bytesDown) {
        this.bytesDown = bytesDown;
    }

    public long getContentLength() {
        return contentLength;
    }

    public void setContentLength(long contentLength) {
        this.contentLength = contentLength;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeLong(this.bytesDown);
        dest.writeLong(this.contentLength);
        dest.writeByte(this.done ? (byte) 1 : (byte) 0);
    }

    protected FileDownLoadProgress(Parcel in) {
        this.bytesDown = in.readLong();
        this.contentLength = in.readLong();
        this.done = in.readByte() != 0;
    }

    public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
        @Override
        public FileDownLoadProgress createFromParcel(Parcel source) {
            return new FileDownLoadProgress(source);
        }

        @Override
        public FileDownLoadProgress[] newArray(int size) {
            return new FileDownLoadProgress[size];
        }
    };
}

 

2.回调进度的接口

    /**
     * 下载进度的监听
     */


    public interface ProgressResponseListener{
        void onResponseProgress(FileDownLoadProgress progress);
    }

 

3.重写拦截器

package wytnewhttp;

import java.io.IOException;

import okhttp3.Interceptor;
import okhttp3.Response;

/**
 * Created by hcy on 2017/3/10.
 * func:监听下载进度的拦截器
 *
 *
 */

public class DownloadProgressInterceptor implements Interceptor {

    private OkhttpListener.ProgressResponseListener listener;

    public DownloadProgressInterceptor(OkhttpListener.ProgressResponseListener listener) {
        this.listener = listener;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Response originalResponse = chain.proceed(chain.request());

        return originalResponse.newBuilder()
                .body(new ProgressResponseBody(originalResponse.body(), listener))
                .build();
    }
}

 

package wytnewhttp;

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;

/**
 * Created by hcy on 2017/3/10.
 * func:下载进度监听
 */

public class ProgressResponseBody extends ResponseBody{
    private  final  ResponseBody responseBody;

    private final OkhttpListener.ProgressResponseListener  progressResponseListener;

    private BufferedSource  bufferedSource;


    public ProgressResponseBody(ResponseBody responseBody, OkhttpListener.ProgressResponseListener progressResponseListener) {
        this.responseBody = responseBody;
        this.progressResponseListener = progressResponseListener;
    }






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

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

    @Override
    public BufferedSource source() {
        if (null == bufferedSource){
            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);
                totalBytesRead += bytesRead != -1 ? bytesRead : 0;
                progressResponseListener.onResponseProgress(new FileDownLoadProgress(totalBytesRead, responseBody.contentLength(), bytesRead == -1));
                return bytesRead;
            }
        };
    }
}

 

 

 

 

 

 

 

 

4给retrofit设置okhttp3(设置拦截器)

  public static  T downLoadFiles(final Class serviceClass, String endpoint, OkhttpListener.ProgressResponseListener responseListener) {
        OkHttpClient client = new OkHttpClient.Builder()
                .addInterceptor(new DownloadProgressInterceptor(responseListener))
                .retryOnConnectionFailure(true)
                .connectTimeout(15, TimeUnit.SECONDS)
                .build();

        Retrofit adapter = new Retrofit.Builder()
                .baseUrl(endpoint)
                .client(client)
                .addConverterFactory(ScalarsConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .build();

        return adapter.create(serviceClass);


    }

5,请求

   /**
     * 下载大文件
     */


    public interface DownLoadFile {
        @Streaming  //大文件
        @GET
        Observable downFile(@Url String fileUrl);
    }

 

 /**
     * 
     * @param dirName  文件存放目录
     * @param listener  进度监听
     * @param fileType  文件后罪名
     * @return   返回rxjava 回调
     */


    public Observable downFile(final String dirName, OkhttpListener.ProgressResponseListener listener, final String fileType) {


        return ServiceFactory.downLoadFiles(DownLoadFile.class, Contacts.AIYIXUE_TEACHER_URL, listener)
                .downFile(url)
                .subscribeOn(Schedulers.io())
                .map(new Func1() {
                    @Override
                    public File call(ResponseBody responseBody) {
                        return ProjectUtils.writeResponseBodyToDisk(responseBody,dirName, ProjectUtils.md5Encode(url)+"."+fileType, context);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread());


    }

 

/**
     * 下载文件的返回
     * @param body      下载文件的返回体
     * @param fileName  文件名: 001.ppt
     * @param context   上下文
     * @return           是否写入成功
     */

    public  static  File writeResponseBodyToDisk(ResponseBody body,String dirName,String  fileName,Context context) {
        try {

            File file = new File(getDiskCacheDir2(context,dirName)+File.separator+fileName);

            InputStream inputStream = null;
            OutputStream outputStream = null;

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



                inputStream = body.byteStream();
                outputStream = new FileOutputStream(file);

                while (true) {
                    int read = inputStream.read(fileReader);

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

                    outputStream.write(fileReader, 0, read);

         
              
                }

                outputStream.flush();

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

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

 

6测试

 new WytHttpUtils(MainActivity.this,"uploadfile/ppt/2016112120083.pptx").downFile("ppt", new OkhttpListener.ProgressResponseListener() {
            @Override
            public void onResponseProgress(FileDownLoadProgress progress) {

                Logger.t("文件下载进度").d(progress.getBytesDown()+"/"+progress.getContentLength()+"/"+progress.isDone());
            }
        },"pptx").subscribe(new Action1() {
            @Override
            public void call(File file) {
                
            }
        });


android 积累okhttp3与retrofit2常见的使用方法_第1张图片

对于一些比较奇怪的接口

{{api_url}}{{version}}family-box/topics/item/{{topic_id}}?access_token={{access_token_parent1}}

   //获取专题详情数据
    @GET("family-box/topics/item/{topic_id}")
    Flowable> requestProjectDetails(@Path("topic_id") int topic_id, @Query("access_token") String access_token);

注意啊:

Expected a string but was BEGIN_OBJECT 

当我请求接口的时候,我只想把服务器返回的字符串打印出来,但出现了Expected a string but was BEGIN_OBJECT这个bug

明明我retrofit2加了

addConverterFactory(ScalarsConverterFactory.create())

但还是报错,这里注意下retrofit2初始化的顺序

retrofit = new Retrofit.Builder()
        .client(client)
        .baseUrl(BASE_URL)
        .addConverterFactory(ScalarsConverterFactory.create())
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build();

如果颠倒了就会出现这个问题。

 

 

 


 

你可能感兴趣的:(Android)