Java 原生API进行网络请求
先了解底层,才能更好地上手Android网络请求框架。
一、android使用Java原生API进行网络请求的步骤
-
声明网络权限
<uses-permission android:name="android.permission.INTERNET"/>
-
使用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网络请求的处理
-
降维度,即降低API版本,
targetSdkVersion <= 27
显然这不太合乎常规,机器是要进化的,高版本兼容低版本,特殊情况,但这也绝非不可。 -
Manifest.xml的application标签中添加
android:usesCleartextTraffic="true"
,最方便也是最有效的方案。世界上没有绝对安全的系统,这种方案带来的缺陷也显而易见。 -
添加网络配置文件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格式的石器时代,那么雨我无瓜。那么我们拿到后台数据之后,要干什么,如何去做?无非就是下面两点:
-
后台数据格式化(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);
-
更新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加载时候的性能。在做项目中,应该都会有缩略图,比如一个商品列表,不可能上来就请求原图,这么多商品图片被请求,不崩才怪呢!所以说,缩略图是一种解决方案,当用户点击了某个商品之后,进入商品详情图,这时候请求商品原图给用户是一种很好的方式。
-
请求一张图片,主要是底层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); } }); }
-
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
帅哥美女,如果小二本篇文章对您有所帮助,请给小二一个👍、⭐️。