Android 中Okhttp的同步请求与异步请求详解

简介: Android 中Okhttp的同步请求与异步请求详解

前言: 在过去,Android上发送HTTP请求一般有两种方式:HttpURLConnection和HttpClient,由于HttpClient存在的API数量过多,扩展困难等缺点,在Android6.0系统中,HttpClient的功能被完全移除了。

OkHttp 是由Square公司开发的,OkHttp在接口封装上做的简单易用,比起原生的HttpURLConnection,可以说是有过之而无不及,现在已经成为了广大Android开发者首选的网络通信库。

使用HttpURLConnection进行网络请求详解请看这篇文章

同步请求与异步请求的概念:

简单地说,同步就是发出一个请求后什么事都不做,一直等待请求返回后才会继续做事;异步就是发出请求后继续去做其他事,这个请求处理完成后会通知你,这时候就可以处理这个回应了。

写了个Demo去理解Okhttp中的get同步请求与异步请求,和post同步请求与异步请求

1.get的同步请求,其中的讲解,已经在代码中注释了出来。

//get同步请求
    public void getSync(View view) {
        //在Android 中完成网络请求必须在子线程中完成
        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient okHttpClient = new OkHttpClient();
                Request request = new Request.Builder().url("http://www.httpbin.org/get?a=1&b=2").build();
                //准备好请求的Code对象
                Call call = okHttpClient.newCall(request);
                try {
                    //同步请求要创建子线程,是因为execute()方法,会阻塞后面代码的执行
                    //只有执行了execute方法之后,得到了服务器的响应response之后,才会执行后面的代码
                    //所以同步请求要在子线程中完成
                    Response response = call.execute();
                    //把服务器给我们响应的字符串数据打印出来
                    Log.i(TAG,"getSync:"+response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

2.get异步请求:

//get的异步请求
    public void getAsync(View view) {
        //定义okhttp对象
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder().url("http://www.httpbin.org/get?a=1&b=2").build();
        Call call = okHttpClient.newCall(request);
        //异步请求:不用创建子线程
        //enqueue()并不会阻塞代码的执行,不需要与服务器请求完成之后,才会执行后面的代码
        //而且enqueue内部会为我们创建子线程
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
            }
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
             Log.i("TAG", "onResponse: " + (Looper.getMainLooper().getThread() == Thread.currentThread()));//为false 表示这是在子线程,需要切换到主线程才能操作UI
                if (response.isSuccessful()){
                    Log.i(TAG,"getAsync:"+response.body().string());
                }
            }
        });
    }

3.post同步请求:

//post同步请求
    public void postSync(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                OkHttpClient okHttpClient = new OkHttpClient();
                //post请求规定,把参数放在请求体里面,用form表单的方式来添加我们的请求体
                FormBody formBody = new FormBody.Builder().add("a", "10000").add("b", "15000").build();
                Request request = new Request.Builder().url("http://www.httpbin.org/post")
                        .post(formBody)
                        .build();
                Call call = okHttpClient.newCall(request);
                try {
                    Response response = call.execute();
                    Log.i(TAG,"postSync:"+response.body().string());
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

4.post的异步请求:

//post异步请求
    public void postAsync(View view) {
        OkHttpClient okHttpClient = new OkHttpClient();
        FormBody formBody = new FormBody.Builder().add("a", "1000").add("b", "2000").build();
        Request request = new Request.Builder().url("http://www.httpbin.org/post")
                .post(formBody)
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
            }
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
              Log.i("TAG", "onResponse: " + (Looper.getMainLooper().getThread() == Thread.currentThread()));//为false 表示这是在子线程,需要切换到主线程才能操作UI
                if (response.isSuccessful()){
                    Log.i(TAG,"postAsync:"+response.body().string());
                }
            }
        });
    }

上面用到的http服务器是公用的,需要的拿去用:地址www.httpbin.org/

新增:

一、 使用OkHttp 上传图片到服务器

