安卓网络知识总结(四)--Okhttp的简单介绍和使用

Okhttp的简单介绍和使用

这一周就是把之前学的Okhttp重新总结和学习了一下,之前只是在《安卓第一行代码》里面简单了解了一下这个,但是实际自己用起来还是不太熟练,可能是练的太少了吧,然后看了好多人的博客,总结一下这个。

okhttp介绍

一个处理网络请求的开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献。反正就是别人大佬在前人基础上封装的一个网络库,比之前用的网络基础类HttpUrlConnection要简单很多,因为好多的事别人都帮你弄好。
网络请求发展:
HttpURLConnection—>Apache HTTP Client—>Volley—->okHttp
优势
允许连接到同一个主机地址的所有请求,提高请求效率
共享Socket,减少对服务器的请求次数
通过连接池,减少了请求延迟
缓存响应数据来减少重复的网络请求
减少了对数据流量的消耗
自动处理GZip压缩
缺点
消息回来需要切到主线程,主线程要自己去写
传入调用比较复杂。

使用步骤

第一步:添加网络权限和okhttp的包
compile ‘com.squareup.okhttp3:okhttp:3.0.1’
这个去具体官网上看下最新的是多少
这里写图片描述
第二步:创建OkhttpClient对象
OkHttpClient client=new OkHttpClient();
第三步:创建一个Request对象
Request request = new Request.Builder().url(url).build();
里面url可以添加请求的地址,可以添加请求头
第四步:调用newcall()回调方法创建一个call对象,调用它的execute()获取请求返回的数据

GET请求同步方法

OkHttpClient client=new OkHttpClient(); //创建一个okhttpClient实例
Request request = new Request.Builder().url(url) .build(); //创建一个Request实例
Response response= client.newCall(request).execute(); //调用一个newcall创建一个call对象 并execute方法发送请求并获取服务器返回的数据
String message=response.body().string();//得到返回的内容

以上就是get请求方式
1.先实例化okhttp,构建一个request,使用的是get方式,放入一个url地址就可以了,也可以通过Request.Builder设置更多的参数。
2.然后通过client发起一个请求,放入队列。等待任务完成,在Callback中取结果。
3.通过response.body().string()获取返回来的字符串。
这个body()其实就是ResponseBody的对象

GET请求异步方法

 Request request = new Request.Builder().url("http://www.baidu.com").build();
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        // call   是一个接口,  是一个准备好的可以执行的request  可以取消,对位一个请求对象,只能单个请求
                         Log.d("233","请求失败");
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        /**
                         * 通过拿到response这个响应请求,然后通过body().string(),拿到请求到的数据
                         *这里最好用string()  而不要用toString()
                         * toString()每个类都有的,是把对象转换为字符串
                         * string()是把流转为字符串
                         */
                        result = response.body().string();

同步提交和异步提交的差别

**同步请求只能同一个时刻发起一个任务
异步请求可以同一个时刻发起多个请求**
同步和异步的概念对于很多人来说是一个模糊的概念,是一种似乎只能意会不能言传的东西。其实我们的生活中存在着很多同步异步的例子。比如:你叫我去吃饭,我听到了就立刻和你去吃饭,如果我们有听到,你就会一直叫我,直到我听见和你一起去吃饭,这个过程叫同步;异步过程指你叫我去吃饭,然后你就去吃饭了,而不管我是否和你一起去吃饭。而我得到消息后可能立即就走,也可能过段时间再走。如果我请你吃饭,就是同步,如果你请我吃饭就用异步,这样你比较省钱。哈哈哈。。。
在计算机领域,同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

Post请求

From表单形式

OkHttpClient client = new OkHttpClient();
RequestBody body = new FormBody.Builder()
.add("username","xiaoyi")
.build();
Request request = new Request.Builder()
.post(body)
.url(url)
. build();
client.newCall(request).enqueue(new Callback() {...});

json参数形式

kHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), json); Request request = new Request.Builder() .post(body) .url(url). build(); client.newCall(request).enqueue(new Callback() {...});

文件上传

