美文网首页
Android网络编程

Android网络编程

作者: Anwfly | 来源:发表于2020-10-06 23:15 被阅读0次

    一、后台与APP 交互过程分析

    1 、后台与APP 交互过程分析

    基于http/https协议的app前后台交互包含以下几个步骤:

    1.建立连接:前台后台建立连接。
    2.发送请求:建立连接后,app向后台发送请求。
    3.发送响应:后台处理完请求后,要向app发送响应消息。
    比如:android代表客户端开发,php代表服务端开发。json在其中是一种通用语言的角色。中国人(客户端)和日    本人(服务器)就用英语(json)交流。
    4.断开连接:以上交互完成后可以断开连接了。
    
    img02.jpg

    二、Tomcat基本使用

    1、 Tomcat简介★★★★

    Tomcat服务器由Apache提供,开源免费。由于Sun和其他公司参与到了Tomcat的开发中,所以最新JSP/Servlet规范总是能在Tomcat中体现出来。当前最新版本是Tomcat10,我们课程中使用Tomcat7。Tomcat7支持Servlet3.0,而Tomcat6只支持Servlet2.5!
    访问:http://localhost:8080
    ​ localhost是指访问自己电脑上的tomcat服务器
    格式:http://ip地址:8080,Tomcat默认的端口号是8080,可以修改,打开Tomcat安装路径,%CATALANA_HOME%\conf\server.xml文件:

    img02.png

    2、 Tomcat部署json★★★★

    Tomacat下载安装:

    ​ 下载Tomcat可以到http://tomcat.apache.org下载。
    Tomcat分为安装版和解压版:

    1.安装版:一台电脑上只能安装一个Tomcat;
    2.解压版:无需安装,解压即可用,解压多少份都可以,所以我们选择解压版。
    

    在启动Tomcat之前,我们必须要配置环境变量:

    1.JAVA_HOME:必须先配置JAVA_HOME,因为Tomcat启动需要使用JDK;
    2.CATALANA_HOME:如果是安装版,那么还需要配置这个变量,这个变量用来指定Tomcat的安装路径,例如:F:\apache-tomcat-7.0.42。
    3.启动:进入%CATALANA_HOME%\bin目录,找到startup.bat,双击即可;(linux系统,双击startup.sh)
    4.关闭:进入%CATALANA_HOME%\bin目录,找到shutdown.bat,双击即可;注意:我们必须在启动Tomcat之前把JAVA_HOME配置正确。
    

    启动问题:点击startup.bat后窗口一闪即消失:检查JAVA_HOME环境变量配置是否正确;
    启动成功后再浏览器中访问http://localhost:8080/,如果能看到如下图所示界面,说明Tomcat启动成功。

    img04.jpg

    Tomcat部署json:
    可以在Tomcat安装目录下找到webapps目录,新建一个文件夹,将资源放入文件夹,例如新建res目录,放入class.json资源,访问路径:http://192.168.1.103:8080/res/class.json(192.168.1.103为ip,res为资源目录路径),或者:http://localhost:8080/res/class.json

    三、HttpURLConnection

    1、 HttpURLConnection 简介

    • ​客户端向网络请求数据,需要借助URLConnection。任何网络连接都需要经过socket才能连接,URLConnection 不需要设置socket,所以URLConnection并不是底层的连接,而是在底层连接上的一个请求。这就是为什么URLConneciton只是一个抽象类,自身不能被实例化的原因。URLConnection只能通过url.openConnection()方法创建具体的实例。而HttpURLConnection是URLConnection的子类,加入了http规范相关的操作。

    • ​虽然底层的网络连接可以被多个HttpURLConnection实例共享,但每一个HttpURLConnection实例只能发送一个请求。请求结束之后,应该调用HttpURLConnection实例的InputStream或OutputStream的close()方法以释放请求的网络资源,不过这种方式对于持久化连接没用。对于持久化连接,得用disconnect()方法关闭底层连接的socket。

    • HttpURLConnection是一个抽象类,其对象不能通过构造器直接产生,应用中通常通过URL对象调用openConnection()方法获取。http协议中最常用两种请求方式:get请求和post请求。

    区别:

    1.get请求没有请求体,post请求有请求体
    2.get请求请求参数拼接到url地址上,post请求请求参数通过请求体发送给服务器
    3.get请求的网页可以被收藏,post请求不能被收藏
    4.get请求的url地址限制长度为2048个字符,post请求请求体长度没有限制
    

    2、 HttpURLConnection 获取服务器数据★★★★★

    1. Get请求
    1.首先创建URL对象,注意如果有请求参数应该拼接到这个对象中
      URL url = new URL("http://localhost/day07/AutoLoginServlet?name=zs");
    2.然后获取HttpURLConnection对象,注意需要强转。
      HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    3.设置相关参数
      a)conn.setConnectTimeout(10);//请求超时时间10秒
      b)conn.setUseCaches(false);// 设置是否缓存,不缓存
      c)conn.setRequestMethod("GET");// 可以不写,默认get请求
      d)conn.setDoOutput(true);// 有请求体就要设置为true,默认为false
      e)conn.setDoInput(true);// 有响应体就设置为true,默认为true
      f)conn.connect();//连接服务器,这个方法调用与否都不影响
      g)conn.getResponseCode();//获取响应码,该语句会自动执行连接服务器的动作
    4.获取响应数据
    

    案例代码:

    private void initData() {
      new Thread(new Runnable() {
        @Override
        public void run() {
          try {
            //网址不能写这个,http://localhost:8080/res/class.json,必须使用带ip的地址
            //1.创建URL对象
            URL url = new URL("http://192.168.1.103:8080/res/class.json");
            //2.然后获取HttpURLConnection对象
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //3.获取响应码
            int responseCode = conn.getResponseCode();
            //4.判断响应码,成功的响应码为200
            if (responseCode == HttpURLConnection.HTTP_OK){
              //获取响应码描述信息,可以不写
              String msg = conn.getResponseMessage();
              //获取响应头信息,可以不写
              String field=conn.getHeaderField("content-type");
              Log.d("tag", "msg: "+msg+",field:"+field);
    
              //5.获取输入流
              InputStream is = conn.getInputStream();
              //6.创建输出流
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              byte[] buf = new byte[1024];
              int len = -1;
              while ((len = is.read(buf)) != -1) {
                //7.将输入流数据读取出来写入输出流
                baos.write(buf, 0, len);
              }
              //8.打印数据
              Log.d("tag", "结果:"+baos.toString());
    
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }).start();
    }
    

    *注意:

    1.清单文件添加网络权限
    2.如果模拟器或者真机试Android9.0以上的系统,需要在清单文件中配置支持http网络请求(因为Android9.0开始系统不支持http请求,只支持加密的https请求,如果需要支持http请求,需要做配置)
    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.xts.day09">
        <!--网络权限-->
        <uses-permission android:name="android.permission.INTERNET"/>
    
        <!--android:usesCleartextTraffic="true",android9.0支持http请求配置-->
        <application
            android:usesCleartextTraffic="true"
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>
    
    1. Post请求
      相比get请求,post请求也并无太多不同之处。不同之处主要有,post请求有请求体,必须通过请求体发送请求参数,不能将请求参数拼接到url中。

    这里我们拿一个真实的接口讲解案例

    搜索接口:
    https://www.wanandroid.com/article/query/0/json
    请求方式:post
    参数:k:“android”;  //关键字
    

    案例代码:

    private void query() {
      new Thread(new Runnable() {
        @Override
        public void run() {
          URL url = null;
          try {
            //1.创建URL对象
            url = new URL("https://www.wanandroid.com/article/query/0/json");
            //2.然后获取HttpURLConnection对象
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //3.设置请求方式为post,下面两句代码都要有
            conn.setRequestMethod("POST");
            //4.有请求体就要设置为true,默认为false
            conn.setDoOutput(true);
            //有响应体就设置为true,默认为true
            //conn.setDoInput(true);
            //5.通过请求体发送请求数据
            OutputStream os = conn.getOutputStream();
            os.write(("k=android").getBytes());
            // 如有中文需要url编码
            // String userInfo = "user=" + URLEncoder.encode("zs", "utf-8");
            // os.write(userInfo.getBytes());
            os.flush();
            //6.接收响应信息
            int code = conn.getResponseCode();
            if (code == 200) {
              //7.读取响应信息
              ByteArrayOutputStream baos = new ByteArrayOutputStream();
              InputStream is = conn.getInputStream();
    
              byte[] buf = new byte[1024];
              int len = -1;
              while ((len = is.read(buf)) != -1) {
                baos.write(buf, 0, len);
              }
              Log.d("tag", baos.toString());
    
              //8.关闭资源
              os.close();
              is.close();
            }
            //conn.disconnect();//这个方法调用与否都不影响,彻底关闭网络连接
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }).start();
    }
    

    3、 解析从服务器获取的jsonObject★★★★★

    4、 解析从服务器获取的jsonArray★★★★★

    ​ 返回的数据如果是以“{}”括起来的,那么我们需要使用JSONObject解析,如果是以“[]”括起来的,则需要使用JSONArray,以get请求为例,我们将返回的数据进行解析,服务器返回的json数据如下:

    {"error":false,"results":[{"_id":"5b3ed2d5421aa91cfe803e35","createdAt":"2018-07-06T10:24:21.907Z","desc":"2018-07-06","publishedAt":"2018-07-06T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fszxi9lmmzj30f00jdadv.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b3d883f421aa906e5b3c6f1","createdAt":"2018-07-05T10:53:51.361Z","desc":"2018-07-05","publishedAt":"2018-07-05T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsysqszneoj30hi0pvqb7.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b3ae394421aa906e7db029b","createdAt":"2018-07-03T10:46:44.112Z","desc":"2018-07-03","publishedAt":"2018-07-03T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fswhaqvnobj30sg14hka0.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b398cf8421aa95570db5491","createdAt":"2018-07-02T10:24:56.546Z","desc":"2018-07-02","publishedAt":"2018-07-02T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsvb1xduvaj30u013175p.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b33ccf2421aa95570db5478","createdAt":"2018-06-28T01:44:18.488Z","desc":"2018-06-28","publishedAt":"2018-06-28T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsq9iq8ttrj30k80q9wi4.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b32807e421aa95570db5471","createdAt":"2018-06-27T02:05:50.227Z","desc":"2018-06-27","publishedAt":"2018-06-27T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsp4iok6o4j30j60optbl.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b31aa33421aa9556d2cc4a7","createdAt":"2018-06-26T10:51:31.60Z","desc":"2018-06-26","publishedAt":"2018-06-26T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsoe3k2gkkj30g50niwla.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b2f8847421aa9556b44c666","createdAt":"2018-06-24T20:02:15.413Z","desc":"2018-06-24","publishedAt":"2018-06-25T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsmis4zbe7j30sg16fq9o.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b0d6ac0421aa97efda86560","createdAt":"2018-05-29T22:59:12.622Z","desc":"2018-06-02","publishedAt":"2018-06-22T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1frslruxdr1j30j60ok79c.jpg","used":true,"who":"lijinshanmx"},{"_id":"5b27c7aa421aa923c0fbfda0","createdAt":"2018-06-18T22:54:34.199Z","desc":"2018-06-19","publishedAt":"2018-06-21T00:00:00.0Z","source":"web","type":"\u798f\u5229","url":"http://ww1.sinaimg.cn/large/0065oQSqly1fsfq1k9cb5j30sg0y7q61.jpg","used":true,"who":"lijinshanmx"}]}
    

    分析:

    1.最外层的是{}括起来的,所以返回的数据需要放入JSONObject解析
    2.results对应的value是以[]括起来的,所以对应的value需要放入JSONArray解析
    3.results对应的value集合中,每一个都是使用{}括起来的,所以需要JSONObject去解析
    

    编写实体类Bean,具体代码这里就不贴了,以下是Java原生的解析方式:

    //服务器返回的数据
    String json = baos.toString();
    //创建实体类对象
    Bean bean = new Bean();
    ArrayList<Bean.ResultsBean> list = new ArrayList<>();
    //将list设置到bean中
    bean.setResults(list);
    //JsonObject解析数据
    JSONObject jsonObject = new JSONObject(json);
    //获取到值为boolean类型,key为error的value,
    boolean error = jsonObject.optBoolean("error");
    bean.setError(error);
    //通过格式化json串,我们看到key为results的value是个集合
    JSONArray results = jsonObject.optJSONArray("results");
    //通过for循环将JSONArray中的数据分别取出
    for (int i = 0; i < results.length(); i++) {
        //JSONArray中的每一个元素都是JSONObject
        JSONObject item = (JSONObject) results.get(i);
    
        //获取JSONObject中的每一个key对应的value
        String _id = item.optString("_id");
        String createdAt = item.optString("createdAt");
        String desc = item.optString("desc");
        String publishedAt = item.optString("publishedAt");
        String source = item.optString("source");
        String type = item.optString("type");
        String _url = item.optString("url");
        boolean used = item.optBoolean("used");
        String who = item.optString("who");
    
        //创建一个Bean.ResultsBean,将解析出的数据设置到这个对象中
        Bean.ResultsBean resultsBean = new Bean.ResultsBean();
        resultsBean.set_id(_id);
        resultsBean.setCreatedAt(createdAt);
        resultsBean.setDesc(desc);
        resultsBean.setPublishedAt(publishedAt);
        resultsBean.setSource(source);
        resultsBean.setType(type);
        resultsBean.setUrl(_url);
        resultsBean.setUsed(used);
        resultsBean.setWho(who);
        //将resultsBean 添加到集合中
        list.add(resultsBean);
    }
    
    //打印bean
    Log.d("tag", "list: "+bean.toString());
    

    四、Gson解析json

    1、Gson解析jsonObject★★★★★

    2、 Gson解析jsonArray★★★★★

    ​ 通过上面的案例我们发现,如果自己使用原生的解析,写起来比较费劲,需要判断是jsonObject还是jsonArray,然后再去解析,还需要通过key去解析出对应的value,然后设置到实体类对象中。接下来我们介绍一个工具类Gson,它可以帮助我们解析Json串,省去很多原生解析的麻烦,使用如下:

    1. 添加依赖:

    implementation 'com.google.code.gson:gson:2.8.2'
    

    2. 使用Gson对象将json串解析成实体类:

    //服务器返回的json串
    String json = baos.toString();
    //创建Gson对象
    Gson gson = new Gson();
    //解析,第一个参数:json字符串,第二个参数:实体类对应的class对象
    Bean data = gson.fromJson(json, Bean.class);
    Log.d("tag", "data: "+data.toString());
    

    五、 Handler

    Handler是Android中的消息机制,主要用来做线程之间通信的。在Android中,为了保障线程安全,规定只能由主线程来更新UI信息。而在实际开发中,会经常遇到多个子线程都去操作UI信息的情况,那么就会导致UI线程不安全。这时,我们就需要借助 Handler 作为媒介,让 Handler 通知主线程按顺序一个个去更新UI,避免UI线程不安全。

    1、 子线程给主线程发送数据★★

    2、使用TextView显示获取的json★★★

    1.在Activity中创建Handler对象

    //1.Handler在哪个线程中创建,最终handleMessage处理消息就在哪个线程
    //这里是属于Acivity,是主线程
    Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            //处理消息的回调方法,这里是主线程
            //msg:这个msg就是子线程发送过来的对象
            int what = msg.what;
            if (what == 0){
              //注意,子线程message对象携带的是什么对象,这里拿到的就是什么对象
              //我们子线程传递的是Bean对象,这里可以强转成Bean
              Bean bean = (Bean) msg.obj;
              //将数据设置到TextView上
              mTv.setText(bean.toString());
            }
        }
    };
    

    2.在获取网络数据的子线程中,通过Handler将携带数据的Message对象发送到主线程

    //子线程不能刷新ui,需要将子线程中获取的网络数据发送到主线程
    //2.创建/获取Message对象
    //一般不直接new,会额外消耗内存,
    // Message message = new Message();
    //可以通过Message.obtain()获取Message对象,这个对象是Message消息池中已有的对象
    Message message = Message.obtain();
    //将数据通过message携带过去
    message.obj = bean;
    //可以设置一个what,区分是哪个线程发送的数据
    message.what = 0;
    //通过handler将message发送到主线程
    mHandler.sendMessage(message);
    

    相关文章

      网友评论

          本文标题:Android网络编程

          本文链接:https://www.haomeiwen.com/subject/jpuxpktx.html