Android OkHttp的基本用法

转载://www.greatytc.com/p/c478d7a20d03
OkHttp可以说是如今最为流行的网络请求框架之一,今天来探究下OkHttp 的使用方法,包括Get 请求、Post 请求、上传下载文件、上传下载图片等功能

在使用OKHttp之前,首先要先了解如下几个比较核心的类:

  • OkHttpClient:客户端对象
  • Request:访问请求,Post请求中需要包含RequestBody
  • RequestBody:请求数据,在Post请求中用到
  • Response:即网络请求的响应结果
  • MediaType:数据类型,用来表明数据是json,image,pdf等一系列格式
  • client.newCall(request).execute():同步的请求方法
  • client.newCall(request).enqueue(Callback callBack):异步的请求方法,但Callback是执行在子线程中的,因此不能在此进行UI更新操作

在使用前需要先在项目中添加OkHttp的依赖库,在对应的Module的gradle中添加如下语句

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

此外,OkHttp内部依赖另一个开源库OkIo,所以也要将它导入进来

compile 'com.squareup.okio:okio:1.11.0'

然后同步项目即可OkHttp的GitHub地址是:OkHttp
OkIo的GitHub地址是:OkIo

一、Get 请求

最常见的网络请求方式可以说就是Get请求了,这里来获取我在简书的个人主页的网页内容

public void get(View view) {
        OkHttpClient client = new OkHttpClient();
        //构造Request对象
        //采用建造者模式,链式调用指明进行Get请求,传入Get的请求地址
        Request request = new Request.Builder().get().url("//www.greatytc.com/u/9df45b87cfdf").build();
        Call call = client.newCall(request);
        //异步调用并设置回调函数
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(GetActivity.this, "Get 失败");
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                final String responseStr = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_result.setText(responseStr);
                    }
                });
            }
        });
    }

需要注意的是,异步调用的回调函数是在子线程当中的,因为需要用Handler或者runOnUiThread来更新UI
这里使用到了一个Toast工具类,用户判断当前线程是否是主线程,是的话则直接弹出Toast,否则利用runOnUiThread来弹出Toast

public class ToastUtil {

    public static void showToast(final Activity activity, final String message) {
        if ("main".equals(Thread.currentThread().getName())) {
            Log.e("ToastUtil", "在主线程");
            Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
        } else {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Log.e("ToastUtil", "不在主线程");
                    Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

}

此外,在回调函数的以下方法中

public void onResponse(Call call, final Response response)

如果希望获得返回的是字符串,则可以使用

response.body().string()

如果需要的是字节数组,则使用

response.body().bytes()

如果需要的是输入流,则使用

response.body().byteStream()

二、Post 类型

在OkHttp中用Post方法向服务器发送一个请求体时,请求体需要是一个RequestBody。这个请求体可以是:

  • key-value:键值对类型
  • String:字符串类型
  • Form:类似于Html的表单数据提交
  • Stream:流类型
  • File:文件类型

三、Post 键值对

 public void postParameter(View view) {
        OkHttpClient client = new OkHttpClient();
        //构建FormBody,传入要提交的参数
        FormBody formBody = new FormBody
                .Builder()
                .add("username", "initObject")
                .add("password", "initObject")
                .build();
        final Request request = new Request.Builder()
                .url("//www.greatytc.com/")
                .post(formBody)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(PostParameterActivity.this, "Post Parameter 失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseStr = response.body().string();
                ToastUtil.showToast(PostParameterActivity.this, "Code:" + String.valueOf(response.code()));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_result.setText(responseStr);
                    }
                });
            }
        });
    }

这里来向简书的网站主页提交两个参数值,可以通过Post来实现模拟登录的功能。当然这里只是模拟了Post操作而已,提交参数后会跳转到404页面

public void onResponse(Call call, Response response)

方法中通过

response.code()

可以得到整数类型的结果码:404

四、Post 字符串

在上面的例子中Post传递的是参数对,有时候我们会有要传送字符串的需要,比如向服务器发送一个JSON字符串。那么就可以用如下方法:

public void postString(View view) {
        OkHttpClient client = new OkHttpClient();
        //RequestBody中的MediaType指定为纯文本,编码方式是utf-8
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain;charset=utf-8"),
                "{username:admin;password:admin}");
        final Request request = new Request.Builder()
                .url("//www.greatytc.com/")
                .post(requestBody)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(PostStringActivity.this, "Post String 失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseStr = response.body().string();
                ToastUtil.showToast(PostStringActivity.this, "Code:" + String.valueOf(response.code()));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_result.setText(responseStr);
                    }
                });
            }
        });
    }