OkHttpClient client = new OkHttpClient();
RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), fiDatale);
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "head_img", fileBody)
.addFormDataPart("name", "xiaoyi").build();
Request request = new Request.Builder() .url(url) .post(requestBody) .build();
client.newCall(request).enqueue(new Callback() {...});

文件下载

url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";
   //构建request对象
        Request request = new Request.Builder().url(url).build();
        OkHttpClient client = new OkHttpClient();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream inputStream = response.body().byteStream();
                FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/logo.jpg"));
                byte[] buffer = new byte[2048];
                int len = 0;
                while ((len = inputStream.read(buffer)) != -1) {
                    fileOutputStream.write(buffer, 0, len);
                }
                fileOutputStream.flush();
                Log.d("wuyinlei", "文件下载成功...");
            }
        });

超时设置

okhttp3.0之前:
    client.setConnectTimeout(10, TimeUnit.SECONDS);
    client.setWriteTimeout(10, TimeUnit.SECONDS);
    client.setReadTimeout(30, TimeUnit.SECONDS);

okhttp3.0之后:
        client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
        client.newBuilder().readTimeout(10,TimeUnit.SECONDS);
        client.newBuilder().writeTimeout(10,TimeUnit.SECONDS);

okhttp的Doem

这里写图片描述
就是简单的请求一下百度的网址,然后模拟表单请求
布局代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_1"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:text="同步请求"/>
        <Button
            android:id="@+id/btn_2"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:text="异步请求"/>
        <Button
            android:id="@+id/btn_3"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:text="表单提交"/>
        <Button
            android:id="@+id/btn_4"
            android:layout_width="80dp"
            android:layout_height="match_parent"
            android:text="文件下载"/>

    </LinearLayout>
    <TextView
        android:id="@+id/iv_show"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

主activity

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private Button syncGet;
    private Button asyncget;
    private Button post;
    private Button fileDowmload;
    private TextView textView;
    private String result;

    private static OkHttpClient client = new OkHttpClient();

    /**
     * 设置连接超时的设定,在静态方法内,构造方法被调用时候就已经被激活
     * @param savedInstanceState
     */
    static {
        client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
        client.newBuilder().readTimeout(10,TimeUnit.SECONDS);
        client.newBuilder().writeTimeout(10,TimeUnit.SECONDS);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initialize();
        initListener();
    }
    /**
     * 事件监听
     */
    private void initListener(){
        syncGet.setOnClickListener(this);
        asyncget.setOnClickListener(this);
        post.setOnClickListener(this);
        fileDowmload.setOnClickListener(this);
    }
    /**
     * 初始化布局
     */
    private void initialize(){
        syncGet = (Button)findViewById(R.id.btn_1);
        asyncget = (Button)findViewById(R.id.btn_2);
        post = (Button)findViewById(R.id.btn_3);
        fileDowmload = (Button)findViewById(R.id.btn_4);
        textView = (TextView)findViewById(R.id.iv_show);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_1:
               initSyncData();
                break;
            case R.id.btn_2:
                //直接调用
                initAsyncGet();
                break;
            case R.id.btn_3:
                initPost();
                break;
            case R.id.btn_4:
                downLoadFile();
                break;
        }
    }
    /**
     * geti请求同步
     */
    private void initSyncData(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Request request = new Request.Builder().url("http://www.baidu.com").build();
                    Response response = client.newCall(request).execute();
                    result = response.body().string();
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            textView.setText(result);
                            Log.d("233","sync");
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    /**
     * 异步请求
     */
    private void initAsyncGet(){
        new Thread(new Runnable() {
            @Override
            public void run() {
                Request request = new Request.Builder().url("http://www.baidu.com").build();
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        // call   是一个接口,  是一个准备好的可以执行的request  可以取消,对位一个请求对象,只能单个请求
                         Log.d("233","请求失败");
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        /**
                         * 通过拿到response这个响应请求,然后通过body().string(),拿到请求到的数据
                         *这里最好用string()  而不要用toString()
                         * toString()每个类都有的,是把对象转换为字符串
                         * string()是把流转为字符串
                         */
                        result = response.body().string();
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                textView.setText(result);
                            }
                        });

                    }
                });
            }
        }).start();
    }

    /**
     * 表单提交
     */
    private void initPost(){
        String url = "http://112.124.22.238:8081/course_api/banner/query";
        FormBody formBody = new FormBody.Builder()
                .add("type","1")
                .build();
        final Request request = new Request.Builder().url(url)
                .post(formBody).build();
        new Thread(new Runnable() {
            @Override
            public void run() {
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {

                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                textView.setText("成功");
                            }
                        });

                    }
                });
            }
        }).start();
    }

    /**
     * 文件下载
     */
    private void downLoadFile(){
        String url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";
        Request request = new Request.Builder().url(url).build();
        OkHttpClient client = new OkHttpClient();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //请求的结果转换成字节流
                InputStream inputStream = response.body().byteStream();
                /**
                 * 在这里要加上权限   在mainfests文件中
                 * <uses-permission android:name="android.permission.INTERNET"/>
                 * <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
                 */
                //输出流
                FileOutputStream fileOutputStream = new FileOutputStream(new File("logo.jpg"));
                //定义一个字节数组
                byte[] buffer = new byte[2048];
                int len = 0;
                while((len =inputStream.read(buffer))!=-1){
                    //写出文件
                    fileOutputStream.write(buffer,0,len);
                }
                //关闭输出流
                fileOutputStream.flush();
                Log.d("233","下载成功");
            }
        });
    }
}

