1.网络基本知识
1.1 网络分层
1.1.1物理层负责比特流在节点之间的传输
1.1.2 数据链路层 吧不可靠的物理线路上进行数据的可靠传递
1.1.3 网络层决定如何将数据从发送方到接收方
1.1.4 传输层进行端到端的通信 这上面有Tcp和Udp协议
1.1.5应用层 主要协议是HTTP 和FTP 等协议
1.2 三次握手与四次挥手
1.2.1 三次握手
第一次握手:建立连接 客户发送请求报文字段将SYN设置为1,seq设置为x 接下来客户端进入SYN_SENT状态,等待服务器
第二次握手:服务器收到客户端的SYN报文对SYN报文进行确认,设置ACK为x+1同时发送SYN设置为1 seq为y 将上述信息放到SYN+ACK中发给客户端此时进入SYN_RCVD状态
第三次握手客户端收到服务器端SYN+ACK 将ACK设置为y+1向服务端发送ACK报文
1.3.1 四次挥手
第一次挥手 客户端设置seq为ACK 向服务端发送一个FIN报文,
第二次挥手服务端接收到FIN字段 向客户端回了一个ACK报文
第三次服务端向客户发FIN报文请求关闭连接
第四次 客户端接受到服务端发送的FIN报文段,向服务端发送ACK报文然后进入等待状态 等待久了就关闭自己了
2.Volley解析
Volley是一个google官方的网络通信框架,设计是适合数据量不大,但是通信频繁的网络操作,对于下载文件等 表现会比较差
2.1 Volley使用方法
(1)下载Volley jar包 放到AndroidStudio工程下面 导入jar包
(2)开始使用
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
StringRequest stringRequest = new StringRequest(Request.Method.GET, "www.baidu.com", new Response.Listener<String>() {
@Override
public void onResponse(String s) {
//成功会掉
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
requestQueue.add(stringRequest);
private void loadJson() {
RequestQueue requestQueue = Volley.newRequestQueue(getApplicationContext());
JSONObject paramJsonObject = new JSONObject();//传参数
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest("www.baidu.com", paramJsonObject, new Response.Listener<JSONObject>() {
@Override
public void onResponse(JSONObject jsonObject) {
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
}
});
requestQueue.add(jsonObjectRequest);
}
2.2Volley框架源码解析
我们从new RequestQueue入手
public class Volley {
private static final String DEFAULT_CACHE_DIR = "volley";
public Volley() {
}
public static RequestQueue newRequestQueue(Context context, BaseHttpStack stack) {
BasicNetwork network;
if (stack == null) {
if (VERSION.SDK_INT >= 9) {
network = new BasicNetwork(new HurlStack());
} else {
String userAgent = "volley/0";
try {
String packageName = context.getPackageName();
PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
userAgent = packageName + "/" + info.versionCode;
} catch (NameNotFoundException var6) {
;
}
network = new BasicNetwork(new HttpClientStack(AndroidHttpClient.newInstance(userAgent)));
}
} else {
network = new BasicNetwork(stack);
}
return newRequestQueue(context, (Network)network);
}
/** @deprecated */
@Deprecated
public static RequestQueue newRequestQueue(Context context, HttpStack stack) {
return stack == null ? newRequestQueue(context, (BaseHttpStack)null) : newRequestQueue(context, (Network)(new BasicNetwork(stack)));
}
private static RequestQueue newRequestQueue(Context context, Network network) {
File cacheDir = new File(context.getCacheDir(), "volley");
RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
queue.start();
return queue;
}
public static RequestQueue newRequestQueue(Context context) {
return newRequestQueue(context, (BaseHttpStack)null);
}
}
其实就判断当前版本大于9还是小于9小于就创建HttpClient大于就创建HttpURLConnection并调用start方法 我们来看start方法
public void start() {
this.stop();
this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery);
this.mCacheDispatcher.start();
for(int i = 0; i < this.mDispatchers.length; ++i) {
NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
this.mDispatchers[i] = networkDispatcher;
networkDispatcher.start();
}
}
其实就是开启 几个线程 一个是缓存调度线程 四个网络请求线程 一共五个线程在后台运行 按照Volley的使用流程 后面就是讲request加入到队列中去我们看 add方法
public <T> Request<T> add(Request<T> request) {
request.setRequestQueue(this);
Set var2 = this.mCurrentRequests;
synchronized(this.mCurrentRequests) {
this.mCurrentRequests.add(request);
}
request.setSequence(this.getSequenceNumber());
request.addMarker("add-to-queue");
if (!request.shouldCache()) {
this.mNetworkQueue.add(request);
return request;
} else {
this.mCacheQueue.add(request);
return request;
}
}
判断是否需要缓存 如果不需要缓存 直接走mCacheQueue线程,如果需要缓存走mNetworkQueue 线程
mCacheQueue 线程其实就是一个线程维护缓存管理的,代码如下,其实主要就是判断有没有缓存 如果有缓存 取缓存的数据,如果有缓存但是过期了 那么就去请求,没有过期就响应
private void processRequest() throws InterruptedException {
final Request<?> request = (Request)this.mCacheQueue.take();
request.addMarker("cache-queue-take");
if (request.isCanceled()) {
request.finish("cache-discard-canceled");
} else {
Entry entry = this.mCache.get(request.getCacheKey());
if (entry == null) {
request.addMarker("cache-miss");
if (!this.mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
this.mNetworkQueue.put(request);
}
} else if (entry.isExpired()) {
request.addMarker("cache-hit-expired");
request.setCacheEntry(entry);
if (!this.mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
this.mNetworkQueue.put(request);
}
} else {
request.addMarker("cache-hit");
Response<?> response = request.parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
request.addMarker("cache-hit-parsed");
if (!entry.refreshNeeded()) {
this.mDelivery.postResponse(request, response);
} else {
request.addMarker("cache-hit-refresh-needed");
request.setCacheEntry(entry);
response.intermediate = true;
if (!this.mWaitingRequestManager.maybeAddToWaitingRequests(request)) {
this.mDelivery.postResponse(request, response, new Runnable() {
public void run() {
try {
CacheDispatcher.this.mNetworkQueue.put(request);
} catch (InterruptedException var2) {
Thread.currentThread().interrupt();
}
}
});
} else {
this.mDelivery.postResponse(request, response);
}
}
}
}
}
mNetworkQueue这个线程就是网络请求线程 主要是调用网络请求方法,将返回的数据刷新到缓存之中,
private void processRequest() throws InterruptedException {
Request<?> request = (Request)this.mQueue.take();
long startTimeMs = SystemClock.elapsedRealtime();
try {
request.addMarker("network-queue-take");
if (request.isCanceled()) {
request.finish("network-discard-cancelled");
request.notifyListenerResponseNotUsable();
return;
}
this.addTrafficStatsTag(request);
NetworkResponse networkResponse = this.mNetwork.performRequest(request);
request.addMarker("network-http-complete");
if (networkResponse.notModified && request.hasHadResponseDelivered()) {
request.finish("not-modified");
request.notifyListenerResponseNotUsable();
return;
}
Response<?> response = request.parseNetworkResponse(networkResponse);
request.addMarker("network-parse-complete");
if (request.shouldCache() && response.cacheEntry != null) {
this.mCache.put(request.getCacheKey(), response.cacheEntry);
request.addMarker("network-cache-written");
}
request.markDelivered();
this.mDelivery.postResponse(request, response);
request.notifyListenerResponseReceived(response);
} catch (VolleyError var6) {
var6.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.parseAndDeliverNetworkError(request, var6);
request.notifyListenerResponseNotUsable();
} catch (Exception var7) {
VolleyLog.e(var7, "Unhandled exception %s", new Object[]{var7.toString()});
VolleyError volleyError = new VolleyError(var7);
volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
this.mDelivery.postError(request, volleyError);
request.notifyListenerResponseNotUsable();
}
}
最后执行了ResponseDeliveryRunnable这个线程 这个线程就是将结果返回回去 我们直接看正确的结果返回
private static class ResponseDeliveryRunnable implements Runnable {
private final Request mRequest;
private final Response mResponse;
private final Runnable mRunnable;
public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {
this.mRequest = request;
this.mResponse = response;
this.mRunnable = runnable;
}
public void run() {
if (this.mRequest.isCanceled()) {
this.mRequest.finish("canceled-at-delivery");
} else {
if (this.mResponse.isSuccess()) {
this.mRequest.deliverResponse(this.mResponse.result);
} else {
this.mRequest.deliverError(this.mResponse.error);
}
if (this.mResponse.intermediate) {
this.mRequest.addMarker("intermediate-response");
} else {
this.mRequest.finish("done");
}
if (this.mRunnable != null) {
this.mRunnable.run();
}
}
}
}
最终点进去后会发现调用了request子类的监听器回调到给了子线程
protected void deliverResponse(String response) {
Object var3 = this.mLock;
Listener listener;
synchronized(this.mLock) {
listener = this.mListener;
}
if (listener != null) {
listener.onResponse(response);
}
}
3.okHttp解析
3.1okHttp基础使用
简单来说就是 用建造模式创建一个request 然后用httpClient创造一个call出来 然后执行call的两个接口回调
Request.Builder requestBuilder = new Request.Builder().url("www.baidu.com");
requestBuilder.method("GET",null);
Request request = requestBuilder.build();
OkHttpClient okHttpClient = new OkHttpClient();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
}
});
3.2 封装OkHttp
(1)写一个请求回调,用单例模式创建一个 然后传入地址 创建一个request生成一个call 调用call 回调响应的数据
public class OkHttpEngine {
private static volatile OkHttpEngine mInstance;
private OkHttpClient mOkHttpClient;
private Handler mHandler;
public static OkHttpEngine getInstance(Context context) {
if (mInstance == null) {
synchronized (OkHttpEngine.class) {
if (mInstance == null) {
mInstance = new OkHttpEngine(context);
}
}
}
return mInstance;
}
private OkHttpEngine(Context context) {
File externalCacheDir = context.getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
OkHttpClient.Builder builder = new OkHttpClient.Builder().connectTimeout(15, TimeUnit.SECONDS).writeTimeout(20, TimeUnit.SECONDS).readTimeout(10, TimeUnit.SECONDS).cache(new Cache(externalCacheDir.getAbsoluteFile(), cacheSize));
mOkHttpClient = builder.build();
mHandler = new Handler();
}
public void getAsynHttp(String url, ResultCallBack callBack) {
Request request = new Request.Builder().url(url).build();
Call call = mOkHttpClient.newCall(request);
dealResult(call, callBack);
}
public void dealResult(Call call, final ResultCallBack callBack) {
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
//失败的
} @Override
public void onResponse(Call call, Response response) throws IOException {
sendSuccessCallback(response.body().toString(), callBack);
}
});
}
public void sendSuccessCallback(final String str, final ResultCallBack callBack) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (callBack != null) {
try {
callBack.onResponse(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
}
3.3 okHttp源码解析
请参考更加详细的文章地址https://blog.csdn.net/a820703048/article/details/86829476
4Retrofit
Retrofit 底层是基于OkHttp它更多的是运用运行时注解的方式提供功能
4.1Retrofit 的基本使用
4.1.1 注解
注解分为三大类分别是Http请求方法注解、标记类注解、参数类注解。其中Http类注解有POST GET DELETE HEAD PATCH OPTIONS HTTP 标记类注解有比如FromUrlEncoded Multipart Streaming
4.1.2基础使用教程
Retrofit build = new Retrofit.Builder().baseUrl("wwww.huya.com").build();
IpService ipService = build.create(IpService.class);
Call<IpData> call = ipService.getIpData();
call.enqueue(new Callback<IpData>() {
@Override
public void onResponse(Call<IpData> call, Response<IpData> response) {
}
@Override
public void onFailure(Call<IpData> call, Throwable t) {
}
});
public interface IpService {
@GET("www.baidu.com")
Call<IpData> getIpData();
}
4.1.3注解分解
HTTP前面几个比较容易懂的就不解释了
(1)动态配置@Path 就是将字符串拼接起来
@GET("{path}/getinfo")
Call<IpData> getIpMsg(@Path("path") String path);
(2)动态查询条件@Query
@GET("getInfo")
Call<IpData> getData(@Query("ip") String ip);
(3) 动态查询QueryMap
@GET("getInfo")
Call<IpData> getIPMsg(@QueryMap Map<String,String> options);
(4)传输类型为键值对 @Field @FormUrlEncoded是表明这个是一个表单请求
@FormUrlEncoded
@POST
Call<IpData> postMsg(@Field("ip")String ip);
(5)用Post方式将JSON字符串作为请求体送到服务器@body
@POST("getinfo")
Call<IpData> postmsg(@Body IpData data);
(6) 单个文件上传 @Part
@Multipart
@POST("user/photo")
Call<IpData> update(@Part MultipartBody.Part photo);
(7) 消息头Header为 给请求加入请求头 如果想要加入多个就用{}把它们包裹起来
@GET("some/end")
@Headers("Accept-Encoding:application/json")
Call<IpData> getCarType();
(8)Header用动态的形式加入进去
@GET("some")
Call<IpData> gethost(@Header("Location") String location);
4.2 源码解析Retrofit
Retrofit build = new Retrofit.Builder()
Retrofit 我们通过Builder来创建Retrofit线程池然后我们查看build方法
static class Android extends Platform {
@Override public Executor defaultCallbackExecutor() {
return new MainThreadExecutor();
}
@Override CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
if (callbackExecutor == null) throw new AssertionError();
return new ExecutorCallAdapterFactory(callbackExecutor);
}
static class MainThreadExecutor implements Executor {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override public void execute(Runnable r) {
handler.post(r);
}
}
}
我们看build的源代码
public Retrofit build() {
if (baseUrl == null) {//地址不能为空
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory; //转换工厂
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;//用来将回调传递到ui线程
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
//用于存储对call转化对象
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.//用于存储转发数据对象
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
我们来看create方法的创建过程
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
其实是使用了代理对象 第一个参数是代理对象 第二个是调用的方法 第三个是方法参数 我们看一下 loadSerivceMethod方法做了什么
ServiceMethod<?, ?> loadServiceMethod(Method method) {
ServiceMethod<?, ?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder<>(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
判断serviceMethodCache查询传入方法是否有缓存 如果有就用缓存的serviceMethod如果没有就创建一个加入serviceMethodCache缓存起来
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError("'"
+ Utils.getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
if (httpMethod == null) {
throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
}
if (!hasBody) {
if (isMultipart) {
throw methodError(
"Multipart can only be specified on HTTP methods with request body (e.g., @POST).");
}
if (isFormEncoded) {
throw methodError("FormUrlEncoded can only be specified on HTTP methods with "
+ "request body (e.g., @POST).");
}
}
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, "Parameter type must not include a type variable or wildcard: %s",
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, "No Retrofit annotation found.");
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
return new ServiceMethod<>(this);
}
Retrofit 的build代码如下
public Retrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
Executor callbackExecutor = this.callbackExecutor;
if (callbackExecutor == null) {
callbackExecutor = platform.defaultCallbackExecutor();
}
// Make a defensive copy of the adapters and add the default Call adapter.
List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));
// Make a defensive copy of the converters.
List<Converter.Factory> converterFactories = new ArrayList<>(this.converterFactories);
return new Retrofit(callFactory, baseUrl, converterFactories, adapterFactories,
callbackExecutor, validateEagerly);
}
adapterFactories列表默认会添加defaultCallAdapterFactory这个是ExecutorCallAdapterFactory 看它的get方法
@Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
final Type responseType = Utils.getCallResponseType(returnType);
return new CallAdapter<Object, Call<?>>() {
@Override public Type responseType() {
return responseType;
}
@Override public Call<Object> adapt(Call<Object> call) {
return new ExecutorCallbackCall<>(callbackExecutor, call);
}
};
}
###最终调用了enqueue 方法解析响应
call.enqueue(new okhttp3.Callback() {
@Override public void onResponse(okhttp3.Call call, okhttp3.Response rawResponse)
throws IOException {
Response<T> response;
try {
response = parseResponse(rawResponse);
} catch (Throwable e) {
callFailure(e);
return;
}
callSuccess(response);
}
toResponse 方法如下 responseConverter就是此前降到的createResponseConverter返回的Converter ,GsonConverterFactory中有一个方法叫responseBodyConverter,它最终创建GsonResponseBodyConverter,这其中convert方法会将回调的数据转为JSON格式,我们也知道此前调用的responseConverter.convert是为了转为特定的数据格式,call的enqueque方法主要是做okHttp的网络请求返回的Response进行数据转换并回调给UI线程
R toResponse(ResponseBody body) throws IOException {
return responseConverter.convert(body);
}