Android网络请求心路历程,分布式架构演进+相关笔记参考

// 调用URL的openConnection()方法,获取HttpURLConnection对象
conn = (HttpURLConnection) mURL.openConnection();

conn.setRequestMethod(“POST”);// 设置请求方法为post
conn.setReadTimeout(5000);// 设置读取超时为5秒
conn.setConnectTimeout(10000);// 设置连接网络超时为10秒
conn.setDoOutput(true);// 设置此方法,允许向服务器输出内容

// post请求的参数
String data = content;
// 获得一个输出流,向服务器写数据,默认情况下,系统不允许向服务器输出内容
OutputStream out = conn.getOutputStream();// 获得一个输出流,向服务器写数据
out.write(data.getBytes());
out.flush();
out.close();

int responseCode = conn.getResponseCode();// 调用此方法就不必再使用conn.connect()方法
if (responseCode == 200) {

InputStream is = conn.getInputStream();
String response = getStringFromInputStream(is);
return response;
} else {
throw new NetworkErrorException("response status is "+responseCode);
}

} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();// 关闭连接
}
}

return null;
}

public static String get(String url) {
HttpURLConnection conn = null;
try {
// 利用string url构建URL对象
URL mURL = new URL(url);
conn = (HttpURLConnection) mURL.openConnection();

conn.setRequestMethod(“GET”);
conn.setReadTimeout(5000);
conn.setConnectTimeout(10000);

int responseCode = conn.getResponseCode();
if (responseCode == 200) {

InputStream is = conn.getInputStream();
String response = getStringFromInputStream(is);
return response;
} else {
throw new NetworkErrorException("response status is "+responseCode);
}

} catch (Exception e) {
e.printStackTrace();
} finally {

if (conn != null) {
conn.disconnect();
}
}

return null;
}

private static String getStringFromInputStream(InputStream is)
throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
// 模板代码 必须熟练
byte[] buffer = new byte[1024];
int len = -1;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
is.close();
String state = os.toString();// 把流中的数据转换成字符串,采用的编码是utf-8(模拟器默认编码)
os.close();
return state;
}
}

注意网络权限!被坑了多少次。

同步&异步

这2个概念仅存在于多线程编程中。
android中默认只有一个主线程,也叫UI线程。因为View绘制只能在这个线程内进行。
所以如果你阻塞了(某些操作使这个线程在此处运行了N秒)这个线程,这期间View绘制将不能进行,UI就会卡。所以要极力避免在UI线程进行耗时操作。
网络请求是一个典型耗时操作。
通过上面的Utils类进行网络请求只有一行代码。

NetUtils.get(“http://www.baidu.com”);//这行代码将执行几百毫秒。

如果你这样写

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String response = Utils.get(“http://www.baidu.com”);
}

就会死。。
这就是同步方式。直接耗时操作阻塞线程直到数据接收完毕然后返回。Android不允许的。
异步方式:

//在主线程new的Handler,就会在主线程进行后续处理。
private Handler handler = new Handler();
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text);
new Thread(new Runnable() {
@Override
public void run() {
//从网络获取数据
final String response = NetUtils.get(“http://www.baidu.com”);
//向Handler发送处理操作
handler.post(new Runnable() {
@Override
public void run() {
//在UI线程更新UI
textView.setText(response);
}
});
}
}).start();
}

在子线程进行耗时操作,完成后通过Handler将更新UI的操作发送到主线程执行。这就叫异步。Handler是一个Android线程模型中重要的东西,与网络无关便不说了。关于Handler不了解就先去Google一下。
关于Handler原理一篇不错的文章

但这样写好难看。异步通常伴随者他的好基友回调
这是通过回调封装的Utils类。

public class AsynNetUtils {
public interface Callback{
void onResponse(String response);
}

public static void get(final String url, final Callback callback){
final Handler handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
final String response = NetUtils.get(url);
handler.post(new Runnable() {
@Override
public void run() {
callback.onResponse(response);
}
});
}
}).start();
}

