Android 网络编程-网络请求

Android 网络编程-网络请求

文章目录

  • Android 网络编程-网络请求
    • 一、主要内容
    • 二、开发网络请求前的基本准备
      • 1、查看需要请求的网址是否有效
        • (1)通过网页在线验证
        • (2)使用专用window网咯请求工具
        • (3)编写app代码验证
      • 2、学会把服务器的json数据转换成Bean对象
      • 3、具体效果测试
        • 简单测试的网址:
          • 天气api:
          • apipost调试网址
        • (1)get请求,在浏览器窗口栏请求的显示
        • (2)get请求在在线请求网址的显示
        • (3)post请求在在线请求的的网址显示
        • (4)json数据在线转换成Bean对象
        • 应用app效果显示;
    • 三、代码介绍
      • 1、普通网络请求
        • (1)get网络请求
        • (2)Post网络请求
      • 2、使用OkHttp网络框架请求网络
        • (1)Get网络请求
        • (2)Post网络请求
      • 3、使用Retrofit网络框架请求网络
        • (1)Get网络请求
          • ①创建请求接口对象
          • ② 具体的请求代码
        • (2)Post网络请求
          • ①创建请求接口对象
          • ② 具体的请求代码
      • 4、使用WebView显示对应网址的网页
        • (1)在布局文件写入控件WebView
        • (2) 设置基本参数
    • 三、总结
      • 1、网络请求是要在子线程内进行
      • 2、不同框架的网络请求根据项目具体情况使用
      • 3、Android 网络编程要学习些什么
        • (1)网络分层和HTTP协议基本知识,比如请求报文和响应报文
        • (2)Java网络编程基础,TCP/UDP 进行连接交互
        • (3)Json数据转Gson对象
        • (4)Android基本网络请求和基本网络框架使用
        • (5)加密算法:数据加密和解密

本文介绍一下Android 网络请求,开发了简单demo,适合Android入门人员学习。

为啥要写这个??给应届生看的。。。

一、主要内容

1、开发网络请求前的基本准备
2、普通网络请求代码
3、使用OkHttp网络框架请求网络代码
4、使用Retrofit网络框架请求网络代码
5、使用WebView显示对应网址的网页
6、应用demo的相关代码和apk

二、开发网络请求前的基本准备

1、查看需要请求的网址是否有效

(1)通过网页在线验证

能验证get请求和简单的post 请求,比如只设置几个参数的post请求
在线get/post请求测试(里面还有一系列工具):
http://www.jsons.cn/httpurl/
http://coolaf.com/

//可以简单模拟 get/post返回的数据
https://v7.apipost.cn/#/apis/design

(2)使用专用window网咯请求工具

① PostMan
② Apifox (国内自研,PostMan加强版,支持网页和桌面工具)
https://apifox.com/#pricing

(3)编写app代码验证

一般用于验证文件上传的情况,
也可以用windows 工具进行验证,Apifox 也是支持文件上传的。

2、学会把服务器的json数据转换成Bean对象

在线转换Json格式转换JAVA实体Bean类:
http://www.jsons.cn/json2java/

作用?
把字符串的数据赋值到对象,使用的时候直接使用 Object.getXXX 获取返回的某个信息。

也可以使用Android Studio 插件:GsonFormat

3、具体效果测试

get请求测试,可以找网上天气网址的api或者笑话类的api网址;
post请求测试,可以找地图类的api(百度地图),或者语音类的api网址(讯飞)。

简单测试的网址:

天气api:

提供天气,气象查询:https://www.yiketianqi.com/index/doc
get请求网址;
https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=28392918&appsecret=No9zfo8f&adcode=440307000000

apipost调试网址

提供get/post简单调试功能:https://v7.apipost.cn/#/apis/design
注册登陆后,看起来是可以设计返回的数据的,估计是操作要麻烦一点,有需要的可以自己研究。

post请求网址:
https://demo-api.apipost.cn/api/demo/login
mobile=18289454846&ver_code=123456

(1)get请求,在浏览器窗口栏请求的显示

在这里插入图片描述

(2)get请求在在线请求网址的显示