private void UpLoadImage(String pictPath, String fileName) { //参数1:图片路径 参数2:图片名称
        new Thread(new Runnable() {
            @Override
            public void run() {
                String url = "具体的URL地址";
                //定义OkHttp
                OkHttpClient okHttpClient = new OkHttpClient();
                MediaType JSON = MediaType.parse("multipart/form-data");
                //定义请求体
                RequestBody body = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM)
                        .addFormDataPart("file", fileName,
                                RequestBody.create(JSON, new File(pictPath)))//addFormDataPart方法的第一个参数是key值,第二个参数是上传文件的名字,第三个参数是需要上传的文件
                        .build();
                try {
                    //执行OkHttp
                    Request request = new Request.Builder()
                            .post(body)
                            .url(url)
                            .build();
                    Response response = okHttpClient.newCall(request).execute();
                    String ss = response.body().string();
                    ResultMsg resultMsg = new Gson().fromJson(ss, ResultMsg.class);
                    if (resultMsg.Result.equals("1")) {
                        Looper.prepare();
                        Toast.makeText(ChangeInformationActivity.this, "图片上传成功!", Toast.LENGTH_SHORT).show();
                        Looper.loop();
                    } else {
                        Looper.prepare();
                        Toast.makeText(ChangeInformationActivity.this, resultMsg.Message, Toast.LENGTH_SHORT).show();
                        Looper.loop();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

二、 使用OkHttp 通过GET异步请求从服务器获取图片,下载到手机图库中,代码如下:

btn_save_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //申请读取或修改存储卡的权限
                //对于共享区间写入的权限,在API29 Android系统10之前是需要申请的
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                    if (ContextCompat.checkSelfPermission(OkHttpActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                        ActivityCompat.requestPermissions(OkHttpActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                    } else {
                        SaveImage();
                    }
                } else {
                    SaveImage();
                }
            }
        });

SaveImage()方法实现从服务器下载一张图片,保存到图库中的功能:

//定义OkHttp
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url("https://cdn.pixabay.com/photo/2021/12/13/15/14/flowers-6868494_960_720.jpg")
                .build();
        Call call = okHttpClient.newCall(request);
        //进行GET的异步请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) { //没有网络的情况下,会回调这个方法
                Log.e(TAG, "onFailure: " + "失败");
            }
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
              //当前就是子线程所以不用再开启子线程了
                InputStream inputStream = response.body().byteStream();
                //之后包装成处理流,提高流的读取
                BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
                BufferedOutputStream bufferedOutputStream = null;
                try {
                    //保存到图库的URI
                    Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
                    OutputStream outputStream = getContentResolver().openOutputStream(uri);
                    bufferedOutputStream = new BufferedOutputStream(outputStream);
                    //定义每次读取的字节数
                    byte[] buffer = new byte[1024 * 8];
                    int len;
                    int length = 0;
                    while ((len = bufferedInputStream.read(buffer)) != -1) {
                        bufferedOutputStream.write(buffer, 0, len);
                        length += len;
                    }
                    Log.i(TAG, "length: " + length);
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (bufferedOutputStream != null) {
                            bufferedOutputStream.close();
                        }
                        if (bufferedInputStream != null) {
                            bufferedInputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

以上就是Okhttp框架的简单实用~,如有不当之处,还望各位网友加以指正!


目录
相关文章
|
5月前
|
存储 缓存 Android开发
安卓Jetpack Compose+Kotlin, 使用ExoPlayer播放多个【远程url】音频,搭配Okhttp库进行下载和缓存,播放完随机播放下一首
这是一个Kotlin项目,使用Jetpack Compose和ExoPlayer框架开发Android应用,功能是播放远程URL音频列表。应用会检查本地缓存,如果文件存在且大小与远程文件一致则使用缓存,否则下载文件并播放。播放完成后或遇到异常,会随机播放下一首音频,并在播放前随机设置播放速度(0.9到1.2倍速)。代码包括ViewModel,负责音频管理和播放逻辑,以及UI层,包含播放和停止按钮。
|
3月前
|
存储 安全 Android开发
"解锁Android权限迷宫:一场惊心动魄的动态权限请求之旅,让你的应用从平凡跃升至用户心尖的宠儿!"
【8月更文挑战第13天】随着Android系统的更新,权限管理变得至关重要。尤其从Android 6.0起,引入了动态权限请求,增强了用户隐私保护并要求开发者实现更精细的权限控制。本文采用问答形式,深入探讨动态权限请求机制与最佳实践,并提供示例代码。首先解释了动态权限的概念及其重要性;接着详述实现步骤:定义、检查、请求权限及处理结果;最后总结了六大最佳实践,包括适时请求、解释原因、提供替代方案、妥善处理拒绝情况、适应权限变更及兼容旧版系统,帮助开发者打造安全易用的应用。
73 0
|
2月前
|
存储 API Android开发
"解锁Android权限迷宫:一场惊心动魄的动态权限请求之旅,让你的应用从平凡跃升至用户心尖的宠儿!"
随着Android系统的更新,权限管理成为应用开发的关键。尤其在Android 6.0(API 级别 23)后,动态权限请求机制的引入提升了用户隐私保护,要求开发者进行更精细的权限管理。
66 2
|
6月前
|
安全 Android开发
Android之OKHttp基本使用和OKHttp发送https请求安全认证
Android之OKHttp基本使用和OKHttp发送https请求安全认证
177 0
|
5月前
|
缓存 Android开发 Kotlin
【安卓app开发】kotlin Jetpack Compose框架 | 先用OKhttp下载远程音频文件再使用ExoPlayer播放
使用 Kotlin 的 Jetpack Compose 开发安卓应用时,可以结合 OkHttp 下载远程音频文件和 ExoPlayer 进行播放。在 `build.gradle` 添加相关依赖后,示例代码展示了如何下载音频并用 ExoPlayer 播放。代码包括添加依赖、下载文件、播放文件及简单的 Compose UI。注意,示例未包含完整错误处理和资源释放,实际应用需补充这些内容。
|
5月前
|
存储 Android开发 Kotlin
开发安卓app OKhttp下载后使用MediaPlayer播放
在Android Jetpack Compose应用程序中,要使用OkHttp下载远程音频文件并在本地播放,你需要完成以下几个步骤: 1. **添加依赖**:确保`build.gradle`文件包含OkHttp和Jetpack Compose的相关依赖。 2. **下载逻辑**:创建一个`suspend`函数,使用OkHttp发起网络请求下载音频文件到本地。 3. **播放逻辑**:利用`MediaPlayer`管理音频播放状态。 4. **Compose UI**:构建用户界面,包含下载和播放音频的按钮。
|
6月前
|
API Apache Android开发
对于Android的http请求的容错管理
对于Android的http请求的容错管理
34 1
|
6月前
|
安全 Android开发 数据安全/隐私保护
Android中的动态权限请求与最佳实践
【4月更文挑战第14天】 在现代安卓应用开发中,用户隐私和安全被赋予了前所未有的重要性。随着Android 6.0(API级别23)引入的运行时权限模型,开发者必须更加细致地处理权限请求,以确保应用功能的完整性同时不侵犯用户的隐私。本文将深入探讨如何在Android应用中实现动态权限请求,分析常见问题,并提供一系列最佳实践,以帮助开发者优雅地处理这一挑战。
428 5
|
6月前
|
JSON 安全 Java
Android网络部分-----网络数据请求、解析
Android网络部分-----网络数据请求、解析
Android网络部分-----网络数据请求、解析
|
6月前
|
Java Android开发
Android Mediatek 禁用 USB 权限请求和声音提示 & 解决USB HID设备不识别问题(附带USB调试过程)
Android Mediatek 禁用 USB 权限请求和声音提示 & 解决USB HID设备不识别问题(附带USB调试过程)
209 0