OkHttp

作者: luoqiang108 | 来源:发表于2018-08-06 14:01 被阅读20次

    1.OkHttp什么是什么?

    OkHttp是一款优秀的HTTP框架,它支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZIP压缩,支持响应缓存避免重复的网络请求,支持使用连接池来降低响应延迟问题。OkHttp官网

    2.怎么使用?

    1.在app的build.gradle中添加OkHttp的依赖

    compile 'com.squareup.okhttp3:okhttp:3.11.0'
    

    2.AndroidManifest.xml中加入网络权限

     <uses-permission android:name="android.permission.INTERNET"/>
    

    3.具体使用步骤

    步骤1:拿到OkHttpClient对象
    步骤2:构造Request
    步骤3:将Request封装为Call
    步骤4:执行Call
    import android.os.Environment;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.Cookie;
    import okhttp3.CookieJar;
    import okhttp3.FormBody;
    import okhttp3.HttpUrl;
    import okhttp3.MediaType;
    import okhttp3.MultipartBody;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            /*解决session过期问题*/
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .cookieJar(new CookieJar() {
                        private Map<String, List<Cookie>> cookieStore = new HashMap<>();
                        @Override
                        public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
                            cookieStore.put(url.host(), cookies);
                        }
                        @Override
                        public List<Cookie> loadForRequest(HttpUrl url) {
                            List<Cookie> cookies = cookieStore.get(url.host());
                            return cookies != null ? cookies : new ArrayList<Cookie>();
                        }
                    }).build();
    
        }
    
        //1.拿到OkHttpClient对象
        OkHttpClient okHttpClient = new OkHttpClient();
        public void doGet(View view) throws IOException {
            //2.构造Request
            Request.Builder builder = new Request.Builder();
            Request request = builder.get().url("https://www.imooc.com/").build();
            executeRequest(request);
        }
    
        private void executeRequest(Request request) {
            //3.将Request封装为Call
            Call call = okHttpClient.newCall(request);
            //4.执行Call
            //同步执行请求,发送请求后,就会进入阻塞状态,直到收到响应,
            //所以必须在子线程中执行,否则或抛出android.os.NetworkOnMainThreadException异常
            //Response response = call.execute();
            //异步执行请求,请求放到线程池队列中等待执行,执行完成后在Callback回调中进行响应数据的处理,注意回调是在子线程
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
                @Override
                public void onResponse(Call call, final Response response) throws IOException {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //更新UI操作
                            String responseString = null;
                            try {
                                responseString = response.body().string();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                            Log.d("onResponse",responseString);
                        }
                    });
                }
            });
        }
    
        //要提交post请求的url,这里是瞎写的,不可用
        private String mBaseUrl = "www.post.com";
        public void doPost(View view){
            //2.构造Request
            //2.1构造requestBody
            FormBody.Builder formBodeBuilder = new FormBody.Builder();
            RequestBody requestBody = formBodeBuilder.add("username", "test")
                    .add("password", "test")
                    .build();
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(mBaseUrl + "login").post(requestBody).build();
            executeRequest(request);
        }
    
        //post提交字符串
        public void doPostString(View view){
            RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;chaset=utf-8"), "testString");
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(mBaseUrl + "postString").post(requestBody).build();
            executeRequest(request);
        }
    
        //post提交文件
        //写文件要添加WRITE_EXTERNAL_STORAGE权限
        public void doPostFile(View view){
            File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
            if (!file.exists()){
                Log.e("mTAG",file.getAbsolutePath()+"not exist!");
                return;
            }
            //不知道数据的具体MediaType,可以搜索mime type去查找
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(mBaseUrl + "postString").post(requestBody).build();
            executeRequest(request);
        }
    
        //post上传文件
        public void doUpload(View view){
            File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
            if (!file.exists()){
                Log.e("mTAG",file.getAbsolutePath()+"not exist!");
                return;
            }
            MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
            RequestBody requestBody = multipartBodyBuilder.setType(MultipartBody.FORM)
                    .addFormDataPart("username", "test")
                    .addFormDataPart("password", "test")
                    //addFormDataPart(服务器表单域key,服务器图片名称,File的RequestBody)
                    .addFormDataPart("mPhoto", "upload.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), file))
                    .build();
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(mBaseUrl + "uploadInfo").post(requestBody).build();
            executeRequest(request);
        }
    
        //post下载文件
        public void doDownload(View view){
            //2.构造Request
            Request.Builder builder = new Request.Builder();
            Request request = builder.get().url(mBaseUrl+"files/test.jpg").build();
            //3.将Request封装为Call
            Call call = okHttpClient.newCall(request);
            //4.执行Call
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
                @Override
                public void onResponse(Call call, final Response response) throws IOException {
                    InputStream is = response.body().byteStream();
                    int len = 0;
                    File file = new File(Environment.getExternalStorageDirectory(),"test1.jpg");
                    FileOutputStream fos = new FileOutputStream(file);
                    byte[] buf = new byte[128];
                    while ((len = is.read(buf))!=-1){
                        fos.write(buf,0,len);
                    }
                    fos.flush();
                    fos.close();
                    is.close();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //更新UI操作
                            /*对于大图片可以先将图片下载到本地,
                            利用BitmapFactory.Options将图片进行改造压缩。
                            inJustDecodeBounds
                            inSampleSize
                            然后再显示
                            */
                        }
                    });
                }
            });
        }
    
    }
    

    2.追踪下载和上传文件进度

    2.1 追踪下载进度的方法(在写文件方面做文章)

        //post下载文件,在上面代码doDownload方法的基础上做修改
        public void doDownload(View view){
            //2.构造Request
            Request.Builder builder = new Request.Builder();
            Request request = builder.get().url(mBaseUrl+"files/test.jpg").build();
            //3.将Request封装为Call
            Call call = okHttpClient.newCall(request);
            //4.执行Call
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
    
                }
                @Override
                public void onResponse(Call call, final Response response) throws IOException {
                    long total = response.body().contentLength();
                    long sum = 0L;
                    InputStream is = response.body().byteStream();
                    int len = 0;
                    File file = new File(Environment.getExternalStorageDirectory(),"test1.jpg");
                    FileOutputStream fos = new FileOutputStream(file);
                    byte[] buf = new byte[128];
                    while ((len = is.read(buf))!=-1){
                        fos.write(buf,0,len);
                        sum += len;
                        //通过日志打印出下载进度
                        Log.d("progress",sum + "/" + total);
                    }
                    fos.flush();
                    fos.close();
                    is.close();
                }
            });
        }
    

    2.2 通过对原有的RequestBody进行封装的方法来追踪上传进度。

    创建ProgressResponseBody,继承自RequestBody
    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;
    
    public class ProgressRequestBody extends RequestBody {
        //真正的RequestBody,内部所有的方法都是通过这个代理对象去执行
        private RequestBody delegateRequestBody;
        private ProgressListener listener;
    
        public interface ProgressListener {
            /**
             * @param byteWrited 上传了的字节数
             * @param total 总共的字节数
             */
            void onUploadProgress(long byteWrited,long total);
        }
    
        public ProgressRequestBody(RequestBody delegateRequestBody, ProgressListener listener) {
            this.delegateRequestBody = delegateRequestBody;
            this.listener = listener;
        }
    
        @Nullable
        @Override
        public MediaType contentType() {
            return delegateRequestBody.contentType();
        }
    
        @Override
        public long contentLength() {
            try {
                return delegateRequestBody.contentLength();
            } catch (IOException e) {
                return -1;
            }
        }
    
        @Override
        public void writeTo(BufferedSink sink) throws IOException {
            CountingSink countingSink = new CountingSink(sink);
            BufferedSink bufferedSink = Okio.buffer(countingSink);
            delegateRequestBody.writeTo(bufferedSink);
            bufferedSink.flush();
        }
    
        private class CountingSink extends ForwardingSink{
            private long bytesWrited;
            public CountingSink(Sink delegate) {
                super(delegate);
            }
            @Override
            public void write(Buffer source, long byteCount) throws IOException {
                super.write(source, byteCount);
                bytesWrited += byteCount;
                listener.onUploadProgress(bytesWrited,contentLength());
            }
        }
    
    }
    
    使用ProgressRequestBody追踪上传进度
        //post上传文件
        public void doUpload(View view){
            File file = new File(Environment.getExternalStorageDirectory(),"test.jpg");
            if (!file.exists()){
                Log.e("mTAG",file.getAbsolutePath()+"not exist!");
                return;
            }
            MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
            RequestBody requestBody = multipartBodyBuilder.setType(MultipartBody.FORM)
                    .addFormDataPart("username", "test")
                    .addFormDataPart("password", "test")
                    //addFormDataPart(服务器表单域key,服务器图片名称,File的RequestBody)
                    .addFormDataPart("mPhoto", "upload.jpg", RequestBody.create(MediaType.parse("application/octet-stream"), file))
                    .build();
            //使用我们封装的ProgressRequestBody
            ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody, new ProgressRequestBody.ProgressListener() {
                @Override
                public void onUploadProgress(long byteWrited, long total) {
                    //通过日志打印出上传进度
                    Log.d("progress",byteWrited + "/" + total);
                }
            });
            Request.Builder builder = new Request.Builder();
            Request request = builder.url(mBaseUrl + "uploadInfo").post(progressRequestBody).build();
            executeRequest(request);
        }
    

    3.封装

    实际开发中建议使用封装的比较好的OkHttp库OkGo:https://github.com/jeasonlzy/okhttp-OkGo

    相关文章

      网友评论

        本文标题:OkHttp

        本文链接:https://www.haomeiwen.com/subject/fopuvftx.html