对okhttp的封装

如果每次一次请求都要按照上面的写一大堆的话,就是觉得很麻烦,然后可以把他们封装一下,这样下次调用时候就能方便点。
类似这种
这里写图片描述
封装的okhttpManager

package com.example.hasee.okhttpdome;

import android.os.Handler;
import android.os.Looper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 封装okhttp
 */
public class OkHttpManager {
    /**
     * 静态实例
     */
    private static OkHttpManager sokHttpManager;
    /**
     * okhttpclient实例
     */
    private OkHttpClient mClient;
    /**
     * 请求数据必须在子线程里面,所以用handler
     */
    private Handler mHandler;

    /**
     * 构造方法
     */
    private OkHttpManager() {
        mClient = new OkHttpClient();
        /**
         * 直接设置超时这些
         */
        mClient.newBuilder().connectTimeout(10, TimeUnit.SECONDS);
        mClient.newBuilder().readTimeout(10, TimeUnit.SECONDS);
        mClient.newBuilder().writeTimeout(10, TimeUnit.SECONDS);
        /**
         * 初始化handler
         */
        mHandler = new Handler(Looper.getMainLooper());
    }
    /**
     * 单例模式
     */
    public static OkHttpManager getInstance(){
        if (sokHttpManager == null){
            sokHttpManager = new OkHttpManager();
        }
        return sokHttpManager;
    }
    //-----------------同步请求-----------------------------------------
    /**
     * 对外提供get方法,
     */
    public static Response getSync(String url){
        //通过实例获取调用内部的方法
        return sokHttpManager.inner_getSync(url);
    }
    /**
     * get的内部的方法
     */
    private Response inner_getSync(String url){
        Request request = new Request.Builder().url(url).build();
        Response response = null;
        try {
            response = mClient.newCall(request).execute();
        }catch (IOException e){
            e.printStackTrace();
        }
        return response;
    }
    /**
     * 对外获取同步的string方法
     */
    public static String getSyncString(String url){
        return sokHttpManager.inner_getSynString(url);
    }
    /**
     * 同步的方法
     */
    private String inner_getSynString(String url){
        String result = null;
        try {
            //结果转换为字符串
            result = inner_getSync(url).body().string();
        }catch (IOException e){
            e.printStackTrace();
        }
        return result;
    }
    //------------------异步请求数据-------------------------------------------------