在这里插入图片描述

(3)post请求在在线请求的的网址显示

post 请求在浏览器输入行直接是无法请求到数据的,只能使用专业的网址或者工具 获取post请求的数据。

在这里插入图片描述

(4)json数据在线转换成Bean对象

在这里插入图片描述

应用app效果显示;

主界面:
在这里插入图片描述

普通网络请求:

在这里插入图片描述

OkHttp网络请求:
在这里插入图片描述

retrofit网络请求:
在这里插入图片描述
为啥这里TextView显示的不对,大家可以在代码里面看看。

WebView界面:
在这里插入图片描述

应用demo里面显示了很多WebView界面,这里只展示其中一个。

代码资源下载地址:

https://download.csdn.net/download/wenzhi20102321/88215651

三、代码介绍

1、普通网络请求

网络请求一定要在子线程执行,否则会报错。
数据返回后要显示在界面上要切换回主线程。

(1)get网络请求

    //get方法请求网络public void getNetwork(View view) {GET_UTL = et_url_get.getText().toString();LogUtil.debugInform("GET_UTL = " + GET_UTL);//创建线程,请求网络new Thread(new Runnable() {@Overridepublic void run() {// 创建一个URL对象URL url = null;try {url = new URL(GET_UTL);// 创建一个HttpURLConnection对象,并设置请求方法为GETHttpURLConnection connection = null;connection = (HttpURLConnection) url.openConnection();connection.setRequestMethod("GET");connection.setConnectTimeout(5000);// 获取服务器响应的状态码int responseCode = 0;responseCode = connection.getResponseCode();if (responseCode == HttpURLConnection.HTTP_OK) {// 读取服务器响应的数据BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));StringBuilder response = new StringBuilder();String line;while ((line = reader.readLine()) != null) {response.append(line); //把读取的数据不断放入response对象中}reader.close();// 在UI线程中更新UI  runOnUiThreadString responseData = response.toString();}} catch (Exception e) {e.printStackTrace();LogUtil.error("", e);}}}).start();}

(2)Post网络请求

//post方法请求王网络public void postNetwork(View view) {//创建线程,请求网络new Thread(new Runnable() {@Overridepublic void run() {// 创建一个URL对象URL url = null;try {url = new URL(POST_UTL);// 创建一个HttpURLConnection对象,并设置请求方法为GETHttpURLConnection connection = null;connection = (HttpURLConnection) url.openConnection();connection.setConnectTimeout(5000);//------------------------------ 区别和Get方法 ,Startconnection.setRequestMethod("POST");// 启用输出流,以便向服务器发送数据connection.setDoOutput(true);// 创建一个输出流对象,并将数据写入输出流OutputStream outputStream = connection.getOutputStream();String postData = POST_MESSAGE;outputStream.write(postData.getBytes());outputStream.flush();outputStream.close();//------------------------------ 区别和Get方法 ,End// 获取服务器响应的状态码int responseCode = connection.getResponseCode();if (responseCode == HttpURLConnection.HTTP_OK) {// 读取服务器响应的数据BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));StringBuilder response = new StringBuilder();String line;while ((line = reader.readLine()) != null) {response.append(line); //把读取的数据不断放入response对象中}reader.close();// 在UI线程中更新UI// 处理服务器响应的数据String responseData = response.toString();}} catch (Exception e) {e.printStackTrace();LogUtil.error("", e);}}}).start();}

2、使用OkHttp网络框架请求网络

(1)Get网络请求

//get方法请求网络public void getNetwork(View view) {Request request = new Request.Builder().url(GET_UTL).get() //默认为get ,不设置也行.build();Call call = client.newCall(request);//网络请求的回调call.enqueue(new Callback() {@Overridepublic void onFailure(@NonNull Call call, @NonNull IOException e) {Toast.makeText(OkhttpNetworkActivity.this, "请求错误:" + e.getMessage(), Toast.LENGTH_LONG).show();}@Overridepublic void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {// 处理服务器响应的数据String responseData = response.body().string();LogUtil.debugInform("responseData = " + responseData);// TODO: 在这里处理服务器响应的数据}});}

