Android HTTP访问

您所在的位置:网站首页 http请求json数据 Android HTTP访问

Android HTTP访问

2023-04-07 10:37| 来源: 网络整理| 查看: 265

一、简介 主要有okhttp在App接口访问中的详细用法,内容包括通过okhttp调用HTTP接口的三种方式(GET方式、表单格式的POST请求、JSON格式的POST请求)、如何使用okhttp下载网络文件以及如何将本地文件上传到服务器、如何借助下拉刷新和上拉加载技术实现网络信息的分页访问。 1、通过okhttp调用HTTP接口 虽然使用HttpURLConnection能够实现大多数的网络访问操作,但是它的用法实在烦琐,很多细节都要开发者关注,一不留神就可能导致访问异常。于是许多网络开源框架纷纷涌现,比如声名显赫的Apache的HttpClient、Square的okhttp。Android从9.0开始正式弃用HttpClient,使得okhttp成为App开发流行的网络框架。 因为okhttp属于第三方框架,所以使用之前要修改build.gradle,增加下面一行依赖配置:

implementation 'com.squareup.okhttp3:okhttp:4.9.2'

访问网络之前得先申请上网权限,也就是在AndroidManifest.xml里面补充以下权限:

除此之外,Android 9开始默认只能访问以HTTPS开头的安全地址,不能直接访问以HTTP开头的网络地址。如果应用仍想访问以HTTP开头的普通地址,就得修改AndroidManifest.xml,给application节点添加如下属性,表示继续使用HTTP明文地址:

android:usesCleartextTraffic="true"

二、okhttp的网络访问功能十分强大,单就HTTP接口调用而言,它就支持三种访问方式:GET方式的请求、表单格式的POST请求、JSON格式的POST请求,下面分别进行说明: 1、GET方式的请求 不管是GET方式还是POST方式,okhttp在访问网络时都离不开下面4个步骤: (1)使用OkHttpClient类创建一个okhttp客户端对象。创建客户端对象的示例代码如下:

OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象

(2)使用Request类创建一个GET或POST方式的请求结构。采取GET方式时调用get方法,采取POST方式时调用post方法。此外,需要指定本次请求的网络地址,还可添加个性化HTTP头部信息。创建请求结构的示例代码如下:

// 创建一个GET方式的请求结构 Request request = new Request.Builder() //.get() // 因为OkHttp默认采用get方式,所以这里可以不调get方法 .header("Accept-Language", "zh-CN") // 给http请求添加头部信息 .url(URL_STOCK) // 指定http请求的调用地址 .build();

(3)调用第1步骤中客户端对象的newCall方法,方法参数为第2步骤中的请求结构,从而创建Call类型的调用对象。创建调用对象的示例代码如下:

Call call = client.newCall(request); // 根据请求结构创建调用对象

(4)调用第3步骤中Call对象的enqueue方法,将本次请求加入HTTP访问的执行队列,并编写请求失败与请求成功两种情况的处理代码。加入执行队列的示例代码如下:

// 加入HTTP请求队列。异步调用,并设置接口应答的回调方法 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 请求失败 // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用股指接口报错:"+e.getMessage())); } @Override public void onResponse(Call call, final Response response) throws IOException { // 请求成功 String resp = response.body().string(); // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用股指接口返回:\n"+resp)); } });

以上四步就是使用okhttp访问网络的完整步骤,具体的接口调用代码如下:OkhttpCallActivity完整代码

// 发起GET方式的HTTP请求 private void doGet() { OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象 // 创建一个GET方式的请求结构 Request request = new Request.Builder() //.get() // 因为OkHttp默认采用get方式,所以这里可以不调get方法 .header("Accept-Language", "zh-CN") // 给http请求添加头部信息 .url(URL_STOCK) // 指定http请求的调用地址 .build(); Call call = client.newCall(request); // 根据请求结构创建调用对象 // 加入HTTP请求队列。异步调用,并设置接口应答的回调方法 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 请求失败 // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用股指接口报错:"+e.getMessage())); } @Override public void onResponse(Call call, final Response response) throws IOException { // 请求成功 String resp = response.body().string(); // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用股指接口返回:\n"+resp)); } }); }

