zoukankan      html  css  js  c++  java
  • 安卓网络编程学习(1)——java原生网络编程(1)

    写在前面

    马上要进行第二轮冲刺,考虑到自己的APP在第一轮冲刺的效果不尽人意,有很多网络方面的小BUG,这里就系统学习一下网络编程,了解来龙去脉,以便更好的对项目进行优化处理。

    http协议

    http协议的定义和工作流程

    要进行http请求,首先要知道什么是http协议。http是什么意思?HyperText Transfer Protocol 翻译过来就是超文本传输协议。协议就是约定的意思,内容是Http相关的格式,http协议是基于TCP/IP协议之上的应用层协议。这就涉及到计算机网络的知识了,但奈何我的计算机网络不是很好,就不班门弄斧了。那么http协议是如何工作的呢?如下图:

    客户端发起请求(request)到服务器,服务器响应请求(response)到客户端。我们一直在做的APP其实就是客户端,负责发起请求然后接受内容。类似的,我们的网页也是一个客户端,发起请求然后接收内容。可能这也是为什么现在能够做到写一个web前端就能同时部署到手机端和桌面端的原因吧。

    http协议的常用请求方式

    在之前学习java web的过程中,了解到了get和post这两种最常用的,其实还有put delete head trace options connect,但对于我们做客户端开发,只要了解前面的四种即可了。一般来说,get用于请求数据,post用于提交数据,put用于更新数据,delete用于删除数据。
    关于http其他的知识,之前学习java web时已经基本了解过了,这里就不再过多阐述了。

    使用java的api发起网络请求

    这里我们使用阳光沙滩网站提供的API,可以让你在本地架设一个服务器,类似tomcat.具体的原理我也不大懂.
    clone完之后我们用java -jar启动该jar包即可。


    出现你放API的地址即说明部署成功了。

    事不宜迟,先贴代码:

    new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        URL url = new URL("http://10.0.2.2:9102/get/text");
                        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                        connection.setRequestMethod("GET");
                        connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                        connection.setRequestProperty("Accept","*/*");
                        connection.connect();
                        //结果码
                        int responseCode = connection.getResponseCode();
                        if(responseCode==200){
                            Map<String, List<String>> headerFields = connection.getHeaderFields();
                            Set<Map.Entry<String, List<String>>> entries = headerFields.entrySet();
                            for(Map.Entry<String,List<String>> entry:entries){
                                Log.d(TAG,entry.getKey()+"=="+entry.getValue());
                            }
                            InputStream inputStream = connection.getInputStream();
                            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                            String json = bufferedReader.readLine();
                            //Log.d(TAG,"json -->"+json);
                            Gson gson = new Gson();
                            GetTextItem getTextItem = gson.fromJson(json, GetTextItem.class);
                            updateUI(getTextItem);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
    

    代码解析

    我们请求数据不能在主线程进行,需要新建一个子线程,但实际开发中不建议如此使用,这里主要为了学习java API
    可以看到,我们首先定义了一个URL,然后把请求地址放进去,新建一个连接并返回成HttpURLConnection类型,通过这个对象来设置请求参数,并用connect()方法来发出请求。
    而后通过返回响应码来确定是否请求成功,若成功则提取数据并用GSON转成相应的json数据,输出。

    注意事项

    要发起网络请求,首先需要在manifest中设置网络权限:

    <uses-permission android:name="android.permission.INTERNET" />
    

    但这样还不够,由于我们的安卓在某个版本后不再支持访问http类型的地址了,想要访问需要进行配置,可以这样设置:

        <application
            android:usesCleartextTraffic="true"
    

    但这样配置过于简略,我们可以设置xml配置文件来进行详细的配置,如:

    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
            <base-config cleartextTrafficPermitted="true"/>
    </network-security-config>
    

    然后在manifest中使用:

    android:networkSecurityConfig="@xml/network_security_config"
    

    也要放到application标签中。
    Tips1:如果发现配置好了还是无法使用,请把APP卸载再安装,有奇效哦!
    Tips2:这里使用了Gsonformat来生成bean类,这是一个输入json就可以自动生成bean类的插件,建议百度下载。

    使用java原生API请求图片

    在上面的操作里,我们使用了glide工具包来帮我们处理图片的载入,那我们如何使用java API来实现呢?接下来我们来简单的处理一下:

       new Thread(new Runnable() {
                @Override
                public void run() {
                  try {
                       URL url = new URL("https://cdn.sunofbeaches.com/images/ad/shop-ad.png");
                        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                       connection.setRequestMethod("GET");
                       connection.setRequestProperty("Accept-Language","zh-CN,zh;q=0.9");
                        connection.setRequestProperty("Accept","*/*");
                      connection.connect();
                       int responseCode = connection.getResponseCode();
                      if(responseCode==HttpURLConnection.HTTP_OK){
                           InputStream inputStream = connection.getInputStream();
                          //转成BitMap
                       final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                            //更新UI,要在主线程
                         runOnUiThread(new Runnable() {
                             @Override
                               public void run() {
                                 ImageView imageView = findViewById(R.id.result_image);
                                 imageView.setImageBitmap(bitmap);
                              }
                           });
                      }
                   } catch (Exception e) {
                        e.printStackTrace();
                  }
                    runOnUiThread(new Runnable() {
                       @Override
                       public void run() {                  
     }
                  });
               }
            }).start();
    

    获取到内容后,转成bitmap然后设置到Image即可。但这样的用法并不值得被提倡,因为如果我们的图片过大,甚至会导致我们的APP崩掉,我们要对其进行一定的压缩,压缩到适合我们APP使用的大小。
    下面是一段常见的算法:

            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            //拿到图片的大小
            BitmapFactory.decodeResource(getResources(), R.mipmap.test_pic,options);
            ImageView imageView = findViewById(R.id.result_image);
             int outHeight = options.outHeight;
            int outWidth = options.outWidth;
            Log.d(TAG,"outHeight ==>"+outHeight);
            Log.d(TAG,"outWidth ==>"+outWidth);
            //拿控件的尺寸
            int measuredHeight = imageView.getMeasuredHeight();
            int measuredWidth = imageView.getMeasuredWidth();
            //
            Log.d(TAG,"measuredHeight ==>"+measuredHeight);
            Log.d(TAG,"measuredWidth ==>"+measuredWidth);
            options.inSampleSize  =  1;
            //图片的宽度/控件的宽度
            // 图片的高度/控件的高度
            //取两者之间的小值
            if(outHeight > measuredHeight || outWidth > measuredWidth){
                int subHeight = outHeight/measuredHeight;
                int subWidth = outWidth/measuredWidth;
                options.inSampleSize = subHeight > subWidth ?subWidth:subHeight;
            }
            options.inJustDecodeBounds = false;
            Log.d(TAG,"inSampleSize ==>"+options.inSampleSize);
        //根据控件大小,动态地计算sample值
            final Bitmap bigImage = BitmapFactory.decodeResource(getResources(), R.mipmap.test_pic,options);
    
            imageView.setImageBitmap(bigImage);
    

    这里通过计算比例得到一个相对合适的比例值,然后再将这个bitmap设置给image控件。这就是安卓大图片的处理方式了。
    实际开发中,我们都会用开源框架来解决,比如glide,XUtils等等。框架能做的事要更多,但基本的还是离不开这些。

    总结

    主要是简单学习了一下如何使用java原声API来请求(get)数据。为了不让博客太长,把其余一些内容放置到下篇博客了。
    希望学习了之后能够更好的开发我们自己的APP。

  • 相关阅读:
    JS LeetCode 1423. 可获得的最大点数简单题解
    SpringBoot 学集 (第六章) Docker
    Linux 学记 (第三章)
    Linux 学记 (第二章)
    Linux 学记 (第一章)
    SpringBoot 学集 (第五章) Web开发续
    SpringBoot 学集 (第四章)Web开发
    SpringBoot 学集 (第三章) 日志框架
    SpringBoot 学集 (第二章) 配置文件
    SpringBoot 学集 (第一章)
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/12937531.html
Copyright © 2011-2022 走看看