nohttp请求的返回值的what的值可以一样吗

您的位置: &
& NoHttp详解之NoHttp最基本使用
NoHttp最基本使用
(NoHttp QQ交流群:, NoHttp官方 E-mail: )
NoHttp是一个专门做Android网络相关的框架.
本文章demo下载
本文demo源码下载地址:
本文的例子来自上面的demo中的OriginalActivity中
对于新手, 看别人封装好的代码允许要稍微吃力一点, 尤其是一个框架, 那么NoHttp最原始的使用方法是什么样的呢?
public class OriginalActivity extends BaseActivity implements View.OnClickListener {
* 用来标志请求的what, 类似handler的what一样,这里用来区分请求
private static final int NOHTTP_WHAT_TEST = 0x001;
* 请求的时候等待框
private WaitDialog mWaitD
* 请求队列
private RequestQueue requestQ
protected void onActivityCreate(Bundle savedInstanceState) {
setTitle(Application.getInstance().nohttpTitleList[0]);
setContentView(R.layout.activity_original);
findView(R.id.btn_start).setOnClickListener(this);
mWaitDialog = new WaitDialog(this);
requestQueue = NoHttp.newRequestQueue();
public void onClick(View v) {
Request&String& request = NoHttp.createStringRequest(url, RequestMethod.POST);
request.add("userName", "yolanda");
request.add("userPass", 1);
request.add("userAge", 1.25);
request.add("userHead", new FileBinary(new File(path)));
request.addHeader("Author", "nohttp_sample");
requestQueue.add(NOHTTP_WHAT_TEST, request, onResponseListener);
* 回调对象,接受请求结果
private OnResponseListener&String& onResponseListener = new OnResponseListener&String&() {
@SuppressWarnings("unused")
public void onSucceed(int what, Response&String& response) {
if (what == NOHTTP_WHAT_TEST) {
String result = response.get();
Headers headers = response.getHeaders();
headers.getResponseCode();
response.getNetworkMillis();
public void onStart(int what) {
mWaitDialog.show();
public void onFinish(int what) {
mWaitDialog.dismiss();
public void onFailed(int what, String url, Object tag, CharSequence error, int resCode, long ms) {
protected void onDestroy() {
super.onDestroy();
requestQueue.cancelAll();
requestQueue.stop();
如果还是有疑问的同学, 可以在下面留言, 或者加入NoHttp的交流群咨询
(NoHttp QQ交流群:, NoHttp官方 E-mail: )
NoHttp是一个专门做Android网络相关的框架.
47分钟前150阅47分钟前362阅47分钟前195阅1小时前147阅3小时前431阅3小时前479阅3小时前229阅3小时前421阅4小时前276阅5小时前409阅
CentOS专题
8884阅9941阅8657阅6622阅8779阅8424阅1643阅3806阅1454阅7303阅
5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!
按 Ctrl+D 键,
把本文加入收藏夹
热门栏目 &
热门教程 &
图书推荐 &
12345678910
12345678910
12345678910
微信扫一扫,关注动态开局声明:这是基于nohttp1.0.4-include-source.jar版本写的教程
由于nohttp功能强悍,因此需要多种权限,仅仅一个联网的权限是不够的,如果只给了Internet的权限,去请求网络将还会报错:
onFailed: com.yolanda.nohttp.error.NetworkError: The network is not available, please check the network. The requested url is: /xml/iphoneinterface.aspx?type=news&nums=20
因此建议,直接把nohttp的权限全部加入:
&uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /&
&uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&
&uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /&
&uses-permission android:name="android.permission.INTERNET" /&
&uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&
&uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /&
&uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /&
&uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /&
&uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /&
首先是初始化整个应用全局的
1 package com.qg.lizhanqi.
3 import android.app.A
5 import com.yolanda.nohttp.NoH
* Created by lizhanqi on -0028.
10 public class MyApplication extends Application {
public void onCreate() {
//对你没看错就是这么一行就这么简单,NOhttp就是这么简单
NoHttp.initialize(this);
super.onCreate();
Get请求方式
public void noHttpGetString(String url) {
//第一步:创建Nohttp请求对列(如果是本类使用的比较频繁,在onCreate的时候初始化一次就行了,这里是为了怕忘记这个步骤)
requestQueues = NoHttp.newRequestQueue();
//第二步:创建请求对象(url是请求路径)
Request&String& stringRequest = NoHttp.createStringRequest(url,RequestMethod.GET);//这里 RequestMethod.GET可以不写(删除掉即可),默认的是Get方式请求
//第三步:加入到请求对列中,requestQueues.add()分别是请求列的请求标志,请求对象,监听回调
requestQueues.add(1, stringRequest, new SimpleResponseListener&String&() {
public void onSucceed(int i, Response&String& response) {
Toast.makeText(MainActivity.this, "noHttpGetString请求成功" + response, Toast.LENGTH_SHORT).show();
public void onFailed(int i, String s, Object o, Exception e, int i1, long l) {
Toast.makeText(MainActivity.this, "noHttpGetString请求失败" + e, Toast.LENGTH_SHORT).show();
Log.e(TAG, "onFailed: " + e);
post方式请求
public void noHttpPostString(String url) {
//第一步:创建Nohttp请求对列(如果是本类使用的比较频繁,在onCreate的时候初始化一次就行了,这里是为了怕忘记这个步骤)
requestQueues = NoHttp.newRequestQueue();
//第二步:创建请求对象(url是请求路径, RequestMethod.POST是请求方式)
Request&String& stringPostRequest = NoHttp.createStringRequest(url, RequestMethod.POST);
// 添加请求参数例如"/xml/iphoneinterface.aspx?type=news&nums=20"
stringPostRequest.add("type", "news");
stringPostRequest.add("nums", "20");
//第三步:加入到请求对列中,requestQueues.add()分别是请求列的请求标志,请求对象,监听回调
requestQueues.add(2, stringPostRequest, new SimpleResponseListener&String&() {
@Override//请求成功的回调
public void onSucceed(int i, Response&String& response) {
Log.i(TAG, "onSucceed: " + response);
Toast.makeText(MainActivity.this, "noHttpPostString请求成功" + response.get(), Toast.LENGTH_LONG).show();
@Override//请求失败的回调
public void onFailed(int i, String s, Object o, Exception e, int i1, long l) {
Log.e(TAG, "onFailed: " + e);
//缓存文字的请求
public void noHttpCacheString(String url) {
//第一步:创建Nohttp请求对列(如果是本类使用的比较频繁,在onCreate的时候初始化一次就行了,这里是为了怕忘记这个步骤)
requestQueues = NoHttp.newRequestQueue();
//第二步:创建请求对象(url是请求路径, RequestMethod.POST是请求方式)
Request&String& stringPostRequest = NoHttp.createStringRequest(url);
//第三步:设置请求缓存的五种模式:
//DEFAULT是http标准协议的缓存
//stringPostRequest.setCacheMode(CacheMode.DEFAULT);
//REQUEST_NETWORK_FAILED_READ_CACHE请求失败返回上次缓存的数据(建议使用这种)
stringPostRequest.setCacheMode(CacheMode.REQUEST_NETWORK_FAILED_READ_CACHE);
//NONE_CACHE_REQUEST_NETWORK在没有缓存再去请求网络
// stringPostRequest.setCacheMode(CacheMode.NONE_CACHE_REQUEST_NETWORK);
// ONLY_READ_CACHE仅仅请求缓存,如果没有缓存就会请求失败
//stringPostRequest.setCacheMode(CacheMode.ONLY_READ_CACHE);
//ONLY_REQUEST_NETWORK仅仅请求网络不支持302重定向
// stringPostRequest.setCacheMode(CacheMode.ONLY_REQUEST_NETWORK);
// 添加请求参数例如"/xml/iphoneinterface.aspx?type=news&nums=20"
//第三步:加入到请求对列中,requestQueues.add()分别是请求列的请求标志,请求对象,监听回调
requestQueues.add(3, stringPostRequest, new SimpleResponseListener&String&() {
@Override//请求成功的回调
public void onSucceed(int i, Response&String& response) {
Log.i(TAG, "onSucceed: " + response);
Toast.makeText(MainActivity.this, "noHttpCacheString请求成功" + response.get(), Toast.LENGTH_LONG).show();
@Override//请求失败的回调
public void onFailed(int i, String s, Object o, Exception e, int i1, long l) {
Log.e(TAG, "noHttpCacheString..onFailed: " + e);
阅读(...) 评论()当前位置: >
Android NoHttp 框架作者带你看源码(一)
发布时间:
& 作者:本站编辑 &
浏览次数:
摘要: 版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 现在市场的Http框架很多,比如我们熟知的...
现在市场的Http框架很多,比如我们熟知的NoHttp、Retrofit、Volley、android-async-http等上层框架,HttpURLConnection、OkHttp、HttpClient等底层框架,今天不说孰好孰坏,今天我带大家来分析NoHttp的源码,教大家如何来看NoHttp的源码。
今天我们由浅到深,深入浅出的分析第一个模块:请求模块。
支持作者可以去Github上关注NoHttp源代码:,。
更多NoHttp相关文章请看NoHttp博客专栏:cool.net/column/details/nohttp.html。
NoHttp 源码该如何入手
想要看一个框架的源码,首先就要学会怎么用,最起码基础用法要会,也不必深入或者精通。那么我们先来看下NoHttp的异步请求和同步请求的简单用法。
切入NoHttp
作为一个优秀的网络框架,必定时提供了异步请求、同步请求两种方式给开发者的。
NoHttp的异步,我们先来看一个最简单实践:
RequestQueue queue = NoHttp.newRequestQueue();
Request&String& sReq = new StringRequest(url, POST);
queue.add(what sReq, new OnResponseListener() {
public void onStart(int what){}
public void onFinish(int what){}
public void onSucceed(int what, Response&String& response){}
public void onFailed(int what, Response&String& response){}
来做个简单的分析,首先是new了一个队列,然后创建了一个String的Request,之后把这个请求添加到队列,等待请求网络后响应,完事儿,就是这么简单。
NoHttp同步请求,再来看一个最简单实例:
Request&String& request = new StringRequest(url, GET);
Response&String& response = NoHttp.startRequestSync(request);
这个更简单了,创建了一个请求,然后调用NoHttp同步请求的方法拿到请求结果。
从哪里开始看起
看了异步请求和同步请求后我们来分析一下,应该从哪里开始看NoHttp的源码。
从上面的代码中看到,异步请求和同步请求最大的区别是:异步请求需要用队列发送,用Listener接受请求结果,而同步请求是直接请求到结果,那么最大的可能就是异步请求是建立在同步请求这个基础上的。所以我们直接看异步请求,在开始之前我已经画好了几个图。
NoHttp流程图
这个图是NoHttp异步请求时,从主线程调用网络到拿到结果的流程图,这里非常有必要对这些类做个说明。
默认实现类
RequestQueue
RequestDispatcher
轮询队列的线程
IRestParser
RestParser
解析网络结果,针对IParserRequest
IRestProtocol
RestProtocol
按照Http协议请求网络处理请求结果,针对IProtocolRequest
BasicConnection
提供基础的访问网络能力,针对IBaseRequst,更改底层为OkHttp时只需要改它
IBaseRequst
BaseRequest
提供通用的网络设置、参数设置、Cookie、重试机制,下载和请求模块通用
IProtocolRequest
ProtocolRequest
请求模块的协议,例如缓存机制
IParserRequest
ParserRequest
泛型,提供解析请求结果ByteArray为泛型
RestRequest
提供异步请求的参数记录功能,如what、Listener等
注意:其中BasicConnection是网络访问的基础类,所以它提供了请求网络、发送数据、上传文件、拿到服务器响应头、拿到服务器响应body、拿到服务器的流等基础网络功能。
NoHttp动态流程图
如果上面的图还是不够显然,我们可以结合下面的图再看一边动态流程图就更加显而易懂了:
从上面的两张图可以看到,任何一个请求都是从主线程开始发起,先把Request添加到RequestQueue(队列)中,队列此时会启动子线程,再由ReuqestDispatcher(请求分发者)把队列中请求按照一定的顺序分发给子线程去执行网络操作,ReuqestDispatcher拿到结果后,用Handler发送到主线程,这个过程就是NoHttp的整个异步请求的过程。
接着上面的分析,我们现在开始撸源码,那么先入手的入手的就是RequestQueue了。
RequestQueue
我们先来看看NoHttp怎么创建RequestQueue:
public static RequestQueue newRequestQueue() {
return newRequestQueue(DEFAULT_REQUEST_THREAD_SIZE);
public static RequestQueue newRequestQueue(int threadPoolSize) {
return newRequestQueue(DiskCacheStore.INSTANCE, threadPoolSize);
public static RequestQueue newRequestQueue(Cache&CacheEntity& cache, int threadPoolSize) {
return newRequestQueue(RestProtocol.getInstance(cache), threadPoolSize);
public static RequestQueue newRequestQueue(IRestProtocol iRestProtocol, int threadPoolSize) {
return newRequestQueue(RestParser.getInstance(iRestProtocol), threadPoolSize);
public static RequestQueue newRequestQueue(IRestParser implRestParser, int threadPoolSize) {
RequestQueue requestQueue = new RequestQueue(implRestParser, threadPoolSize);
requestQueue.start();
return requestQ
这里有5个方法可以创建ReuqestQueue,但是每个方法最终都会来到最后方法,最后一个方法需要两个参数,第一个参数是IRestParser,也就是响应解析者,第二个参数是threadPoolSize,也就是队列中启动的线程的数量,创建好ReuqestQueue后,调用start()方法启动队列,这时就可以往队列中添加请求了。
既然到这里我们就必须去看看ReuqestQueue的源码了,我已经把原文中的英文注释改为中文了,方便大家理解:
public class RequestQueue {
/** * 保存没有完成的请求,包括正在执行的请求。 */
private final BlockingQueue&Request&?&& mUnFinishQ
/** * 保存没有执行的请求,不包括正在执行的请求。 */
private final BlockingQueue&Request&?&& mRequestQ
/** * Http 请求结果解析器。 */
private final IRestParser mImplRestP
/** * 线程池。 */
private RequestDispatcher[] mD
public RequestQueue(IRestParser implRestParser, int threadPoolSize) {
mImplRestParser = implRestP
mDispatchers = new RequestDispatcher[threadPoolSize];
/** * 启动线程池,轮询请求队列。 */
public void start() {
for (int i = 0; i & mDispatchers. i++) {
RequestDispatcher networkDispatcher = new RequestDispatcher(..., mImplRestParser);
mDispatchers[i] = networkD
networkDispatcher.start();
/** * 1. 添加一个请求到队列,如果队列中请求数没有满,则会立即执行,否则等待前面的请求执行完成后再执行。 * 2. 在真正添加到队列前检查当前要添加的请求是否在队列中,如果重复添加则无任何操作。 */
public &T& void add(int what, Request&T& request, OnResponseListener&T& responseListener) {
/** * 没有开始执行的请求数量。 */
public int unStartSize() {}
/** * 没有完成的请求数量,包括正在执行的请求。 */
public int unFinishSize() {}
/** * 停止队列,使三个线程停止,不进行轮询队列。 */
public void stop() {}
/** * 根绝sign取消所有用sign打标的请求。 */
public void cancelBySign(Object sign) {}
/** * 取消队列中所有请求。 */
public void cancelAll() {}
结合上文所说的,这里贴出了所有方法和最重要的实现。在构造方法中,创建了一个threadPoolSize大小的RequestDispatcher数组,调用start()的时候为数组的每一个index赋值一个真正的RequestDispatcher线程,并启动这个线程去轮询Queue,同时在创建RequestDispatcher的时候把我们创建队列的时候的IRestParser穿进去了,说明真正的调用网络还是在RequestDispatcher这个子线程中,具体怎么调用并处理接着看下文。关于队列和线程的知识点这里不讲太多,只讲NoHttp在这里的设计,关于更多多线程、队列和任务优先级顺序的知识,请看。
RequestDispatcher
我们上面说到RequestDispatcher是一个线程,而且它在轮询队列里面的请求,根绝开始的流程图它也负责发送请求结果到主线程,所以它应该NoHttp异步请求中最重要的类之一了,我们不能放过它:
public class RequestDispatcher extends Thread {
private boolean mQuit = false;
public void stop() {
mQuit = true;
public void run() {
while (!mQuit) {
final Request&?&
request = mRequestQueue.take();
} catch (InterruptedException e) {
if (request.isCanceled()) {
final int what = request.what();
final OnResponseListener&?& responseListener = request.responseListener();
request.start();
final ThreadPoster startThread = new ThreadPoster(what, responseListener);
startThread.onStart();
PosterHandler.getInstance().post(startThread);
Response&?& response = mIRestParser.parserRequest(request);
mUnFinishQueue.remove(request);
final ThreadPoster finishThread = new ThreadPoster(what, responseListener);
finishThread.onFinished();
PosterHandler.getInstance().post(finishThread);
request.finish();
if (request.isCanceled())
Logger.d(request.url() + " finish, but it's canceled.");
final ThreadPoster responseThread = new ThreadPoster(what, responseListener);
responseThread.onResponse(response);
PosterHandler.getInstance().post(responseThread);
private class ThreadPoster implements Runnable {
public static final int COMMAND_START = 0;
public static final int COMMAND_RESPONSE = 1;
public static final int COMMAND_FINISH = 2;
private final int
private final OnResponseListener responseL
private int
public ThreadPoster(int what, OnResponseListener&?& responseListener) {
this.what =
this.responseListener = responseL
public void onStart() {
this.command = COMMAND_START;
public void onResponse(Response response) {
this.command = COMMAND_RESPONSE;
this.response =
public void onFinished() {
this.command = COMMAND_FINISH;
public void run() {
if (responseListener != null) {
if (command == COMMAND_START)
responseListener.onStart(what);
else if (command == COMMAND_FINISH)
responseListener.onFinish(what);
else if (command == COMMAND_RESPONSE) {
if (response.isSucceed()) {
responseListener.onSucceed(what, response);
responseListener.onFailed(what, response);
如果你认真看了我的注释结合我的解释也许就会明白很多了。
RequestDispatcher在线程没有被标志停止的情况下会一直循环调用Queue.take()轮询队列中的请求,如果线程中没有请求,由于Queue.take()的特性,这个子线程会处于阻塞状态,当然这不会使APP卡顿,因为它在子线程。当它每拿到一个Request先会判断请求是否被取消,如果是取消了的则去轮询下一个请求,如果没有取消会利用Handler发送一个Runnable回调Listener.onStart()方法通知主线程请求开始了,接着去执行Request,其中最重要的一句就是调用IRestParse的地方,这里正好印证了我们最开始讲的,在子线程中利用IRestParse去发送请求并解析结果成泛型:
Response&?& response = mIRestParser.parserRequest(request);
执行完请求后再次利用Handler发送一个Runnable回调Listener.onFinish()方法通知主线程网络请求执行完了:
final ThreadPoster finishThread = new ThreadPoster(what, responseListener);
finishThread.onFinished();
PosterHandler.getInstance().post(finishThread);
request.finish();
if (request.isCanceled())
Logger.d(request.url() + " finish, but it's canceled.");
final ThreadPoster responseThread = new ThreadPoster(what, responseListener);
responseThread.onResponse(response);
PosterHandler.getInstance().post(responseThread);
可以看到如果回调了onStart()则一定会回调onFinish(),所以我们在OnResponseListener的onStart和onFinish非常适合做一个Dilaog的显示和关闭。
因为请求网络可能耗时比较长或者网络不好超时等因素,用户可能会取消这个请求,所以我们看到在回调了onFinish()后在发送结果到主线程前NoHttp又做了一个请求是否被取消的判断,综上所述我们得出一系列结论:
我们可以在onStart()时显示了一个Dialog,那么我们可以在onFinish()关闭Dialog。
如果请求开始之前就取消了,那这个请求不会被执行。
如果请求已经开始了,但是被中途取消,onFinish()还是会被回调,所以在这里关闭Dialog是非常合适的;同时请求若是被中途取消,那么也一定不会回调onSucceed()和onFailed()了,这里就涉及到取消请求了,用户退出当前页面会不会发生内存泄漏的问题,答案自然是不会。
IRestParser和它的实现类RestParser
看完了RequestQueue和RequestDispatcher后发现,里面除了和主线程的交互外,就是和网络的交互和结果如果解析了。
由上可以看到在创建队列、启动子线程到真正的执行请求,最终都需要响应解析者IRestParser,我们来看下它的源代码:
public interface IRestParser {
/** * 请求网络并且解析结果。 */
&T& Response&T& parserRequest(IParserRequest&T& request);
根据源码和流程图的结构来看,它负责针对IRestRequest解析出数据并返回Response,数据肯定是来自网络,因此它也怎么从网络拿到数据并解析成我们想要的泛型结果就是重点了。但它只是一个接口,想知道它是如何实现的,就得看NoHttp为它提供的默认实现类怎么请求网络并返回数据了。
我们选中IRestParser,键盘上按下Ctrl + T(也许你的快捷键跟我不一样)就看到了接口的实现类,同时NoHttp为它提供的默认实现在创建队列的时候可以看到RestProtocol
public static RequestQueue newRequestQueue(IRestProtocol iRestProtocol, int threadPoolSize) {
return newRequestQueue(RestParser.getInstance(iRestProtocol), threadPoolSize);
我们可以看到源码是用RestParser.getInstance(iRestProtocol)单例模式从RestParser获取IRestParser的实例,因此下面接着就要撸RestParser的源码了:
public class RestParser implements IRestParser {
private static RestParser _INSTANCE;
private final IRestProtocol mIRestP
public static IRestParser getInstance(IRestProtocol implRestConnection) {
synchronized (RestParser.class) {
if (_INSTANCE == null)
_INSTANCE = new RestParser(implRestConnection);
return _INSTANCE;
private RestParser(IRestProtocol iRestProtocol) {
this.mIRestProtocol = iRestP
public &T& Response&T& parserRequest(IParserRequest&T& request) {
long startTime = SystemClock.elapsedRealtime();
ProtocolResult httpResponse = mIRestProtocol.requestNetwork(request);
boolean isFromCache = httpResponse.isFromCache();
Headers responseHeaders = httpResponse.responseHeaders();
Exception exception = httpResponse.exception();
T result = null;
byte[] responseBody = httpResponse.responseBody();
if (exception == null) {
result = request.parseResponse(responseHeaders, responseBody);
} catch (Throwable e) {
exception = new ParseError("Parse data error: " + e.getMessage());
return new RestResponse&T&(request, isFromCache, responseHeaders,
result, SystemClock.elapsedRealtime() - startTime, exception);
这里的单例和构造方法不多说,如果这都看不懂的话你可能不太适合做编程,我们接着分析parserRequest()方法。
parserRequest()中是真正的请求网络,这里可以理解为同步请求的开始,所以看到这里不是有了灵感,NoHttp的同步请求一并看了,这也是NoHttp设计上的优点,同步请求更多的内容看本文最后。继续说,parserRequest()开始时记录了请求开始时间,然后立刻调用网络协议处理器IRestProtocol请求网络:
ProtocolResult httpResponse = mIRestProtocol.requestNetwork(request);
完成网络协议请求后拿到ByteArray后调用IParserRequest.parseResponse()解析泛型结果,所以具体解析成什么结果是由IParserRequest决定的(题外话:因此我们在自定义请求时,继承RestRequest需要重写parseResponse解析结果),解析完ByteArray成泛型的结果后把异常、是否来自缓存和结果封装成RestResponse返回,剩下的事情就是上文中分析过的RequestDispatcher处理了,如果你忘记了RequestDispatcher的逻辑,可以回头去看看。
其实到这里这个过程就完了,但是大家肯定要吐槽我了:你特喵的扯什么淡呢,连一点点和http相关的都没看到。嗯这就对了,我们上面看到和Http相关的的网络请求是通过IRestProtoco这个接口发出的,so,接下来该撸IRestProtocol这个接口了。
IRestProtocol和它的实现类RestProtocol
IRestProtocol文章开头就说道了,它是一个接口,没啥好分析的,直接打开看源码:
public interface IRestProtocol {
/** * 解析Http协议相关参数,完成网络请求。 */
ProtocolResult requestNetwork(IProtocolRequest request);
根据源码和流程图的结构来看,它负责针对IProtocolRequest解析Http协议参数,并发起网络请求返回请求的结果。因此我们需要关心的地方是它如何处理Http协议的参数,so我们接着看NoHttp为它提供的默认实现类怎么请求网络并返回数据了。
引入IRestProtocol:
选中IRestProtocol,键盘上按下Ctrl + T(也许你的快捷键跟我不一样)就看到了接口的实现类,或者回去看创建RequestQueue时,获取IRestParser的单例时:
public static RequestQueue newRequestQueue(Cache&CacheEntity& cache, int threadPoolSize) {
return newRequestQueue(RestProtocol.getInstance(cache), threadPoolSize);
public static RequestQueue newRequestQueue(IRestProtocol iRestProtocol, int threadPoolSize) {
return newRequestQueue(RestParser.getInstance(iRestProtocol), threadPoolSize);
public static RequestQueue newRequestQueue(IRestParser implRestParser, int threadPoolSize) {
RequestQueue requestQueue = new RequestQueue(implRestParser, threadPoolSize);
requestQueue.start();
return requestQ
这里可以看到最终创建队列时需要一个IRestParser,而在上一个方法获取IRestParser时需要一个IRestProtocol接口作为参数,在最上面的方法中看到IRestProtocol的是由RestProtocol.getInstance(cache)生成的,所以NoHttp为IRestProtocol提供的默认实现类是RestProtocol。
ProtocolResult requestNetwork(IProtocolRequest request);
由于这个类代码有点多,我们一点点的来分析,首先就是IRestProtocol必须要实现的方法requestNetwork():
public class RestProtocol extends BasicConnection implements IRestProtocol {
public ProtocolResult requestNetwork(IProtocolRequest request) {
CacheMode cacheMode = request.getCacheMode();
String cacheKey = request.getCacheKey();
CacheEntity cEntity = mCache.get(cacheKey);
switch (cacheMode) {
case ONLY_READ_CACHE:
if (cEntity == null) {
return new ProtocolResult(null, null, true, new NotFoundCacheError("没找到缓存"));
return new ProtocolResult(cEntity.getResponseHeaders(), cEntity.getData(), true, null);
case ONLY_REQUEST_NETWORK:
result = getHttpResponse(request);
case NONE_CACHE_REQUEST_NETWORK:
if (cEntity == null) {
result = getHttpResponse(request);
return new ProtocolResult(cEntity.getResponseHeaders(), cEntity.getData(), true, null);
case REQUEST_NETWORK_FAILED_READ_CACHE:
if (cEntity != null)
setRequestCacheHeader(request, cEntity);
result = getHttpResponse(request);
if (cEntity != null) {
if (cEntity.getLocalExpire() & System.currentTimeMillis()) {
return new ProtocolResult(cEntity.getResponseHeaders(), cEntity.getData(), true, null);
setRequestCacheHeader(request, cEntity);
result = getHttpResponse(request);
return handleResponseCache(request, cEntity, result);
大家千万不要忘记了看类的继承关系,RestProtocol实现了IRestProtocol接口,并且继承BasicConnection这个基类。
要注意的两点:
第一:NoHttp的几种缓存模式:
只请求缓存
先读缓存,没有缓存再请求网络
先请求网络,请求网络失败再读取缓存
按照Http标准协议,重定向缓存机制
第二:此方法中出现的几个未知的方法:
setRequestCacheHeader(request, cacheEntity); // 为请求设置缓存头。
getHttpResponse(request); // 真正的请求网络。
handleResponseCache(request, cEntity, result); // 处理响应结果、缓存等。
这个方法是在请求之前为Request添加和缓存协议有关的请求头,这是Http标准协议的内容,更多的协议讲解请看这篇博客:cool.net/yanzhenjie1003/article/details/
private void setRequestCacheHeader(IProtocolRequest request, CacheEntity cacheEntity) {
if (cacheEntity == null) {
request.headers().remove("If-None-Match");
request.headers().remove("If-Modified-Since");
Headers headers = cacheEntity.getResponseHeaders();
String eTag = headers.getETag();
if (eTag != null) {
request.headers().set("If-None-Match", eTag);
long lastModified = headers.getLastModified();
if (lastModified & 0) {
request.headers().set("If-Modified-Since", HeaderUtil.formatMillisToGMT(lastModified));
这里需要解释一下Http的缓存协议了。如果服务器支持http标准的缓存,当我们第一次请求服务器的时候,服务器会在响应头中添加Last-Modified头,这个头的含义是服务器最后一次修改响应body的时间,如果服务器支持设置缓存有效期,还会添加一个E-Tag的头,这个头是可以理解为响应body的一个tag。客户端接受到响应头到,会把这两个相应头保存起来,在第二次请求的时候会首先检查响应body是否过期,如果没有过期则直接使用上次的响应body,也就是我们在requestNetwork()方法中看到的:
if (cEntity != null) {
if (cEntity.getLocalExpire() & System.currentTimeMillis()) {
return new ProtocolResult(cEntity.getResponseHeaders(), cEntity.getData(), true, null);
setRequestCacheHeader(request, cEntity);
result = getHttpResponse(request);
如果响应body过期,那么客户端应该重新请求服务器,并且在请求头中添加两个请求头,第一个是If-None-Match头,这个头的值应该是上次请求服务器时,服务器返回的E-Tag,第二个要添加的请求头是If-Modified-Since,这个头的值应该是上次服务器返回的Last-Modified的值。
服务器接受到请求后会用If-None-Match和If-Modified-Since和服务器现在E-Tag和Last-Modified做对比,判断客户端上次的缓存是否过期。如果没有过期则返回304响应码,并且不会向响应body中写入内容,客户端接受到这个响应后,判断响应码是304时应该从客户端拿上次的缓存数据;如果过期则返回200段的响应码,并且会向响应body中写入新的内容,客户端接受到这个响应后,判断响应码是200段,应该重新从响应body中读取内容。
这就是Http标准协议中的缓存协议内容,NoHttp做到了完美的支持。
getHttpResponse(request);
/** * 真正的请求网络。 */
private ProtocolResult getHttpResponse(IProtocolRequest request) {
byte[] responseBody = null;
Connection connection = getConnection(request);
Headers responseHeaders = connection.responseHeaders();
Exception exception = connection.exception();
if (exception == null) {
if (hasResponseBody(request.getRequestMethod(), responseHeaders.getResponseCode()))
responseBody = IOUtils.toByteArray(connection.serverStream());
} catch (IOException e) {
exception =
IOUtils.closeQuietly(connection);
return new ProtocolResult(responseHeaders, responseBody, exception != null, exception);
其中Connection connection = getConnection(request); 。里面才是真正的建立网络请求,发送数据、上传文件等操作,我将会新开一篇博客专门来讲BasicConnection类。
handleResponseCache(request, cEntity, result);
private ProtocolResult handleResponseCache(IProtocolRequest request, CacheEntity localCacheEntity, ProtocolResult httpResponse) {
boolean isFromCache = false;
Headers responseHeaders = httpResponse.responseHeaders();
byte[] responseBody = httpResponse.responseBody();
Exception exception = httpResponse.exception();
CacheMode cacheMode = request.getCacheMode();
int responseCode = responseHeaders.getResponseCode();
if (exception == null) {
if (responseCode == 304) {
isFromCache = true;
if (localCacheEntity == null) {
responseBody = new byte[0];
localCacheEntity.getResponseHeaders().setAll(responseHeaders);
responseHeaders = localCacheEntity.getResponseHeaders();
localCacheEntity.setLocalExpire(HeaderUtil.getLocalExpires(responseHeaders));
responseBody = localCacheEntity.getData();
} else if (responseBody != null) {
if (localCacheEntity == null) {
localCacheEntity = HeaderUtil.parseCacheHeaders(...);
localCacheEntity.getResponseHeaders().setAll(responseHeaders);
localCacheEntity.setLocalExpire(HeaderUtil.getLocalExpires(responseHeaders));
localCacheEntity.setData(responseBody);
if (localCacheEntity != null) {
mCache.replace(request.getCacheKey(), localCacheEntity);
} else if (cacheMode == CacheMode.REQUEST_NETWORK_FAILED_READ_CACHE
&& localCacheEntity != null) {
exception = null;
isFromCache = true;
responseHeaders = localCacheEntity.getResponseHeaders();
responseBody = localCacheEntity.getData();
return new ProtocolResult(responseHeaders, responseBody, isFromCache, exception);
这个类的作用是根据服务器响应码、服务器响应头、本地数据等处理和缓存相关的逻辑,大家可以认真看下源码和逻辑。主要做的事情是,解析服务器响应码、响应内容,根据标准的http协议来决定是否缓存数据,或者更新上次的缓存数据。
今天我们的请求模块到这里就解析完了,看完文章的同学也许还会有不明白的地方,欢迎大家在博客下方留言。
还剩下BasicConnection,因为它的能力请求网络、发送数据、上传文件、拿到服务器响应头、拿到服务器响应body、拿到服务器的流等内容较多,我会专门开一篇新的博客专门讲这个类。
RequestQueue是请求队列,在主线程执行,主线程可以添加Request到请求队列中,等待子线程轮询读取Request去执行。
RequestDispatcher是请求分发者,它是一个子线程,作用是轮询请求队列,拿到请求后调用IRestParser执行请求结果,负责发送开始请求、结束请求、把结果发送到主线程等重要任务。 2.1 RequestQueue、RequestDispatcher可以接受的请求类是Request接口,Request接口继承自IParserRequest接口,Request接口负责记录响应监听器Listener和监听器的what对象。
IRestParser是请求结果解析者,它在子线程中运行,负责把从网络请求回来的ByteArray解析成开发者想要的泛型对象。 3.1 IRestParser接口带有泛型,可以接受到的请求类是IParserRequest接口,IParserRequest接口继承自IRestPtotocol接口,IParserRequest接口负责具体实现解析成开发者想要的泛型对象,由IRestParser具体调用。
IRestProtocol是协议处理器,它在子线程中运行,负责从网络请求结果,包括Header、Body(ByteArray),并且在请求到结果前后处理缓存协议(其他协议待加)等。 4.1 IRestProtocol接口可以接受的请求类是IProtocolRequest接口,IProtocolRequest接口继承自IBasicRequest接口,IProtocolRequest接口负责记录客户端自定义Http协议等,例如缓存模式,缓存Key等。
BasicConnection是基础的网络访问类,它的能力:能力请求网络、发送数据、上传文件、拿到服务器响应头、拿到服务器响应body、拿到服务器的流等,是下载模块和请求模块的通用网络请求模块。 5.1 BasicConnection可以接受的请求类是IBasicRequest接口,IBasicRequest接口记录了基础的请求属性、通用的网络设置、参数设置、Cookie、重试机制,下载和请求模块通用。
转载请注明本文出处:
Android编程
Android布局优化
Android的MVC
最好的Android应用
Android Drawable之GradientDrawable
我来说两句
友情链接:}

我要回帖

更多关于 http user agent的值 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信