五、Post 表单

通过查看网站登录页的Html源代码,通常都可以查看到如下格式的登录表单

<form id="fm1" action="" method="post">
    <input id="username" name="username" type="text"/>    
    <input id="password" name="password" type="password"/>                    
</form>

这里使用到 MuiltipartBody 来构建一个RequestBody,这是 RequestBody 的一个子类,提交表单数据就是利用这个类来实现的

public void postForm(View view) {
        OkHttpClient client = new OkHttpClient();
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("username", "叶应是叶")
                .addFormDataPart("password", "叶应是叶")
                .build();
        final Request request = new Request.Builder()
                .url("//www.greatytc.com/")
                .post(requestBody)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(PostFormActivity.this, "Post Form 失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseStr = response.body().string();
                ToastUtil.showToast(PostFormActivity.this, "Code:" + String.valueOf(response.code()));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_result.setText(responseStr);
                    }
                });
            }
        });
    }

六、Post 流

public void postStreaming(View view) {
        final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
        OkHttpClient client = new OkHttpClient();
        RequestBody requestBody = new RequestBody() {
            @Override
            public MediaType contentType() {
                return MEDIA_TYPE_MARKDOWN;
            }

            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                sink.writeUtf8("Numbers\n");
                sink.writeUtf8("-------\n");
                for (int i = 2; i <= 997; i++) {
                    sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
                }
            }

            private String factor(int n) {
                for (int i = 2; i < n; i++) {
                    int x = n / i;
                    if (x * i == n) return factor(x) + " × " + i;
                }
                return Integer.toString(n);
            }
        };
        Request request = new Request.Builder()
                .url("https://api.github.com/markdown/raw")
                .post(requestBody)
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(PostStreamingActivity.this, "Post Streaming 失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseStr = response.body().string();
                ToastUtil.showToast(PostStreamingActivity.this, "Code:" + String.valueOf(response.code()));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_result.setText(responseStr);
                    }
                });
            }
        });
    }

七、Post 文件

public void postFile(View view) {
        OkHttpClient client = new OkHttpClient();
        final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
        File file = new File("README.md");
        Request request = new Request.Builder()
                .url("https://api.github.com/markdown/raw")
                .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(PostFileActivity.this, "Post File 失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String responseStr = response.body().string();
                ToastUtil.showToast(PostFileActivity.this, "Code:" + String.valueOf(response.code()));
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tv_result.setText(responseStr);
                    }
                });
            }
        });
    }

八、下载图片

public void downImage(View view) {
        OkHttpClient client = new OkHttpClient();
        final Request request = new Request
                .Builder()
                .get()
                .url("http://avatar.csdn.net/B/0/1/1_new_one_object.jpg")
                .build();
        Call call = client.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                ToastUtil.showToast(DownImageActivity.this, "下载图片失败");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                InputStream inputStream = response.body().byteStream();
                //将图片显示到ImageView中
                final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        iv_result.setImageBitmap(bitmap);
                    }
                });
                //将图片保存到本地存储卡中
                File file = new File(Environment.getExternalStorageDirectory(), "image.png");
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                byte[] temp = new byte[128];
                int length;
                while ((length = inputStream.read(temp)) != -1) {
                    fileOutputStream.write(temp, 0, length);
                }
                fileOutputStream.flush();
                fileOutputStream.close();
                inputStream.close();
            }
        });
    }

指定图片地址并下载成功后,获取图片的输入流,先用Bitmap decodeStream(InputStream is)方法将输入流转为Bitmap然后显示出来,然后将图片保存到本地存储卡根目录下
记得要申请存储卡的写权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,652评论 18 139
  • 参考Android网络请求心路历程Android Http接地气网络请求(HttpURLConnection) 一...
    合肥黑阅读 21,274评论 7 63
  • 前言:现在做 Android 开发,应该绝大部分都是用 OkHttp 来做网络请求的。可见 OkHttp 的强大。...
    张少林同学阅读 3,291评论 0 14
  • 最好的生活状态是顺其自然,而且心中有爱。不管你本来的起始点是好还是不好,只要心中始终如一,最后总会走向你自己状...
    简彤阅读 121评论 0 0
  • 一、TOPK 分析工具的定义 这个学期,通过学习黄徳华老师(江湖人称:华仔老师)主讲的《创业搭档》课程,我们学会了...
    一往直前阅读 1,038评论 0 0