    /**
     * 数据回调接口
     */
    public interface DataCallBack{
        void requestFailure(Request request,IOException e);
        void requestSuccess(String result) throws Exception;
    }
    /**
     * 分发失败的时候调用
     *
     * @param request
     * @param e
     * @param callBack
     */
    private void deliverDataFailure(final Request request, final IOException e, final DataCallBack callBack) {
        /**
         * 在这里使用异步处理
         */
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    callBack.requestFailure(request, e);
                }
            }
        });
    }

    /**
     * 分发成功的时候调用
     *
     * @param result
     * @param callBack
     */
    private void deliverDataSuccess(final String result, final DataCallBack callBack) {
        /**
         * 在这里使用异步线程处理
         */
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    try {
                        callBack.requestSuccess(result);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
    //-------------------------异步的方式请求数据--------------------------
    public static void getAsync(String url, DataCallBack callBack) {
        getInstance().inner_getAsync(url, callBack);
    }

    /**
     * 内部逻辑请求的方法
     *
     * @param url
     * @param callBack
     * @return
     */
    private void inner_getAsync(String url, final DataCallBack callBack) {
        final Request request = new Request.Builder().url(url).build();

        mClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                deliverDataFailure(request, e, callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = null;
                try {
                    result = response.body().string();
                } catch (IOException e) {
                    deliverDataFailure(request, e, callBack);
                }
                deliverDataSuccess(result, callBack);
            }
        });
    }


    /**
     * 对外的接口
     * @param url
     * @param callBack
     */
    public static void getAsync(String url,Map<String, String> params,DataCallBack callBack){
        getInstance().inner_postAsync(url,params,callBack);
    }
    private void inner_postAsync(String url, Map<String,String> params, final DataCallBack callBack){
        RequestBody requestBody = null;
        if (params==null){
            params = new HashMap<>();
        }

        FormBody.Builder builder = new FormBody.Builder();

        //对参加的参数进行遍历
        for(Map.Entry<String,String>map:params.entrySet()){
            String key = map.getKey().toString();
            String value = null;
            //判断值是否为空
            if (map.getValue()==null){
                value = "";
            }else {
                value = map.getValue();
            }
            //添加到formbody
            builder.add(key,value);
        }
        requestBody = builder.build();
        //返回结果
        final Request request = new Request.Builder().url(url).post(requestBody).build();
        mClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                deliverDataFailure(request,e,callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String result = response.body().string();
                deliverDataSuccess(result,callBack);

            }
        });
    }
    //-----------------------文件下载---------------------------------------------------
    public static void downloadAsync(String url,String desDir,DataCallBack callBack){
        getInstance().inner_downloadAsync(url,desDir,callBack);
    }

    /**
     *
     * @param url  下载地址
     * @param desDir  目标地址
     * @param callBack
     */
    private void inner_downloadAsync(final String url,final String desDir,final DataCallBack callBack){
        final Request request = new Request.Builder().url(url).build();
        mClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                deliverDataFailure(request,e,callBack);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream inputStream = null;
                FileInputStream fileInputStream = null;
                FileOutputStream fileOutputStream = null;
                try {
                    File file = new File(desDir,getFileName(url));
                    inputStream = response.body().byteStream();
                    fileInputStream = new FileInputStream(file);
                    int len  = 0;
                    byte[] bytes = new byte[2048];
                    //循环读取数据
                    while ((len = inputStream.read(bytes)) != -1) {
                        fileOutputStream.write(bytes, 0, len);
                    }
                    //关闭文件输出流
                    fileOutputStream.flush();
                    //调用分发数据成功的方法
                    deliverDataSuccess(file.getAbsolutePath(), callBack);
                }catch (IOException e){
                    //失败后
                    deliverDataFailure(request,e,callBack);
                    e.printStackTrace();
                }finally {
                    if (inputStream!=null){
                        inputStream.close();
                    }
                    if (fileOutputStream!=null){
                        fileOutputStream.close();
                    }
                }

            }
        });
    }
    /**
     * 根据文件url获取文件的路径名字
     *
     * @param url
     * @return
     */
    private String getFileName(String url) {
        int separatorIndex = url.lastIndexOf("/");
        String path = (separatorIndex < 0) ? url : url.substring(separatorIndex + 1, url.length());
        return path;
    }

}

总结

就把简单的例子总结了一下,但是具体的源代码还没看,对网络请求这块运用有了基本的理解。
https://github.com/sakurakid/okhttpDome是Dome的地址,封装的http代码也在里面
希望对别人有帮助

扫描二维码关注公众号,回复: 2640689 查看本文章

猜你喜欢

转载自blog.csdn.net/sakurakider/article/details/80557148