(2)Post网络请求

//post方法请求王网络public void postNetwork(View view) {//创建网络处理的对象OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();//mobile=18289454846&ver_code=123456//post请求来获得数据//创建一个RequestBody,存放重要数据的键值对RequestBody body = new FormBody.Builder().add("mobile", "18289454846").add("ver_code", "123456").build();//创建一个请求对象,传入URL地址和相关数据的键值对的对象Request request = new Request.Builder().url(POST_UTL).post(body).build();//创建一个能处理请求数据的操作类Call call = client.newCall(request);//使用异步任务的模式请求数据call.enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {LogUtil.error("", e);}@Overridepublic void onResponse(Call call, Response response) throws IOException {// 在UI线程中更新UIString responseData = response.body().string();LogUtil.debugInform("result = " + responseData);}});}

3、使用Retrofit网络框架请求网络

(1)Get网络请求

请求示例网址:
https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=28392918&appsecret=No9zfo8f&adcode=440307000000

①创建请求接口对象
package com.example.networkdemo.retrofit;import com.example.networkdemo.bean.WeatherBean;import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;/*** Get请求* 这里使用get请求的方式请求数据* 并且到的是字符串数据*/
public interface RetrofitWeatherService {//键值对的定义和数据的返回类型的定义这里是String//https://v0.yiketianqi.com/api?unescape=1&version=v61&appid=28392918&appsecret=No9zfo8f&adcode=440307000000//这里使用 @Field 是会报错,是要使用 @Query@GET("api")//get请求方式Call<WeatherBean> getWeather(@Query("unescape") String unescape, @Query("version") String version,@Query("appid") String appid, @Query("appsecret") String appsecret, @Query("adcode") String adcode);
}
② 具体的请求代码

比如在某个Activity写如下代码

//get方法请求网络public void getNetwork(View view) {Retrofit retrofit = getGsonRetrofit(GET_UTL);RetrofitWeatherService weatherService = retrofit.create(RetrofitWeatherService.class);//?unescape=1&version=v61&appid=28392918&appsecret=No9zfo8f&adcode=440307000000"Call<WeatherBean> call = weatherService.getWeather("1", "v61", "28392918", "No9zfo8f", "440307000000");//转换成Call,在call对象包含Url的完整地址//可以看到这里使用了create的方法,里面传入了请求服务的接口类//并且后面接的是接口类的方法,方法里面传入Url地址要的键值对的值//这时call对象就有完整的Url地址,就可以请求数据了//使用call对象进行网络数据请求call.enqueue(new Callback<WeatherBean>() {//网络数据请求成功的回调方法@Overridepublic void onResponse(Call<WeatherBean> call, Response<WeatherBean> response) {runOnUiThread(new Runnable() {@Overridepublic void run() {WeatherBean bean = response.body();tv_info.setText(TimeUtil.getTimeString() + " \n Get请求的数据:" + bean + "");String air_tips = bean.getAir_tips();String update_time = bean.getUpdate_time();String tem1 = bean.getTem1();String tem2 = bean.getTem2();String tem = bean.getTem();Toast.makeText(RetrofitNetworkActivity.this, "天气时间:" + update_time+ "\n 当前温度:" + tem + ",温度变化" + tem2 + "--" + tem1 +"\n 温馨提示:" + air_tips, Toast.LENGTH_LONG).show();}});}//网络数据请求失败的回调方法@Overridepublic void onFailure(Call<WeatherBean> call, Throwable t) {tv_info.setText(TimeUtil.getTimeString() + " \n Get 请求的失败日志:" + t.getMessage() + "");}});}

(2)Post网络请求

Post请求网址:https://demo-api.apipost.cn/api/demo/login
携带信息:mobile=18289454846&ver_code=123456