2、表单格式的POST请求 由于表单格式不能传递复杂的数据,因此App在与服务端交互时经常使用JSON格式。设定好JSON串的字符编码后再放入RequestBody结构中,示例代码如下:

// 创建一个POST方式的请求结构 RequestBody body = RequestBody.create(jsonString, MediaType.parse("text/plain;")); Request request = new Request.Builder().post(body).url(URL_LOGIN).build();

仍以登录功能为例,App先将用户名和密码组装进JSON对象,再把JSON对象转为字符串,后续便是常规的okhttp调用过程了。采取JSON格式的登录代码如下:

// 发起POST方式的HTTP请求(报文为JSON格式) private void postJson() { String username = et_username.getText().toString(); String password = et_password.getText().toString(); String jsonString =""; try { JSONObject jsonObject = new JSONObject(); jsonObject.put("username",username); jsonObject.put("password",password); jsonString = jsonObject.toString(); } catch (JSONException e) { e.printStackTrace(); } // 创建一个POST方式的请求结构 RequestBody body = RequestBody.create(jsonString, MediaType.parse("text/plain;charset=utf-8")); OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象 Request request = new Request.Builder().post(body).url(URL_LOGIN).build(); Call call = client.newCall(request); // 加入HTTP请求队列。异步调用,并设置接口应答的回调方法 call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 请求失败 // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用登录接口报错:"+e.getMessage())); } @Override public void onResponse(Call call, final Response response) throws IOException { // 请求成功 String resp = response.body().string(); // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用登录接口返回:\n"+resp)); } }); }

要确保服务端的登录接口正常开启,并且手机和计算机连接同一个WiFi,再运行并测试该App。打开登录页面,填入登录信息后点击“发起接口调用”按钮,接收到服务端返回的数据,如图【JSON格式的POST请求结果】所示

JSON格式的POST请求结果.png

二、使用okhttp下载和上传文件 (1)okhttp不但简化了HTTP接口的调用过程,连下载文件都变简单了。对于一般的文件下载,按照常规的GET方式调用流程,只要重写回调方法onResponse,在该方法中通过应答对象的body方法即可获得应答的数据包对象,调用数据包对象的string方法即可得到文本形式的字符串,调用数据包对象的byteStream方法即可得到InputStream类型的输入流对象,从输入流就能读出原始的二进制数据。 以下载网络图片为例,位图工具BitmapFactory刚好提供了decodeStream方法,允许直接从输入流中解码获取位图对象。此时通过okhttp下载图片的示例代码如下:OkhttpDownloadActivity

private final static String URL_IMAGE = "https://www.2008php.com/2019_Website_appreciate/2019-06-11/20190611170449.jpg"; // 下载网络图片 private void downloadImage() { tv_progress.setVisibility(View.GONE); iv_result.setVisibility(View.VISIBLE); // 创建一个okhttp客户端对象 OkHttpClient client = new OkHttpClient(); // 创建一个GET方式的请求结构 Request request = new Request.Builder().url(URL_IMAGE).build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { // 请求失败 // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("下载网络图片报错:" + e.getMessage())); } @Override // 请求成功 public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { InputStream is = response.body().byteStream(); // 从返回的输入流中解码获得位图数据 Bitmap bitmap = BitmapFactory.decodeStream(is); String mediaType = response.body().contentType().toString(); long length = response.body().contentLength(); String desc = String.format("文件类型:%s,文件大小:%d", mediaType, length); // 回到主线程操纵界面 runOnUiThread(() -> { tv_result.setText("下载网络图片返回:"+desc); iv_result.setImageBitmap(bitmap); }); } }); }

运行APP测试如图【下载网络图片的结果】所示

okhttp下载网络图片的结果.png

