- 发送/接收数据
在成功建立连接之后,就可以愉快地跟服务器交互,进行组装数据、发送数据、接收数据、解析数据。我们关注的是,如何根据网络状况将带宽利用好,怎样快速地侦测到网络延时,在弱网络下如何调整包大小等问题。
- 关闭连接
连接的关闭看起来非常简单,其实这里的水也很深。这里主要关注主动关闭和被动关闭两种情况,一般我们都希望客户端可以主动关闭连接。
所谓网络优化,就是围绕速度、弱网络、安全这三个核心内容,减少每一个步骤的耗时,打造快速、稳定且安全的高质量网络。
在实际的开发工作中,我们很少会像《UNIX 网络编程》那样直接去操作底层的网络接口,一般都会使用网络库。Square 出品的 OkHttp 是目前最流行的 Android 网络库,它还被 Google 加入到 Android 系统内部,为广大开发者提供网络服务。
网络库屏蔽的下层复杂的网络接口,让我们可以更高效的使用网络请求,极大的提高了我们的开发效率。我经常看到一些开发者会使用基于网络库再次封装的开源库,这里很不建议开发者使用这些库。
首先不清楚这些库是否能完全符合我们的需求;然后这些库的质量参差不齐,往往在使用中遇到问题无法快速修复。这里强烈建议大家使用一手资源,推荐自己封装,不仅可以提升开发效率,还可以提高下自己的编码水平。
大平台网络库
据了解业内大厂蘑菇街、头条、UC 浏览器都在 Chromium 网络库上做了二次开发,而微信 Mars 在弱网络方面做了大量优化,拼多多、虎牙、链家、美丽说这些应用都在使用 Mars。
下面我们来一起对比下各个网络库的核心实现。
为什么大厂都不使用 OkHttp 呢?主要是因为它不支持跨平台,对于大型应用来说跨平台是非常重要的。我们不希望所有的优化 Android 和 iOS 都要各自去实现一套,不仅浪费人力而且还容易出现问题。
对于大厂来说,不能只局限在客户端网络库的双端统一上,网络优化不仅仅是客户端的事情,所以一般都有统一的网络中台,它负责提供前台一整套网络解决方案。
阿里的 ACCS、蚂蚁的 mPaas、携程的网络服务都是公司级的网络中台服务,这样所有的网络优化可以让整个集团的所有接入应用受益。
根据网络状态对网络请求进行区别对待,2G 与 WiFi 状态下网络质量肯定是不一样的,那对应的网络策略也应该是不一样的。
例如:在 WiFi 场景下可以进行数据的预取、一些统计的集中上传等;而在 2G 场景下此类操作以及网络请求的次数策略都应该调低。
网络是否连接
通过 ConnectivityManager 可以获取当前是否已连接网络。
public static boolean isNetworkConnected(Context context) {
if (context == null) returnfalse;
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (manager == null) returnfalse;
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
if (networkInfo == null) returnfalse;
return networkInfo.isAvailable() && networkInfo.isConnected();
}
isAvailable() 与 isConnected() 的区别:
| 状态 | isConnected() | isAvailable() |
| — | — | — |
| 显示连接已保存,但标题栏没有,即没有实质连接上 | false | true |
| 显示连接已保存,标题栏也有已连接上的图标 | true | true |
| 选择不保存后 | false | true |
| 选择连接,在正在获取 IP 地址时 | false | false |
网络连接类型
通过 NetworkInfo 中的 getNetworkType() 方法可以获取当前网络类型。
public static final int NETWORK_NONE = 0;
public static final int NETWORK_WIFI = 1;
public static final int NETWORK_MOBILE = 10;
public static final int NETWORK_2G = 12;
public static final int NETWORK_3G = 13;
public static final int NETWORK_4G = 14;
/**
-
获取当前的网络状态
-
@param context
-
@return 没有网络:0; WIFI:1; 手机网络:10; 2G:12; 3G:13; 4G:14;
*/
public static int getNetworkType(Context context) {
ConnectivityManager connectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager == null) return NETWORK_NONE;
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isAvailable())
return NETWORK_NONE;
int type = networkInfo.getType();
if (type == ConnectivityManager.TYPE_WIFI) {
return NETWORK_WIFI; // WiFi
}
if (type == ConnectivityManager.TYPE_MOBILE) {
TelephonyManager telephonyManager = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyManager == null) return NETWORK_NONE;
int networkType = telephonyManager.getNetworkType();
switch (networkType) {
// 2G
case TelephonyManager.NETWORK_TYPE_GPRS:
case TelephonyManager.NETWORK_TYPE_CDMA:
case TelephonyManager.NETWORK_TYPE_EDGE:
case TelephonyManager.NETWORK_TYPE_1xRTT:
case TelephonyManager.NETWORK_TYPE_IDEN:
return NETWORK_2G;
// 3G
case TelephonyManager.NETWORK_TYPE_EVDO_A:
case TelephonyManager.NETWORK_TYPE_UMTS:
case TelephonyManager.NETWORK_TYPE_EVDO_0:
case TelephonyManager.NETWORK_TYPE_HSDPA:
case TelephonyManager.NETWORK_TYPE_HSUPA:
case TelephonyManager.NETWORK_TYPE_HSPA:
case TelephonyManager.NETWORK_TYPE_EVDO_B:
case TelephonyManager.NETWORK_TYPE_EHRPD:
case TelephonyManager.NETWORK_TYPE_HSPAP:
return NETWORK_3G;
// 4G
case TelephonyManager.NETWORK_TYPE_LTE:
return NETWORK_4G;
default:
return NETWORK_MOBILE;
}
}
return NETWORK_NONE;
}
监听网络变化
首先,创建一个 NetworkReceiver。
public class NetworkReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(“NetworkReceiver”, “网络发生变化”);
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
int networkType = NetworkUtil.getNetworkType(context);
Log.e(“NetworkReceiver”, "networkType = " + networkType);
Toast.makeText(context, “当前网络:” + networkType,
Toast.LENGTH_SHORT).show();
}
}
}
然后,在 AndroidManifest.xml 文件中注册 NetworkReceiver。
并添加监听网络需要的相关权限。
在 Android 7.0 之后静态注册广播的方式被取消了,所以我们这里还需要采用动态注册的方
在 Android 7.0 之后静态注册广播的方式被取消了,所以我们这里还需要采用动态注册的方式。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
NetworkReceiver networkReceiver = new NetworkReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
registerReceiver(networkReceiver, filter);
}
设置网络缓存
在一定时间内,对服务端返回的数据进行缓存,比如一些接口的数据不会更新(10 分钟或更久变化一次),我们就可以缓存该接口的数据,设定有效时间,可以减少不必要的流量消耗。
Android 系统上关于网络请求的 Http Response Cache 是默认关闭的,这样会导致每次即使请求的数据内容是一样的也会需要重复被调用执行,效率低下。
我们可以通过下面的代码示例开启 HttpResponseCache。
protected void onCreate(Bundle savedInstanceState) {
// …
try {
File httpCacheDir = new File(context.getCacheDir(), “http”);
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) {
Log.i(TAG, “HTTP response cache installation failed:” + e);
}
}
protected void onStop() {
// …
HttpResponseCache cache = HttpResponseCache.getInstalled();
if (cache != null) {
cache.flush();
}
}
开启 Http Response Cache 之后,Http 操作相关的返回数据就会缓存到文件系统上,不仅仅是主程序自己编写的网络请求相关的数据会被缓存,另外引入的 library 库中的网络相关的请求数据也会被缓存到这个 Cache 中。
备注:如果全部自己从头开始写会比较繁琐复杂,有不少著名的开源框架 Volley、Okhttp 都很好的支持实现自定义缓存。
为了能够减小网络传输的数据量,我们需要对传输的数据做压缩的处理,这样能够提高网络操作的性能。首先不同的网络环境,下载速度以及网络延迟是存在差异的,如下图所示:
如果我们选择在网速更低的网络环境下进行数据传输,这就意味着需要执行更长的时间,而更长的网络操作行为,会导致电量消耗更加严重。另外传输的数据如果不做压缩处理,也同样会增加网络传输的时间,消耗更多的电量。不仅如此,未经过压缩的数据,也会消耗更多的流量,使得用户需要付出更多的流量费。
最后
由于题目很多整理答案的工作量太大,所以仅限于提供知识点,详细的很多问题和参考答案我都整理成了 PDF文件
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
oss-process=image/format,png)
如果我们选择在网速更低的网络环境下进行数据传输,这就意味着需要执行更长的时间,而更长的网络操作行为,会导致电量消耗更加严重。另外传输的数据如果不做压缩处理,也同样会增加网络传输的时间,消耗更多的电量。不仅如此,未经过压缩的数据,也会消耗更多的流量,使得用户需要付出更多的流量费。
最后
由于题目很多整理答案的工作量太大,所以仅限于提供知识点,详细的很多问题和参考答案我都整理成了 PDF文件
[外链图片转存中…(img-5kcfKD4x-1715357351461)]
[外链图片转存中…(img-pHGkNRiE-1715357351462)]
[外链图片转存中…(img-q0gSMcrY-1715357351463)]
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!