①创建请求接口对象
package com.example.networkdemo.retrofit;import com.example.networkdemo.bean.LoginBean;import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;/*** 登陆服务器的请求* 这里使用post请求的方式请求数据* 并且到的是一个自定义的对象数据*/
public interface RetrofitLoginService {//https://demo-api.apipost.cn/api/demo/login@POST("api/demo/login")//Post请求方式@FormUrlEncoded      //键值对的定义和数据的返回类型的定义这里是StringCall<LoginBean> login(@Field("mobile") String mobile, @Field("ver_code") String ver_code);
}
② 具体的请求代码
//post方法请求王网络public void postNetwork(View view) {Retrofit retrofit = getGsonRetrofit(POST_UTL); //https://demo-api.apipost.cn/RetrofitLoginService loginService = retrofit.create(RetrofitLoginService.class);Call<LoginBean> call = loginService.login("18289454846", "123456");call.enqueue(new Callback<LoginBean>() {@Overridepublic void onResponse(Call<LoginBean> call, Response<LoginBean> response) {// 在UI线程中更新UIrunOnUiThread(new Runnable() {@Overridepublic void run() {// 处理服务器响应的数据LoginBean loginBean = response.body();LogUtil.debugInform("loginBean = " + loginBean);int code = loginBean.getCode();LoginBean.DataBean data = loginBean.getData();String msg = loginBean.getMsg();Toast.makeText(RetrofitNetworkActivity.this, "登陆信息:" +"\n code = " + code + ", msg = " + msg, Toast.LENGTH_LONG).show();LogUtil.debugInform("data getToken = " + data.getToken());// TODO: 在这里处理服务器响应的数据tv_info.setText(TimeUtil.getTimeString() + " \n Post请求的数据:" + response + "");}});}@Overridepublic void onFailure(Call<LoginBean> call, Throwable t) {runOnUiThread(new Runnable() {@Overridepublic void run() {tv_info.setText(TimeUtil.getTimeString() + " \n Post请求的失败日志:" + t.getMessage() + "");}});}});}//返回一个Gson类型的对象public Retrofit getGsonRetrofit(String url) {Retrofit retrofit = new Retrofit.Builder().baseUrl(url).addConverterFactory(GsonConverterFactory.create()).build();return retrofit;}//返回一个Gson类型的字符串,public Retrofit getStringRetrofit(String url) {Retrofit retrofit = new Retrofit.Builder().baseUrl(url).addConverterFactory(ScalarsConverterFactory.create()).build();return retrofit;}

4、使用WebView显示对应网址的网页

(1)在布局文件写入控件WebView

   <WebViewandroid:id="@+id/web_view"android:layout_width="match_parent"android:layout_height="match_parent" />

(2) 设置基本参数

web_view = findViewById(R.id.web_view);WebSettings webSettings = web_view.getSettings();//如果访问的页面中要与Javascript交互,则webview必须设置支持JavascriptwebSettings.setJavaScriptEnabled(true);webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式//要显示的网址:web_view.loadUrl(url); //设置网址

这里只是基本代码,还可以设置跳转监听,前进后退网页跳转等,可以自己调试研究。

三、总结

1、网络请求是要在子线程内进行

2、不同框架的网络请求根据项目具体情况使用

如果频率很多的使用网络请求,直接使用原生请求即可,不用使用网络框架。
如果使用频率很高,可以使用健全的网络框架:OkHttp/Retrofit;
OkHttp使用简单,Retrofit 使用复杂一些,但是和很多其他框架可以结合使用,比如Gson,RxJava等。

3、Android 网络编程要学习些什么

(1)网络分层和HTTP协议基本知识,比如请求报文和响应报文

虽然不一定会用到,但是也是要知道里面的知识点。

(2)Java网络编程基础,TCP/UDP 进行连接交互

可以写demo,一个作为客户端一个作为服务端,连接后进行通讯交互。

(3)Json数据转Gson对象

网络上数据请求基本都是返回json数据,使用Gson对象可以直接转换成对应的对象,使用起来比较方便。

但是也有一些网络请求返回的数据不是json数据格式,比如xml格式,或者其他特定格式。
这个就需要自己写工具类进行解析了。

(4)Android基本网络请求和基本网络框架使用

不使用网络框架请求网络和使用主流网络框架请求网络。

(5)加密算法:数据加密和解密