(2)网络文件不只是图片,还有其他各式各样的文件,这些文件没有专门的解码工具,只能从输入流老老实实地读取字节数据。不过读取字节数据有个好处,就是能够根据已经读写的数据长度计算下载进度,特别在下载大文件的时候,实时展示当前的下载进度非常有用。下面是通过okhttp下载普通文件的示例代码:

private final static String URL_APK = "https://ptgl.fujian.gov.cn:8088/masvod/public/2021/03/19/20210319_178498bcae9_r38.mp4"; // 下载网络文件 private void downloadFile() { tv_progress.setVisibility(View.VISIBLE); iv_result.setVisibility(View.GONE); OkHttpClient client = new OkHttpClient(); // 创建一个okhttp客户端对象 // 创建一个GET方式的请求结构 Request request = new Request.Builder().url(URL_APK).build(); Call call = client.newCall(request); // 根据请求结构创建调用对象 // 加入HTTP请求队列。异步调用,并设置接口应答的回调方法 call.enqueue(new Callback() { @Override public void onFailure(@NonNull Call call, @NonNull IOException e) { // 请求失败 // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("下载网络文件报错:" + e.getMessage())); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) { // 请求成功 String mediaType = response.body().contentType().toString(); long length = response.body().contentLength(); String desc = String.format("文件类型为%s,文件大小为%d", mediaType, length); // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("下载网络文件返回:" + desc)); String path = String.format("%s/%s.apk", getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(), DateUtil.getNowDateTime()); // 下面从返回的输入流中读取字节数据并保存为本地文件 try { InputStream is = response.body().byteStream(); FileOutputStream fos = new FileOutputStream(path); byte[] buf = new byte[100 * 1024]; int sum = 0, len = 0; while ((len = is.read(buf)) !=-1){ fos.write(buf,0,len); sum += len; int progress = (int)(sum * 1.0f/length *100); String detail = String.format("文件保存在%s。已下载%d%%",path,progress); // 回到主线程操纵界面 runOnUiThread(() -> tv_progress.setText(detail)); } } catch (Exception e) { e.printStackTrace(); } } }); }

运行测试如图【文件下载】所示:

文件下载结束的画面.png (3)组合上传的业务场景 okhttp不仅让下载文件变简单了,还让上传文件变得更加灵活易用。修改个人资料上传头像图片、在朋友圈发动态视频等都用到了文件上传功能,并且上传文件常常带着文字说明,比如上传头像时可能一并修改了昵称、发布视频时附加了视频描述,甚至可能同时上传多个文件等。 像这种组合上传的业务场景,有了okhttp就好办多了。它引入分段结构MultipartBody及其建造器,并提供了名为addFormDataPart的两种重载方法,分别适用于文本格式与文件格式的数据。带两个输入参数的addFormDataPart方法,它的第一个参数是字符串的键名,第二个参数是字符串的键值,该方法用来传递文本消息。带三个输入参数的addFormDataPart方法,它的第一个参数是文件类型,第二个参数是文件名,第三个参数是文件体。 举个带头像进行用户注册的例子,既要把用户名和密码送给服务端,也要把头像图片传给服务端,此时需多次调用addFormDataPart方法,并通过POST方式提交数据。虽然存在文件上传的交互操作,但整体操作流程与POST方式调用接口保持一致,唯一区别在于请求结构由MultipartBody生成。下面是上传文件之时根据MultipartBody构建请求结构的代码模板:

private List mPathList = new ArrayList(); // 头像文件的路径列表 // 执行文件上传动作 private void uploadFile() { if (mPathList.size() tv_result.setText("调用注册接口报错:\n" + e.getMessage())); } @Override public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { // 请求成功 String resp = response.body().string(); // 回到主线程操纵界面 runOnUiThread(() -> tv_result.setText("调用注册接口返回:\n" + resp)); } }); }

确保服务端的注册接口正常开启服务端代码,并且手机和计算机连接同一个WiFi,再运行并测试该App。打开初始的注册界面,如图【尚未进行用户注册】所示,依次输入注册信息:

尚未进行用户注册.png 成功提交用户注册信息之后,如图所示: 成功提交用户注册信息.png



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3