Android框架

OkHttp

2018-08-06  本文已影响20人  luoqiang108

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

上一篇 下一篇

猜你喜欢

热点阅读