因为网络数据是经过加密的,所以必须要经过解密才能读取到正常数据。
算法是会使用框架就行了的,具体算法一般人写不出来!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/94741.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《游戏编程模式》学习笔记(四) 观察者模式 Observer Pattern

定义 观察者模式定义了对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。 这是定义&#xff0c;看不懂就看不懂吧&#xff0c;我接下来举个例子慢慢说 为什么我们需要观察者模式 我们看一个很简…

ubuntu部署haproxy

HAProxy是可提供高可用性、负载均衡以及基于TCP和HTTP应用的代理. 1、更新系统报 通过在终端中运行以下命令&#xff0c;确保所有系统包都是最新的 sudo apt updatesudo apt upgrade2、安装Haproxy sudo apt install haproxy设置开机自动启动haproxy服务 sudo systemctl en…

微服务-Nacos(注册中心)

Nacos是SpringCloud的一个功能非常强大的组件&#xff0c;想比eureka的功能更加丰富 官方的nacos简介 Nacos&#xff08;全称&#xff1a;Naming and Configuration Service&#xff09;是一个开源的动态服务发现、配置管理和服务管理平台。它由阿里巴巴集团开发并贡献给开源…

SpringBoot复习:(51)默认情况下DataSource是怎么创建出来的,是什么类型的?

DataSource是通过DataSourceAutoConfiguration创建的&#xff0c;这个类代码如下&#xff1a; 可以看到DataSourceAutoConfiguration有个静态内部类PooledDataSourceConfiguration,在这个类上有个Import注解&#xff0c;导入了DataSourceConfiguration.Hikari这个类&#xff0…

【学习日记】【FreeRTOS】任务调度时如何考虑任务优先级——任务的自动切换

写在前面 本文开始为 RTOS 加入考虑任务优先级的自动调度算法&#xff0c;代码大部分参考野火。 本文主要是一篇学习笔记&#xff0c;加入了笔者自己对野火代码的梳理和理解。 一、基本思路 首先我们要知道&#xff0c;在 RTOS 中&#xff0c;优先级越高、越需要被先执行的的…

Jmeter对websocket进行测试

JMeterWebSocketSampler-1.0.2-SNAPSHOT.jar下载 公司使用websocket比较奇怪&#xff0c;需要带认证信息进行长连接&#xff0c;通过websocket插件是请求失败&#xff0c;如下图&#xff0c;后面通过代码实现随再打包jar包完成websocket测试 本地实现代码如下&#xff1a; pa…

Maven基础之仓库、命令、插件机制

文章目录 Maven 仓库中央仓库和本地仓库中央仓库本地仓库 Maven 命令generate 命令compile 命令clean 命令test 命令package 命令install 命令 Maven 插件机制官方插件&#xff1a;Compile 插件Tomcat 7 插件 Maven 仓库 中央仓库和本地仓库 [✎] 简单一点说 中央仓库是一个网…

软件测试(黑皮书)学习一

第一部分 软件测试综述 第一章 软件测试背景 1.1软件缺陷&#xff08;software bug&#xff09; 软件失败的术语 故障&#xff08;fault&#xff09;失败&#xff08;failure&#xff09; 缺点&#xff08;defect&#xff09; ------严重、危险异常&#xff08;anomaly&…

7. 实现 API 自动生成

目录 1. pom.xml中引用依赖 2. 引入相关的依赖 3. 编写配置类 4. application.yml 中添加配置 5. API 常用注解 6. 访问 API 列表 7. API 导入 Postman 使用 Springfox Swagger生成 API&#xff0c;并导入 Postman&#xff0c;完成API单元测试。 Swagger 简介&#xff1a;Swag…

【Docker】Docker安装 MySQL 8.0,简洁版-快速安装使用

今天&#xff0c;使用docker安装mysql数据库进行一个测试&#xff0c;结果网上找了一篇文章&#xff0c;然后。。。。坑死我… 特总结本篇安装教程&#xff0c;主打一个废话不多说&#xff01; 坑&#xff1a;安装成功&#xff0c;客户端工具连接不上数据库》。。。 正文&…