public static void post(final String url, final String content, final Callback callback){
final Handler handler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
final String response = NetUtils.post(url,content);
handler.post(new Runnable() {
@Override
public void run() {
callback.onResponse(response);
}
});
}
}).start();
}
}

然后使用方法。

private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.webview);
AsynNetUtils.get(“http://www.baidu.com”, new AsynNetUtils.Callback() {
@Override
public void onResponse(String response) {
textView.setText(response);
}
});

是不是优雅很多。
嗯,一个蠢到哭的网络请求方案成型了。
愚蠢的地方有很多:

  • 每次都new Thread,new Handler消耗过大
  • 没有异常处理机制
  • 没有缓存机制
  • 没有完善的API(请求头,参数,编码,拦截器等)与调试模式
  • 没有Https

HTTP缓存机制

缓存对于移动端是非常重要的存在。

  • 减少请求次数,减小服务器压力.
  • 本地数据读取速度更快,让页面不会空白几百毫秒。
  • 在无网络的情况下提供数据。

缓存一般由服务器控制(通过某些方式可以本地控制缓存,比如向过滤器添加缓存控制信息)。通过在请求头添加下面几个字端:

Request

请求头字段意义
If-Modified-Since: Sun, 03 Jan 2016 03:47:16 GMT缓存文件的最后修改时间。
If-None-Match: “3415g77s19tc3:0”缓存文件的Etag(Hash)值
Cache-Control: no-cache不使用缓存
Pragma: no-cache不使用缓存

Response

响应头字段意义
Cache-Control: public响应被共有缓存,移动端无用
Cache-Control: private响应被私有缓存,移动端无用
Cache-Control:no-cache不缓存
Cache-Control:no-store不缓存
Cache-Control: max-age=6060秒之后缓存过期(相对时间)
Date: Sun, 03 Jan 2016 04:07:01 GMT当前response发送的时间
Expires: Sun, 03 Jan 2016 07:07:01 GMT缓存过期的时间(绝对时间)
Last-Modified: Sun, 03 Jan 2016 04:07:01 GMT服务器端文件的最后修改时间
ETag: “3415g77s19tc3:0”服务器端文件的Etag[Hash]值

正式使用时按需求也许只包含其中部分字段。
客户端要根据这些信息储存这次请求信息。
然后在客户端发起请求的时候要检查缓存。遵循下面步骤:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传浏览器缓存机制

注意服务器返回304意思是数据没有变动滚去读缓存信息。 曾经年轻的我为自己写的网络请求框架添加完善了缓存机制,还沾沾自喜,直到有一天我看到了下面2个东西。(/TДT)/

Volley&OkHttp

Volley&OkHttp应该是现在最常用的网络请求库。用法也非常相似。都是用构造请求加入请求队列的方式管理网络请求。

先说Volley:
Volley可以通过这个库进行依赖.
Volley在Android 2.3及以上版本,使用的是HttpURLConnection,而在Android 2.2及以下版本,使用的是HttpClient。
Volley的基本用法,网上资料无数,这里推荐郭霖大神的博客
Volley存在一个缓存线程,一个网络请求线程池(默认4个线程)。
Volley这样直接用开发效率会比较低,我将我使用Volley时的各种技巧封装成了一个库 RequestVolly.
我在这个库中将构造请求的方式封装为了函数式调用。维持一个全局的请求队列,拓展一些方便的API。

不过再怎么封装Volley在功能拓展性上始终无法与OkHttp相比。
Volley停止了更新,而OkHttp得到了官方的认可,并在不断优化。
因此我最终替换为了OkHttp

OkHttp用法见这里
很友好的API与详尽的文档。
这篇文章也写的很详细了。
OkHttp使用 Okio进行数据传输。都是Square家的。
但并不是直接用OkHttp。Square公司还出了一个Retrofit库配合OkHttp战斗力翻倍。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
img

总结

写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的GitHub免费获取。
还有免费的高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。

关于Flutter的学习思路及方向,从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的GitHub免费获取。
还有免费的高级UI、性能优化、架构师课程、NDK、混合式开发(ReactNative+Weex)微信小程序、Flutter全方面的Android进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。**

跨平台开发:Flutter.png

  • 21
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值