Android网络编程基础(第一弹)

Java 原生API进行网络请求

先了解底层,才能更好地上手Android网络请求框架。

一、android使用Java原生API进行网络请求的步骤

  1. 声明网络权限

    <uses-permission android:name="android.permission.INTERNET"/>
    
  2. 使用HttpURLConnection进行网络请求,子线程中请求数据,android不允许在Main-Thread中执行耗时操作,防止ANR。对于Java网络编程不熟悉的可以转到这是属于你的频道

    URL url;
    // 使用URLConnection的衍生类 HttpURLConnection
    HttpURLConnection connection;
    try {
        url = new URL("https://www.sunofbeach.net/content/content/moment/list/1153952789488054272/1");
        connection = (HttpURLConnection) url.openConnection();
        // 设置请求参数
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(1000);
        connection.setRequestProperty("accept", "*/*");
        connection.setRequestProperty("connection", "keep-alive");
        connection.setRequestProperty("Accept-Language", "zh-CN,zh");
        // 开始连接,也可以不设置,当获取流的时候,会建立连接
        connection.connect();
        // 获取响应码,HttpURLConnection特有方法
        int responseCode = connection.getResponseCode();
        Log.d(TAG, "responseCode-->" + responseCode);
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream in = connection.getInputStream();
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
            String res = bufferedReader.readLine();
            Log.d(TAG, "responseData: "+res);
            bufferedReader.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    

    对于https请求以上程序是没有问题,但是对于http请求android版本的不同对网络请求的行为进行了相应的变更,对于android8.0(API27)以上,是不允许http请求的,因为http请求消息是不经过加密处理的即明文传输(cleartextTraffic),目的为了更好的保证应用程序的安全,保证用户隐私。但是Android8.0(opera)以下是可以直接进行http请求的,详情信息请移步应用安全性最佳做法

    https由底层的SSL(安全套接层)所支撑,保证了应用程序间进行通信的安全性。但互联网并非所有的链接都是https,android对于http请求的安全性是如何进行处理的,请看如下解决方案。

二、android高版本http网络请求的处理

  1. 降维度,即降低API版本,targetSdkVersion <= 27显然这不太合乎常规,机器是要进化的,高版本兼容低版本,特殊情况,但这也绝非不可。

  2. Manifest.xml的application标签中添加android:usesCleartextTraffic="true"最方便也是最有效的方案。世界上没有绝对安全的系统,这种方案带来的缺陷也显而易见。

  3. 添加网络配置文件network_security_config.xml,比较安全的方案。因为在配置文件中可以指定,信任那些站点,还可以信任某个域以及子域。

    步骤:res下新建xml目录,目录下新建network_security_config.xml,配置如下内容,然后再Manifest.xml的application标签中添加android:networkSecurityConfig="@xml/network_security_config"

    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <!--应用范围内定义-->
        <base-config cleartextTrafficPermitted="true"/>
        <!--网络范围内定义-->
        <!--<domain-config>
            <domain includeSubdomains="true">example.com</domain>
            <domain-config>
            </domain-config>
        </domain-config>-->
    </network-security-config>
    

reminder:对于开发中网络请求的问题,我们应该想到是不是请求权限的问题,http的原因,https不用考 虑太多;比如以后即将用到的OKHttp框架,还是正在当下的Glide图片加载框架,Glide.load(url)图片没有加 载成功,是不是http请求所导致等thinking and study

三、网络请求后回显数据的处理

​ 现在开发请求后端接口,返回的数据大多都是JSON格式的数据了吧,如果还生活在传递xml格式的石器时代,那么雨我无瓜。那么我们拿到后台数据之后,要干什么,如何去做?无非就是下面两点:

  1. 后台数据格式化(JSON >> JavaBean)

    如果后台数据量很大,JSON转JavaBean是一个很繁琐无脑的工作,这里推荐插件GsonFormat,类似于Mybatis-Generator、EasyCode等逆向工程插件。安装步骤这里就不在介绍了,plugins >> MarketExplore >> GsonFormat >> download,很好,一如既往的安装失败!在这给出离线安装jar包,拿去不客气密码:enjh。安装成功后,在所在类直接一顿快捷键*[alt + insert]* 就可以看到GsonFormt选项了,将json格式的数据复制到里面然后根据需要字段生成对应的类即可。

    JSON >> JavaBean:

    1.1)添加Gson依赖implementation 'com.google.code.gson:gson:2.8.5'如果是在project structure下app里面搜索添加的依赖,因为搜索之后会有多个版本,如果依赖下载失败,那么可以尝试一下其他版本。

    1.2)Gson的使用,如果添加依赖成功,但是Gson没有该类,rebuild尝试一下!

    Gson gson = new Gson();
    JavaBean bean = gson.fromJson(JSONData, JavaBean.class);
    
  2. 更新UI

    android里面子线程不可以直接更新UI,要想更新UI两种方法:

    2.1) runOnUIThread

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // 请求数据完成,装载数据,更新UI 
            ...
        }
    });
    

    2.2)使用Handler

四、请求图片数据的处理