运营商三要素 API:构建安全高效的身份验证系统

当今数字化的世界中&#xff0c;身份验证是各行各业中至关重要的一环。为了保护用户的隐私和数据安全&#xff0c;企业需要寻求一种既安全可靠又高效便捷的身份验证方式。运营商三要素 API 应运而生&#xff0c;为构建安全高效的身份验证系统提供了有力的解决方案。 运营商三要…

(三) 搞定SOME/IP通信之CommonAPI库

本章主要介绍在SOME/IP通信过程中的另外一个IPC通信利剑&#xff0c;CommonAPI库&#xff0c;文章将从如下几个角度让读者了解什么是CommonAPI, 以及库在实际工作中的作用 文中资源&#xff1a;vsomeipcommonapi指导文档与demo源码 SOME/IP通信之CommonAPI CommonAPI库是什么C…

Android Jetpack Compose 中的分页与缓存展示

Android Jetpack Compose 中的分页与缓存展示 在几乎任何类型的移动项目中&#xff0c;移动开发人员在某个时候都会处理分页数据。如果数据列表太大&#xff0c;无法一次从服务器检索完毕&#xff0c;这就是必需的。因此&#xff0c;我们的后端同事为我们提供了一个端点&#…

基于YOLOv5n/s/m不同参数量级模型开发构建茶叶嫩芽检测识别模型,使用pruning剪枝技术来对模型进行轻量化处理,探索不同剪枝水平下模型性能影响【续】

这里主要是前一篇博文的后续内容&#xff0c;简单回顾一下&#xff1a;本文选取了n/s/m三款不同量级的模型来依次构建训练模型&#xff0c;所有的参数保持同样的设置&#xff0c;之后探索在不同剪枝处理操作下的性能影响。 在上一篇博文中保持30的剪枝程度得到的效果还是比较理…

异步更新队列 - Vue2 响应式

前言 这篇文章分析了 Vue 更新过程中使用的异步更新队列的相关代码。通过对异步更新队列的研究和学习&#xff0c;加深对 Vue 更新机制的理解 什么是异步更新队列 先看看下面的例子&#xff1a; <div id"app"><div id"div" v-if"isShow&…

Vue的鼠标键盘事件

Vue的鼠标键盘事件 原生 鼠标事件(将v-on简写为) click // 点击 dblclick // 双击 mousedown // 按下 mousemove // 移动 mouseleave // 离开 mouseout // 移出 mouseenter // 进入 mouseover // 鼠标悬浮mousedown.left 键盘事件 keydown //键盘按下时触发 keypress …

C#工程建立后修改工程文件名与命名空间

使用之前的项目做二次开发&#xff0c;项目快结束的时候&#xff0c;需要把主项目的名称修改成我们想要的。 之前从来没有这么干过&#xff0c;记录一下。 步骤如下&#xff1a; 1&#xff1a;打开vs2010项目解决方案&#xff0c;重命名&#xff0c;如下图所示&#xff1a; …

微服务-Nacos(配置管理)

配置更改热更新 在Nacos中添加配置信息&#xff1a; 在弹出表单中填写配置信息&#xff1a; 配置获取的步骤如下&#xff1a; 1.引入Nacos的配置管理客户端依赖&#xff08;A、B服务&#xff09;&#xff1a; <!--nacos的配置管理依赖--><dependency><groupId&…

Git使用教程

一&#xff1a;Git是什么&#xff1f; Git是目前世界上最先进的分布式版本控制系统。文章下面有Git常用所有命令 二&#xff1a;SVN与Git的最主要的区别&#xff1f; SVN是集中式版本控制系统&#xff0c;版本库是集中放在中央服务器的&#xff0c;而干活的时候&#xff0c;用…

SQL Developer中的Data Redaction

SQL Developer中的Data Redaction用起来比命令行方便多了。可以选定表或视图&#xff0c;右键点击“遮盖保护”菜单。 但赋权方面有需要注意的地方。 假设Redact Admin是SYS&#xff0c;Redact User是HR。虽然SYS具备所有权限&#xff0c;但还是报以下错误。其实这个错误是针…