​ 了解了使用java api进行网络请求json格式数据的过程之后,图片数据的处理过程与文本格式稍微有所不同,但是传输过程中还是变成了字节流进行的传输,底层还是01010…,因为图片分辨率不同导致图片所占的内存大小也就有所差异,对于大图片要适当的进行处理防止OOM(Out Of Memory),所以我们可以使用BitmapFactory.Options.inSampleSize按照一定的采样率加载缩小后的图片,将缩小后的图片在ImageView中显示,这样就能降低内存占用,在一定程度上避免OOM,提高bitma加载时候的性能。在做项目中,应该都会有缩略图,比如一个商品列表,不可能上来就请求原图,这么多商品图片被请求,不崩才怪呢!所以说,缩略图是一种解决方案,当用户点击了某个商品之后,进入商品详情图,这时候请求商品原图给用户是一种很好的方式。

  1. 请求一张图片,主要是底层IO流的操作,还有借助BitmapFactory.decodeStream(InputStream in)实例化Bitmap对象。

    URL url = new URL("image url");
    
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    connection.setRequestMethod("GET");
    connection.setConnectTimeout(1000);
    connection.setRequestProperty("accept", "*/*");
    connection.setRequestProperty("connection", "keep-alive");
    connection.setRequestProperty("Accept-Language", "zh-CN,zh");
    
    if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
        InputStream in = connection.getInputStream();
        final Bitmap bitmap = BitmapFactory.decodeStream(in);
        // 更新UI
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ImageView imageView = findViewById(R.id.image_view);
                imageView.setImageBitmap(bitmap);
            }
        });
    
    }
    
  2. Android图片采样缩放对大图处理,防止OOM

    ​ 假设通过imageView来显示图片,很多时候ImageView并没有图片的原始尺寸那么大,这时候把整张图片加载进来后再设给ImageView是没有必要的,因为ImagView并没有办法显示原始的图片。

    2.1)BitmapFactory.Options.inSampleSize(采样率)

    inSampleSize = 1 //采样后图片大小=原始图片大小
    inSampleSize = 2 //那么采样后图片宽高均为原始图片的1/2,像素为原图的1/4,占有的内存大小为原图的1/4。
    例如:一张的图片占有内存1024*1024*4=4M,用采样率为2采样后内存占用为512*512*4=1M。
    

    inSampleSize是必须大于1的整数才有效果,小与1就相当于1,并且同时作用于宽高,所以缩放后的图片大小以采样率的2次方形式递减.根据最新的官方文档,inSampleSize的取值应该总是为2的指数,若给系统的inSampleSize不为2的指数,那么系统会向下取整并且选择一个最接近2的指数来代替,不过经过验证,这个结论并不是在所有的Android版本上都成立。

    2.2)获取采样率

    1、将BitmapFactory.Option的inJustDecodeBound参数设为true,加载图片,这个时候图片并没有加载进内存,仅仅是去解析图片原始宽高信息而已。

    2、从BitmapFactory.Option取出图片的原始宽高信息,对应于outWidth,outHeight参数。

    3、根据采样率的规则和目标原始View的所需大小计算出采样率inSampleSize。

    4、将BitmapFactory.Option的inJustDecodeBound参数设为false,重新加载图片,这时候图片才真正被载进内存。

    在没有进行采样压缩之前的图片

    // 下面将一张6.04MB的图片加载内存,运行后
    // 抛出java.lang.RuntimeException: Canvas: trying to draw too large(336063168bytes) bitmap.
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.large);
    ImageView imageView = findViewById(R.id.image_view);
    imageView.setImageBitmap(bitmap);
    

    经过采样压缩处理的图片

    ImageView imageView = findViewById(R.id.image_view);
    int height = imageView.getMeasuredHeight();
    int width = imageView.getMeasuredWidth();
    Log.d(TAG, "控件的宽高 " + "宽:" + width + " 高:" + height);
    BitmapFactory.Options options = new BitmapFactory.Options();
    // 图片不加载进内存,只解析图片宽高等信息 --> options
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(getResources(), R.drawable.large, options);
    int inSampleSize = 1;
    int scaleX,scaleY;//缩放比
    int outWidth = options.outWidth;
    int outHeight = options.outHeight;
    Log.d(TAG, "原始图片大小 " + "宽:" + outWidth + " 高:" + outHeight);
    if (outWidth > width || outHeight > height) {
        scaleX = outWidth / width;
        scaleY = outHeight / height;
        inSampleSize = scaleX > scaleY ? scaleX : scaleY;
        // 设置新的缩放比
        options.inSampleSize = inSampleSize;
    }
    Log.d(TAG, "缩放比:" + inSampleSize);
    // 将接下来的图片加载内存
    options.inJustDecodeBounds = false;
    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.large, options);
    imageView.setImageBitmap(bitmap);
    
    // log --->
    // 控件的宽高 宽:1080 高:788
    // 原始图片大小 宽:4032 高:3024
    // 缩放比:3
    

    帅哥美女,如果小二本篇文章对您有所帮助,请给小二一个👍、⭐️。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值